手撕AVL树(含旋转代码讲解 + 例题)

本文详细解析AVL树的原理与四种旋转操作(LL、LR、RR、RL),并通过示意图与代码实例帮助读者深入理解。文章还对比了AVL树与红黑树的特点及适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前引


因为这段时间学习数据库 看到B 和 B+树 感觉到很陌生 觉得这个时候是时候去整理一些之前数据结构拖欠的相关比较复杂的树的内容了 所以也就有了此篇

我的初步打算 是打算手撕系列 写两篇 一篇写手撕AVL 一篇写手撕红黑树 手撕红黑树 哈哈 希望自己之后能够写下来 因为红黑树在面试中的考察频率还是相当高的 所以我觉得如果不手撕一次 我是没有办法彻底理解红黑树的实现的

如果面试中 考察了红黑树插入删除 没有手撕一次的过程 肯定在面试的那种状态下肯定是写不出来的 所以于是就这样打算吧

至于B树 与 B+树的话 我应该是会写一篇专门写 B树与B+树的博客 来写应用场景 B树B+树的优点 还有其他很多关于它的
这部分就先写到这里 我们直接先进入AVL树的部分吧


手撕数据结构 总结博客链接


手撕数据结构(最小堆 + 二叉树前中后非递归遍历 + 快排归并排序 + KMP匹配算法 + AVL + 红黑树)


AVL树的理解


针对AVL树 我用自己的话来说一下吧

AVL树:最早发明的完全平衡二叉查找树
优点:高度平衡 对于插入、删除较少的管理需求处理良好 因为高度平衡 所以搜寻速度也相当块
缺点:正是因为高度平衡这个特性,满足这个特性自然而然需要付出代价,代价就是 对于局部调整非常多,导致每次插入、删除的时间自然而然就更多;优点也正是它的缺点(不适合对插入、删除需求大的模型)


既然聊到了AVL树 就不得不聊聊它的大哥 红黑树
红黑树的光芒明显比AVL树耀眼的多 耀眼到很多人基本上都忘记了有AVL的存在 但是的确 红黑树的应用范围要比AVL树广的太多了
那我们下面简单的聊一下红黑树吧 置于详细的聊它 我们在关于红黑树专题里面再聊了

红黑树:弱平衡的二叉搜索树
优点:相较于AVL树 每次插入、删除不保证绝对高度平衡,而只保证整体性平衡,插入删除的代价相对于AVL小的多,查找的效率也比较高,应用范围广泛
缺点:没什么缺点 在绝大部分实际应用场所 表现良好^^(有点点偏心了)


LL、LR、RR、RL旋转


下面的话 我们就直接进入LL LR RR RL旋转的解析
对于二叉树DELETE 没什么好说的 其实重点就是LL LR RR RL旋转
删除找到最后那个点 出现不平衡 同样的我们用LL LR即可
对于INSERT一个道理 先插入 后旋转

所以我们重点的就是对于不平衡的时候我们究竟怎么去处理
这里就涉及4种旋转方式了 分别是上面提及的四种 关键的就是我们怎么去处理


1、LL旋转


1、LL旋转示意图

这里我用Word做了一幅示意图 方便大家理解
转换前发现问题时的三个60 55 50 当然55右边可以是null 但是我们不能忽视它
在这里插入图片描述


好了 根据我最后做出来的代码 和 示意图 就发现 最后要完成AVL树 目的就是要把 我们节点中 被移动过的指针 或者叫做需要旋转的指针 每个都给它再重复利用一次 你可能不清楚我在说什么 我把转换后的图再放上来

我们可以很清楚的发现 我们变动过root->left root->right right->left指针 其余指针都是没有更改过其值的 刚好我们最后的转换形态 也只是这三个指针被赋予了新的值 好了 我们再结合代码来说一下吧

其实把图画出来 我们只需要把代码按照图的形式赋值上去即可
在这里插入图片描述


2、LL旋转代码

Tree LLrotation(Tree T)//LL转向函数
{
    Tree root = T->left,left = T->left->left,right = T,root_right = root->right;
    root->left = left; 
    root->right = right;
    right->left = root_right;
    return root;
}

2、RR旋转


1、RR旋转示意图

其实在把图画出来了之后 我们按照哪些指针用过了 按照顺序重新摆放那些节点 最后用代码表示出来就行了 图如下
旋转前
在这里插入图片描述


旋转后
在这里插入图片描述


2、RR旋转代码

Tree RRrotation(Tree T)//RR转向函数
{
    Tree root = T->right,left = T,right = T->right->right,root_left = root->left;
    root->left = left;
    root->right = right;
    left->right = root_left;
    return root;
}

