平衡二叉树(AVL树)
-
前提一定是搜索二叉树,对于根节点的左右子树的高度差不能超过1,并且所有子树都要循序这个要求
-
如果一个搜索二叉树呈现或接近单支状,它的查找效率很低,很接近链表,因此如果能让它平衡时,查找效率最高
-
由于节点的位置要受到相互之间值的影响,并且在往平衡二叉树中添加节点或者删除节点前,二叉树本身是平衡的,所以只可能在最后操作的节点附近不满足平衡条件,因此需要在该过程中对该节点进行判断并调整。
-
因此一棵平衡二叉树因为添加操作导致不平衡的原因,总结就四种:
第一种: x y / \ / \ y t1 z x / \ / \ / \ z t2 t3 t4 t2 t1 / \ t3 t4 以y为轴 右旋转 第二种: x y / \ / \ t1 y x z / \ / \ / \ t2 z t1 t2 t3 t4 / \ t3 t4 以y为轴 左旋转 第三种: x x z / \ / \ / \ y t1 z t1 y x / \ / \ / \ / \ t2 z y t4 t2 t3 t4 t1 / \ / \ t3 t4 t2 t3 先以z为轴左旋转 再以z为轴右旋转 达到平衡 第四种: x x z / \ / \ / \ t1 y t1 z x y / \ / \ / \ / \ z t2 t3 y t1 t3 t4 t2 / \ / \ t3 t4 t4 t2 先以z为轴右旋转 再以z为轴左旋转 达到平衡
删除节点
-
待删除的节点是叶子节点,直接删除
-
待删除节点的左子树或者右子树为空,则使用非空节点替换
-
待删除节点左右子树非空,则根据左右子树的高度,选择高的一边子树,如果是左子树高,选择左子树中的最大节点赋值给待删除节点,然后再左子树中继续删除该最大节点,相当于继续处理情况1或情况2;如果是右子树高,则在右子树选择最小值节点继续同样处理。
-
删除后可能导致不平衡,需要重新调整平衡
平衡二叉树的优点:
避免了二叉搜索树呈现单支状,让其能以最佳的效率进行查找操作 O(log2n)
平衡二叉树的缺点:
在插入、删除操作时,为了达到平衡需要进行大量的左旋、右旋操作、计算高度,所以此时操作速度慢
因此AVL树适合在数据量大并且数据量比较稳定,没有太多的插入、删除操作,适合大量的查找操作。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 设计二叉树节点结构
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
// 创建节点
TreeNode* create_tree_node(int data)
{
TreeNode* node = malloc(sizeof(TreeNode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
// 求高度
int high_tree(TreeNode* root)
{
if(NULL == root) return 0;
int lh = high_tree(root->left);
int rh = high_tree(root->right);
return lh>rh ? lh+1 : rh+1;
}
// 计算左右子树高度差
int def_high(TreeNode* root)
{
if(NULL == root) return 0;
return high_tree(root->left) - high_tree(root->right);
}
// 左旋转
TreeNode* left_rotate(TreeNode* x)
{
TreeNode* y = x->right;
TreeNode* t2 = y->left;
y->left = x;
x->right = t2;
return y;
}
// 右旋转
TreeNode* right_rotate(TreeNode* x)
{
TreeNode* y = x->left;
TreeNode* t2 = y->right;
y->right = x;
x->left = t2;
return y;
}
// 自动调整平衡 并返回调整后的根节点
TreeNode* auto_balance(TreeNode* x)
{
if(NULL == x) return NULL;
int lh = high_tree(x->left);
int rh = high_tree(x->right);
// 左子树高于右子树 超过1
if(lh - rh > 1)
{
// 情况1
if(def_high(x->left) >= 0)
{
// 右旋转
x = right_rotate(x);
}
// 情况3
else
{
// 左旋转
x->left = left_rotate(x->left);
// 右旋转
x = right_rotate(x);
}
}
// 或者 右高于左 超过1
else if(rh - lh > 1)
{
// 情况2
if(def_high(x->right) <= 0)
{
// 左旋转
x = left_rotate(x);
}
// 情况4
else
{
// 右旋转
x->right = right_rotate(x->right);
// 左旋转
x = left_rotate(x);
}
}
return x;
}
// 添加 返回添加成功后的根节点
TreeNode* insert_tree(TreeNode* root,int data)
{
if(NULL == root)
return create_tree_node(data);
// 节点添加到合适的位置中
if(data < root->data)
root->left = insert_tree(root->left,data);
else
root->right = insert_tree(root->right,data);
// 有可能添加后该位置破坏平衡 需要调整
root = auto_balance(root);
return root;
}
// 找最大值
TreeNode* max_tree_node(TreeNode* root)
{
if(NULL == root) return NULL;
TreeNode* max = root;
while(max->right) max = max->right;
return max;
}
// 找最小值
TreeNode* min_tree_node(TreeNode* root)
{
if(NULL == root) return NULL;
TreeNode* min = root;
while(min->left) min = min->left;
return min;
}
TreeNode* delete_tree(TreeNode* root,int data)
{
if(NULL == root) return NULL;
if(root->data == data)
{
// 左右皆空 直接删
if(NULL == root->left && NULL == root->right)
{
free(root);
return NULL;
}
// 左空 替换为右子树
if(NULL == root->left)
{
TreeNode* temp = root->right;
free(root);
return temp;
}
// 右空 替换为左子树
if(NULL == root->right)
{
TreeNode* temp = root->left;
free(root);
return temp;
}
// 左右都非空
// 左边高
if(def_high(root) >= 0)
{
TreeNode* max = max_tree_node(root->left);
root->data = max->data;
root->left = delete_tree(root->left,max->data);
}
// 右边高
else
{
TreeNode* min = min_tree_node(root->right);
root->data = min->data;
root->right = delete_tree(root->right,min->data);
}
// 重新调整平衡
root = auto_balance(root);
return root;
}
if(data < root->data)
root->left = delete_tree(root->left,data);
else
root->right = delete_tree(root->right,data);
// 重新调整平衡
root = auto_balance(root);
return root;
}
// 遍历
void dlr_show(TreeNode* root)
{
if(NULL == root) return;
printf("%d ",root->data);
dlr_show(root->left);
dlr_show(root->right);
}
void ldr_show(TreeNode* root)
{
if(NULL == root) return;
ldr_show(root->left);
printf("%d ",root->data);
ldr_show(root->right);
}
void lrd_show(TreeNode* root)
{
if(NULL == root) return;
lrd_show(root->left);
lrd_show(root->right);
printf("%d ",root->data);
}
int main(int argc,const char* argv[])
{
TreeNode* root = NULL;
for(int i=0; i<10; i++)
{
root = insert_tree(root,i+1);
}
root = insert_tree(root,20);
root = delete_tree(root,4);
dlr_show(root);
printf("\n");
ldr_show(root);
printf("\n");
lrd_show(root);
printf("\n");
}