关于调节AVL树的平衡(左右旋)
AVL树:具有以下性质的二叉搜索树:左右孩子也都是AVL树,并且左右子树高度差的绝对值不超过1(平衡因子为-1,0,1中的一个)。
平衡因子:该节点右子树和左子树的高度差,这个数字即是这个结点的平衡因子。
也就是说:AVL树是在BST树的基础上增加了平衡因子的概念,变成了平衡二叉搜索树。
关于结点类型和树的设计:
typedef int KeyType;
typedef struct AVLNode{
AVLNode*left;
AVLNode*right;
AVLNode*parent;
KeyType key;
int balance;
}AVLNode;
typedef struct AVLTree{
AVLNode* head;
KeyType cursize;
}AVLTree;
AVL树的结点插入
与BST树的插入方法相同,但是因为平衡因子的加入,当插入结点时,可能是AVL的树的平衡性发生了变化,所以我们需要进行平衡调整。从插入结点的位置开始向根节点回溯,检查各结点的平衡因子,找到不平衡的结点的时候,沿刚才回溯的路径往下取两个结点
- 如果三个结点构成一个条直线,并且方向向左下方,进行右单旋。
- 如果三个结点构成一个条直线,并且方向向右下方,进行左单旋。
- 如果三个结点构成折线,先左后右,进行左右双旋。
- 如果三个结点构成折线,先右后左,进行右左双旋。
右单旋
在C的左孩子增加结点D,从D开始往根节点回溯检查平衡因子,发现A结点的平衡因子为-2,这个AVL树失去平衡,按刚才的路径往下找三个结点:A B C,三个结点构成一个方向是左下方的直线,所以,以B为轴进行右单旋。
- 将ptr的左孩子作为newroot
newroot->parent=ptr->parent
- 将ptr的左孩子指向newroot的右孩子
ptr->left=newroot->right
①当new的右孩子不为空的时候,需要将newroot的右孩子的parent指向ptr
- 将newroot的右孩子指向ptr
newroot->right=ptr
①当ptr是树的根节点的时候,需要将头结点的parent指向newroot
②不是根节点的时候,看ptr是ptr父结点的左孩子还是右孩子,将newroot接回去,这里可能就有人问了,第一步的时候不是已经接回去了嘛?为什么还接一次?因为结点是双向的
③再把ptr的parent指向newroot
- 完成
具体代码实现:
void RoteteRight(AVLTree*ptree, AVLNode*ptr)
{
//1 将ptr的左孩子作为newroot
AVLNode *newroot = ptr->left;
newroot->parent = ptr->parent;
//2 将ptr的左孩子指向newroot的右孩子
ptr->left= newroot->right;
if (newroot->right != NULL)
{
newroot->right->parent = ptr;
}
//3 将newroot的右孩子指向ptr
newroot->right = ptr;
if (ptree->head->parent == ptr) //如果ptr是树的根节点
{
ptree->head->parent = newroot;//将头结点的parent指向newroot
}
else
{
//看ptr是它父结点的左孩子还是右孩子
if (ptr = ptr->parent->left)
{
ptr->parent->left = newroot;
}
else
ptr->parent->right = newroot;
}
ptr->parent = newroot;
}
左单旋
思路和右单旋是相同的,相对操作时镜像的。
单旋以三个结点中的第二个为旋转轴
双旋以最下面的结点为旋转轴(两次旋转都已这个结点为轴)