3、LR旋转


1、LR旋转示意图

注意 这里我们的root 就需要考虑下面的两边指针了 因为我们root两边之后都会是left right 所以需要注意之后安置的位置
旋转前
在这里插入图片描述


旋转后
在这里插入图片描述


2、LR旋转代码

Tree LRrotation(Tree T)//LR转向函数
{
    Tree root = T->left->right,left = T->left,right = T,root_left = root->left,root_right = root->right;
    root->left = left;
    root->right = right;
    left->right = root_left;
    right->left = root_right;
    return root;
}

4、RL旋转


1、RL旋转示意图

旋转前
在这里插入图片描述


旋转后
在这里插入图片描述


2、RL旋转代码

Tree RLrotation(Tree T)//RL转向函数
{
    Tree root = T->right->left,left = T,right = T->right,root_left = root->left,root_right = root->right;
    root->left = left;
    root->right = right;
    left->right = root_left;
    right->left = root_right;
    return root;
}

AVL树代码实现


#include <stdio.h>
#include <stdlib.h>

typedef struct tree
{
    int Data;
    struct tree *left,*right;
}   *Tree;
Tree MakeTree(int numbers);
Tree NewNode(int Data);
Tree LLrotation(Tree T);//LL转向函数
Tree LRrotation(Tree T);//LR转向函数
Tree RRrotation(Tree T);//RR转向函数
Tree RLrotation(Tree T);//RL转向函数
Tree Insert(Tree T,int Data);//插入函数
int Height(Tree T);//测量高度的函数


Tree MakeTree(int numbers)
{
    int Data,i;
    Tree T;
    scanf("%d",&Data);
    T = NewNode(Data);
    for(i=1;i<numbers;i++)
    {
        scanf("%d",&Data);
        T = Insert(T,Data);
    }
    return T;
}

Tree NewNode(int Data)
{
    Tree T;
    T = (Tree)malloc(sizeof(struct tree));
    T->Data = Data;
    T->left = NULL;
    T->right = NULL;
    return T;
}

Tree LLrotation(Tree T)//LL转向函数
{
    Tree root = T->left,left = T->left->left,right = T,root_right = root->right;
    root->left = left;
    root->right = right;
    right->left = root_right;
    return root;
}

Tree RRrotation(Tree T)//RR转向函数
{
    Tree root = T->right,left = T,right = T->right->right,root_left = root->left;
    root->left = left;
    root->right = right;
    left->right = root_left;
    return root;
}

Tree LRrotation(Tree T)//LR转向函数
{
    Tree root = T->left->right,left = T->left,right = T,root_left = root->left,root_right = root->right;
    root->left = left;
    root->right = right;
    left->right = root_left;
    right->left = root_right;
    return root;
}

Tree RLrotation(Tree T)//RL转向函数
{
    Tree root = T->right->left,left = T,right = T->right,root_left = root->left,root_right = root->right;
    root->left = left;
    root->right = right;
    left->right = root_left;
    right->left = root_right;
    return root;
}

Tree Insert(Tree T,int Data)//插入函数
{
    if(!T)
    {
        Tree newtree = NewNode(Data);
        return newtree;
    }
    
    if(Data <= T->Data)    T->left = Insert(T->left,Data);
    else                   T->right = Insert(T->right,Data);
    
    int left_height = Height(T->left);
    int right_height = Height(T->right);
    
    if(left_height == right_height + 2)
    {
        if(Data <= T->left->Data)   T = LLrotation(T);
        else                        T = LRrotation(T);
    }    
    else if(right_height == left_height + 2)
    {
        if(Data <= T->right->Data)  T = RLrotation(T);
        else                        T = RRrotation(T);
    }
    return T;
}

int Height(Tree T)//测量高度的函数
{
    if(!T)  return 0;
    return max(Height(T->left) , Height(T->right)) + 1;
}

int main(void)
{
    int numbers;
    Tree T;
    scanf("%d",&numbers);
    T = MakeTree(numbers);
    printf("%d",T->Data);
    return 0;
}



例题 PTA (Root Of AVL Tree)


PTA 题目链接 2021年秋季 Root Of AVL Tree

大家可以去Mooc搜索浙大数据结构 然后看背后的例题 里面就含有这个链接 具体怎么样我就不再放链接了 然后下面这篇就是我的解答博客 这道题目里面综合考察了四种旋转 还有INSERT函数如何去写 对于AVL树考察的相当全面

那就先写到这里 各位有缘再见~
(c语言)Root of AVL Tree (25分)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Love 6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值