AvlTree
定义
AVL 树是一种平衡二叉树,得名于其发明者的名字( Adelson-Velskii 以及 Landis)。(可见名字长的好处,命名都能多占一个字母出来)。平衡二叉树递归定义如下:
- 左右子树的高度差小于等于 1。
- 其每一个子树均为平衡二叉树。
平衡因子: 某个结点的左子树的高度减去右子树的高度得到的差值。
AVL 树: 所有结点的平衡因子的绝对值都不超过 1 的二叉树。
为了计算平衡因子,我们自然需要在节点中引入高度这一属性。在这里,我们把节点的高度定义为其左右子树的高度的最大值。因此,引入了高度属性的 AVL 树的节点定义如下:
1 2 3 4 5 6
| typedef struct node { int data; int height; struct node *left; struct node *right; }node_t, * nodeptr_t;
|
计算某一个节点的高度
1 2 3 4 5 6 7
| int treeHeight(nodeptr_t root) { if(root == NULL) { return 0; } else { return max(treeHeight(root->left),treeHeight(root->right)) + 1; } }
|
我们在进行如下操作时需要更新受影响的所有节点的高度:
- 在插入结点时, 沿插入的路径更新结点的高度值
- 在删除结点时(delete),沿删除的路径更新结点的高度值
有了高度,计算平衡因子的操作就得以很简单的实现:
1 2 3 4 5 6
| int treeGetBalanceFactor(nodeptr_t root) { if(root == NULL) return 0; else return x->left->height - x->right->height; }
|
当平衡因子的绝对值大于 1 时,就会触发树的修正,或者说是再平衡操作。
树的平衡化操作
二叉树的平衡化有两大基础操作: 左旋和右旋。左旋,即是逆时针旋转;右旋,即是顺时针旋转。这种旋转在整个平衡化过程中可能进行一次或多次,这两种操作都是从失去平衡的最小子树根结点开始的(即离插入结点最近且平衡因子超过1的祖结点)。
右旋

所谓右旋操作,就是把上图中的 B 节点和 C 节点进行所谓“父子交换”。在仅有这三个节点时候,是十分简单的。但是当 B 节点处存在右孩子时,事情就变得有点复杂了。我们通常的操作是:抛弃右孩子,将之和旋转后的节点 C 相连,成为节点 C 的左孩子。这样,我们就能写出对应的代码。
1 2 3 4 5 6 7 8 9 10 11
| nodeptr_t treeRotateRight(nodeptr_t root) { nodeptr_t left = root->left; root->left = left->right; left->right = root;
left->height = max(treeHeight(left->left), treeHeight(left->right))+1; right->height = max(treeHeight(right->left), treeHeight(right->right))+1; return left; }
|
左旋

左旋操作和右旋操作十分类似
1 2 3 4 5 6 7 8 9 10 11
| nodeptr_t treeRotateLeft(nodeptr_t root) { nodeptr_t right = root->right;
root->right = right->left; right->left = root;
left->height = max(treeHeight(left->left), treeHeight(left->right))+1; right->height = max(treeHeight(right->left), treeHeight(right->right))+1;
return right; }
|
需要平衡的四种情况
LL

RR

LR

RL
实现
平衡化操作的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| nodeptr_t treeRebalance(nodeptr_t root) { int factor = treeGetBalanceFactor(root); if(factor > 1 && treeGetBalanceFactor(root->left) > 0) return treeRotateRight(root); else if(factor > 1 && treeGetBalanceFactor(root->left) <= 0) { root->left = treeRotateLeft(root->left); return treeRotateRight(temp); } else if(factor < -1 && treeGetBalanceFactor(root->right) <= 0) return treeRotateLeft(root); else if((factor < -1 && treeGetBalanceFactor(root->right) > 0) { root->right = treeRotateRight(root->right); return treeRotateLeft(root); } else { return root; } }
|
插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| void treeInsert(nodeptr_t *rootptr, int value) { nodeptr_t newNode; nodeptr_t root = *rootptr;
if(root == NULL) { newNode = malloc(sizeof(node_t)); assert(newNode);
newNode->data = value; newNode->left = newNode->right = NULL;
*rootptr = newNode; } else if(root->data == value) { return; } else { if(root->data < value) treeInsert(&root->right,value); else treeInsert(&root->left,value) }
treeRebalance(root); }
|
删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| void treeDelete(nodeptr_t *rootptr, int data) { nodeptr_t *toFree; nodeptr_t root = *rootptr;
if(root) { if(root->data == value) { if(root->right) { root->data = treeDeleteMin(&(root->right)); } else { toFree = root; *rootptr = toFree->left; free(toFree); } } else { if(root->data < value) treeDelete(&root->right,value); else treeDelete(&root->left,value) }
treeRebalance(root); } }
|