点击查看代码
#include<cstdio>
#include<algorithm>
using namespace std;
#pragma warning(disable:4996)
//平衡二叉树AVL的定义
struct node {
int data; //数据域
int height; //以当前结点为根结点的左右子树高度差
node* lchild, * rchild; //左右孩子结点地址
};
//新建一个权值为data的结点
node* newNode(int data) {
node* Node = new node; //申请新结点内存
Node->data = data; //存储结点权值
Node->height = 1; //新结点高度初始为1
Node->lchild = Node->rchild = NULL; //结点左右孩初始为空结点
return Node; //返回新结点地址
}
//获取以root为根结点的子树的当前高度
int getHeight(node* root) {
if (root == NULL) return 0; //空结点高度为0
return root->height; //返回结点高度
}
//计算根结点root的平衡因子
int getBalanceFactor(node* root) {
return getHeight(root->lchild) - getHeight(root->rchild); //左子树高度减右子树高度
}
//更新根结点root的高度
void updateHeight(node* root) {
//根结点高度等于其左子树高度或右子树高度的较大者加一
root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
}
//平衡二叉树AVL的基本操作
//AVL是二叉查找树,查找操作与二叉查找树一样
void search(node* root, int data) { //查找权值为data的结点
if (root == NULL) { //遇到空结点时查找失败
printf("search failed\n");
return; //结束递归,返回上一层
}
if (root->data == data) { //找到权值为data的结点
printf("%d\n", root->data); //输出结点权值
}
else if (data < root->data) { //待查权值data小于根结点权值
search(root->lchild, data); //进入左子树中查找
}
else { //待查权值data大于根结点权值
search(root->rchild, data); //进入右子树中查找
}
}
//AVL的插入操作是在BST的插入操作基础上,增加二叉树的平衡操作
//在AVL中插入一个新结点后如果出现不平衡,则要使用左旋或右旋重新平衡AVL
void L(node*& root) { //左旋left rotation,root会被修改地址,使用引用指针型
node* temp = root->rchild; //temp指向root的右孩
root->rchild = temp->lchild; //root的右孩指向temp的左孩
temp->lchild = root; //temp的左孩指向root
updateHeight(root); //更新root的高度
updateHeight(temp); //更新temp的高度
root = temp; //root重新指向根结点
}
//右旋就是把左旋中的所有lchild和rchild互换,它们是互为逆操作
void R(node*& root) {
node* temp = root->lchild; //temp指向root的左孩
root->lchild = temp->rchild; //root的左孩指向temp的右孩
temp->rchild = root; //temp的右孩指向root
updateHeight(root); //更新root的高度
updateHeight(temp); //更新temp的高度
root = temp; //root重新指向根结点
}
/*在AVL树中插入一个结点后,可能出现4种不平衡情况:(BF是指平衡因子,如BF(root)=2表示根结点的平衡因子为2)
(1)在左子树中插入新结点出现不平衡
1)LL型:BF(root)=2, BF(root->lchild)=1,对root进行右旋
2)LR型:BF(root)=2, BF(root->lchild)=-1, 先对root->lchild进行左旋变为LL型,再对root进行右旋
(2)在右子树中插入新结点出现不平衡
1)RR型:BF(root)=-2, BF(root->rchild)=-1, 对root进行左旋
2)RL型:BF(root)=-2, BF(root->rchild)=1, 先对root->rchild进行右旋变为RR型,再对root进行左旋
*/
void insert(node*& root, int data) { //插入权值为data的结点到AVL中
if (root == NULL) { //root是空结点找到插入位置
root = newNode(data); //新建一个权值为datat的结点,地址赋给root
return; //结束递归,返回上一层
}
if (data < root->data) { //权值data小于root
insert(root->lchild, data); //递归进入左子树中查找插入位置
updateHeight(root); //插入完成后,更新根结点高度
if (getBalanceFactor(root) == 2) { //如果根结点平衡因子为2,则发生不平衡
if (getBalanceFactor(root->lchild) == 1) { //左孩平衡因子为1,则变为LL型
R(root); //对root进行右旋恢复平衡
}
else if (getBalanceFactor(root->lchild) == -1) { //左孩平衡因子为-1,则变为LR型
L(root->lchild); //先对左孩进行左旋变为LL型
R(root); //再对root进行右旋恢复平衡
}
}
}
else { //权值data大于等于root
insert(root->rchild, data); //进入右子树中查找插入位置
updateHeight(root); //插入完成后,更新根结点高度
if (getBalanceFactor(root) == -2) { //如果根结点平衡因子为-2,则发生不平衡
if (getBalanceFactor(root->rchild) == -1) { //右孩平衡因子为-1,则变为RR型
L(root); //对root进行左旋恢复平衡
}
else if (getBalanceFactor(root->rchild) == 1) { //右孩平衡因子为1,则变为RL型
R(root->rchild); //先对右孩进行右旋变为RR型
L(root); //再对root进行左旋恢复平衡
}
}
}
}
//建立AVL树
node* create(int data[], int n) {
node* root = NULL; //新建树的根结点root,初始为空结点
for (int i = 0; i < n; i++) {
insert(root, data[i]); //将data[0]~data[n-1]插入AVL树中
}
return root;
}