AVL添加
题目链接
平衡二叉树,是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。它是一种高度平衡的二叉排序树。现二叉平衡树结点定义如下:
1 2 3 4 5 6 7 8
| typedef struct node { int val; struct node *left; struct node *right; struct node *parent; int height; } node_t;
|
请实现平衡二叉树的插入算法:
1 2
| node_t *avl_insert(node_t *root, int val);
|
前置知识
AVL定义
平衡二叉搜索树:简称平衡二叉树。由前苏联的数学家Adelse-Velskil和Landis在1962年提出的高度平衡的二叉树,根据科学家的英文名也称为AVL树。它具有如下几个性质:
- 可以是空树。
- 假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过1。
平衡之意,如天平,即两边的分量大约相同。如定义,假如一棵树的左右子树的高度之差超过1,如左子树的树高为2,右子树的树高为0,子树树高差的绝对值为2就打破了这个平衡。如依次插入1,2,3三个结点(如下图)后,根结点的右子树树高减去左子树树高为2,树就失去了平衡。
那么在建立树的过程中,我们如何知道左右子树的高度差呢?在这里我们采用了平衡因子进行记录。
平衡因子:左子树的高度减去右子树的高度。由平衡二叉树的定义可知,平衡因子的取值只可能为0,1,-1.分别对应着左右子树等高,左子树比较高,右子树比较高。
AVL树的插入时的失衡与调整
不平衡的4种情况
- 6节点的左子树3节点高度比右子树7节点大2,左子树3节点的左子树1节点高度大于右子树4节点,这种情况成为左左。
- 6节点的左子树2节点高度比右子树7节点大2,左子树2节点的左子树1节点高度小于右子树4节点,这种情况成为左右。
- 2节点的左子树1节点高度比右子树5节点小2,右子树5节点的左子树3节点高度大于右子树6节点,这种情况成为右左。
- 2节点的左子树1节点高度比右子树4节点小2,右子树4节点的左子树3节点高度小于右子树6节点,这种情况成为右右。
LL型
在LL型的不平衡树中,我们首先找到最小不平衡子树,再以其根结点向右旋转。为何是向右旋转呢?应该不难理解,向右旋转后,相当于右边的子树树高增加了1,而左边的子树树高降低了1,而原本的树高之差为2,那么就能够将根的平衡因子就化为0.引用一下之前的图如下。旋转之后为“原来根结点的左孩子作为新的根结点”。
我们对树以根结点为中心,向右旋转。旋转步骤如下:
- 将2作为根结点。
- 将3作为2的右孩子。
- 将2的右孩子作为3的左孩子(维护树的有序性,只是此处为NULL而已)。
旋转后,3与2的平衡因子为0,1的平衡因子保持不变。
RR型
还是引用一下之前的例子。旋转之后为“原来根结点的右孩子作为新的根结点”。旋转的步骤如下:
- 将2作为根结点。
- 将1作为2的左孩子。
- 将2的左孩子作为1的右孩子(维护树的有序性,只是此处为NULL而已)。
最后1,2,3的平衡因子都为0。
LR型
对于LR,要分为两步进行旋。旋转之后为“原来根结点的左孩子的右孩子作为新的根结点”。
第一以较高子树的根,即1,为中心向左旋转。具体步骤如下:
- 将2的左子树作为1的右子树(维护树的有序性,只是此处为NULL而已)。
- 将1作为2的左子树。
- 将2作为3的左子树。
第二以原树的根,即3为中心,向右旋转。最后结果如下:
旋转后,1,2,3的平衡因子变为0。
RL型
还是引用一下之前的例子。与LR型类似,我们需要进行两次旋转。旋转之后为“原来根结点的右孩子的左孩子作为新的根结点”。
第一,以根结点的右孩子即3为中心向右旋转,结果如下。具体步骤如下:
- 将2作为1的右孩子。
- 将3作为2的右孩子。
- 将2的右孩子作为3的左孩子(维护树的有序性,只是此处为NULL而已)。
第二,以原根结点即1,作为中心,向左旋转。结果如下。具体步骤如下:
将2作为根结点。
将1作为2的左孩子。
将2的左孩子作为1的右孩子(维护树的有序性,只是此处为NULL而已)。
最后1,2,3的平衡因子都是0。
答案代码及注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include "avl.h" #include <stdio.h> #include <stdlib.h>
int getHeight(node_t* root) { int height = 0; if (root) height = root->height; return height; } int getMax(int a, int b) { return a > b ? a : b; }
node_t* LL(node_t* root) { node_t* child = root->left; root->left = child->right; child->right = root; root->height = getMax(getHeight(root->left), getHeight(root->right)) + 1; child->height = getMax(getHeight(child->left), root->height) + 1; return child; }
node_t* RR(node_t* root) { node_t* child = root->right; root->right = child->left; child->left = root; root->height = getMax(getHeight(root->left), getHeight(root->right)) + 1; child->height = getMax(root->height, getHeight(child->right)) + 1; return child; }
node_t* RL(node_t* root) { root->right = LL(root->right); return RR(root); }
node_t* LR(node_t* root) { root->left = RR(root->left); return LL(root); } node_t* NewNode(int val) { node_t* newnode = (node_t*)malloc(sizeof(node_t)); newnode->val = val; newnode->left = NULL; newnode->right = NULL; newnode->parent = NULL; newnode->height = 0; return newnode; } node_t* avl_insert(node_t* root, int val) { if (!root) root = NewNode(val); else if (val < root->val) { root->left = avl_insert(root->left, val); if (getHeight(root->left) - getHeight(root->right) == 2) { if (val < root->left->val) root = LL(root); else root = LR(root); } } else if (val > root->val) { root->right = avl_insert(root->right, val); if (getHeight(root->right) - getHeight(root->left) == 2) { if (val > root->right->val) root = RR(root); else root = RL(root); } } root->height = getMax(getHeight(root->left), getHeight(root->right)) + 1; return root; }
|