平衡二叉树
1.平衡二叉树的定义
为了避免树的高度增长过快,降低二叉排序树的性能,我们规定在插入和删除节点时保证节点左右子树的高度差绝对值不超过一,这样的树称为平衡二叉树(也称AVL树),定义节点的左右子树的高度差为该节点的平衡因子,则此值只能为-1,0,1.
特性:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
引用
2.作用
我们知道,对于一般的二叉搜索树(Binary Search Tree),其期望高度(即为一棵平衡树时)为log2n,其各操作的时间复杂度(O(log2n))同时也由此而决定。但是,在某些极端的情况下(如在插入的序列是有序的时),二叉搜索树将退化成近似链或链,此时,其操作的时间复杂度将退化成线性的,即O(n)。我们可以通过随机化建立二叉搜索树来尽量的避免这种情况,但是在进行了多次的操作之后,由于在删除时,我们总是选择将待删除节点的后继代替它本身,这样就会造成总是右边的节点数目减少,以至于树向左偏沉。这同时也会造成树的平衡性受到破坏,提高它的操作的时间复杂度。
3.数据结构
struct node {
int val;
node *left, *right;
};
4.二叉平衡术的插入
1)RR旋转(左旋)
把B节点提起来,B的左挂到A的右,然后A再连到B的左,return
code:
node *rotateLeft(node *root) { //左旋 ,破坏者为右子树的右子树
node *t = root->right;
root->right = t->left;
t->left = root;
return t;
}
2)LL旋转(右旋)
把B节点提起来,B的右挂到A的左,然后A再连到B的右,return
code:
node *rotateRight(node *root) { //右旋 ,破坏者为左子树的左子树
node *t = root->left;
root->left = t->right;
t->right = root;
return t;
}
3)LR旋转(先左后右双旋)
code:
node *rotateLeftRight(node *root) { //‘麻烦节点 ’在左子树的右子树
root->left = rotateLeft(root->left);
return rotateRight(root);
}
4)RL旋转(先右后左双旋)
code:
node *rotateRightLeft(node *root) {
root->right = rotateRight(root->right); // ‘麻烦节点 ’在右子树的左子树
return rotateLeft(root);
}
5.建立AVL树
1) 获取树的高度
int getHeight(node *root) {
if(root == NULL) return 0;
return max(getHeight(root->left), getHeight(root->right)) + 1;
}
2)插入结点并调整平衡
node *insert(node *root, int val) { //建立 BST tree 并调整平衡,不能有相同节点
if(!root) {
root = new node;
root->val = val;
root->left = root->right = NULL;
} else if(val < root->val) {
root->left = insert(root->left, val); //插入
if(getHeight(root->left) - getHeight(root->right) ==2)
root = val < root->left->val ? rotateRight(root) : rotateLeftRight(root); //旋转调整平衡
} else {
root->right = insert(root->right, val);//插入
if(getHeight(root->left) - getHeight(root->right) == -2)
root = val > root->right->val ? rotateLeft(root) : rotateRightLeft(root); //旋转调整平衡
}
return root;
}
6.完整代码
#include<iostream>
using namespace std;
struct node {
int val;
node *left, *right;
};
node *rotateLeft(node *root) { //左旋 ,破坏者为右子树的右子树
node *t = root->right;
root->right = t->left;
t->left = root;
return t;
}
node *rotateRight(node *root) { //右旋
node *t = root->left;
root->left = t->right;
t->right = root;
return t;
}
node *rotateLeftRight(node *root) { //‘麻烦节点 ’在左子树的右子树
root->left = rotateLeft(root->left); //LR旋转
return rotateRight(root);
}
node *rotateRightLeft(node *root) {
root->right = rotateRight(root->right); // ‘麻烦节点 ’在右子树的左子树
return rotateLeft(root);//先对右子树右旋,在左旋
}
int getHeight(node *root) {
if(root == NULL) return 0;
return max(getHeight(root->left), getHeight(root->right)) + 1;
}
node *insert(node *root, int val) {
if(root == NULL) {
root = new node;
root->val = val;
root->left = root->right = NULL;
} else if(val < root->val) {
root->left = insert(root->left, val);
if(getHeight(root->left) - getHeight(root->right) > 1)
root = val < root->left->val ? rotateRight(root) : rotateLeftRight(root);
} else {
root->right = insert(root->right, val);
if(getHeight(root->left) - getHeight(root->right) < -1)
root = val > root->right->val ? rotateLeft(root) : rotateRightLeft(root);
}
return root;
}
void PreOrder(node *root){
node *T=root;
if(T){
cout<<T->val <<" ";
PreOrder(root->left );
PreOrder(root->right );
}
}
void InOrder(node *root){
node *T=root;
if(T){
InOrder(root->left );
cout<<T->val <<" ";
InOrder(root->right );
}
}
int main() {
int n, val;
cin>>n;
node *root = NULL;
for(int i = 0; i < n; i++) {
cin>>val;
root = insert(root, val);
}
cout<<endl<<"先序遍历结果:"<<endl;
PreOrder(root);
cout<<endl<<"中序遍历结果:"<<endl;
InOrder(root);
cout<<endl<<"输入一个插入节点N:"<<endl;
node *T;
while(cin>>n){
T=insert(root, n);
cout<<endl<<"先序遍历结果:"<<endl;
PreOrder(T);
cout<<endl<<"中序遍历结果:"<<endl;
InOrder(T);
root=T;
cout<<endl<<"输入一个插入节点N:"<<endl;
}
return 0;
}
由先序遍历和中序遍历可唯一确定一颗二叉树,且中序遍历可得到升序序列.
测试数据运行截图如下: