平衡二叉树(AVL树)
- height balanced
- |hL- hR| <= 1
- 平衡因子 BL(node) = hL - HR
- 给定结点数为n的AVL树最大高度为O(log2n)
树的高度:根节点高度为0,向下每层加一
给定一组数据,逐个插入时:按照查找的方式插入,再旋转调整
调整方法:
- 左单旋(LL),即麻烦结点在发现者左边的左边,解决方案是顺时针转
- 右单旋(RR)
- 左-右双旋(LR)
A必须有一个左子结点B,且B必须有一个右子结点C
将B与C做右单旋
将A与C做左单旋 - 右-左双旋(RL)
- 注:根据麻烦结点(trouble maker)的位置定义
以下代码源自浙江大学数据结构MOOC
typedef struct AVLNode *Position;
typedef Position AVLTree; /*AVL树类型*/
struct AVLNode{
ElementType Data; /*结点数据*/
AVLTree Left; /*指向左子树*/
AVLTree Right; /*指向右子树*/
int Height; /*树高*/
};
int Max(int a, int b){
return a>b ? a : b;
}
AVLTree SingleLeftRotation(AVLTree A){
/*注意:A必须有一个左子结点B*/
/*将A与B做左单旋,更新A与B的高度,返回新的根节点B*/
AVLTree B;
B = A->Left;
A->Left = B->Right;
B->Right = A;
A->Height = Max(GetHeight(A->Left), GetHeight(A->Right))+1;
B->Height = Max(GetHeight(B->Left), GetHeight(A))+1;
return B;
}
AVLTree DoubleLeftRightRotation(AVLTree A){
/*A必须有一个左子结点B,且B必须有一个右子结点C*/
/*将A,B与C做两次单旋,并返回新的根节点C*/
/*将B与C做右单旋,返回C*/
A->Left = SingleRightRotation(A->Left);
/*将A与C做左单旋,返回C*/
return SingleLeftRotation(A);
}
/*对称的右单旋,右-左双旋省略不写*/
AVLTree Insert(AVLTree T, ElementType X){
/*将X插入AVL树T中,并返回调整后的AVL树*/
if(!T){ /*若插入空树,则新建包含一个结点的树*/
T = (AVLTree)malloc(sizeof(struct AVLNode));
T->Data = X;
T->Left = T->Right = NULL;
T->Height = 0;
}
else if(X < T->Data){
/*插入T的左子树*/
T->Left = Insert(T->Left, X);
/*如果需要左旋*/
if(GetHeight(T->Left)-GetHeight(T->Right) == 2){
if(X < T->Left->Data)
T = SingleLeftRotation(T); /*左单旋*/
else
T = DoubleLeftRightRotation(T); /*左-右双旋*/
}
}
else if(X > T->Data){
/*插入T的右子树*/
T->Right = Insert(T->Right, X);
/*如果需要右旋*/
if(GetHeight(T->Left)-GetHeight(T->Right) == -2){
if(X > T->Right->Data)
T = SingleRightRotation(T); /*右单旋*/
else
T = DoubleRightLeftRotation(T); /*左-右双旋*/
}
}
/*else X == T->Data 无需插入*/
/*更新树高*/
T->Height = Max(GetHeight(T->Left), GetHeight(T->Right))+1;
return T;
}
下面两张图是我自己画的,希望可以帮大家更好地理解
也推荐大家自己画一遍,画完就懂啦