AVL树笔记(一):zig-zag,insert,find,predecessor,successor
2015-11-16 22:35
585 查看
AVL树就是一棵平衡的二叉查找树。
其维护平衡的方式是:维护一个平衡因子h,即子树高度,如果左子树高度和右子树高度相差2,那么就旋转把它弄平衡。
![](https://img-blog.csdn.net/20151116234603809)
这个二叉树明显不平衡,可以发现全部左偏,于是右旋。
右旋就是当前节点的左儿子 的 右儿子是当前节点。
如果当前节点有右儿子,怎么办?
那么把这个右儿子拆下来然后装在当前节点的左儿子上。
如图:
![](https://img-blog.csdn.net/20151116235752755)
![](https://img-blog.csdn.net/20151116234728335)
这个二叉树明显不平衡,可以发现全部右偏,于是左旋。
左旋就是当前节点的右儿子 的 左儿子是当前节点。
如果当前节点有左儿子,怎么办?
那么把这个左儿子拆下来然后装在当前节点的右儿子上。
这个不给图了。
![](https://img-blog.csdn.net/20151116234930459)
这个二叉树明显不平衡,下面右偏上面左偏,于是先左旋再右旋。
![](https://img-blog.csdn.net/20151116235040045)
这个二叉树明显不平衡,下面左偏上面右偏,于是先右旋再左旋。
说白了就是全部反着来,是不是很好懂?
旋转完了,然后insert。
insert就是先插入进去,然后如果不平衡就旋转一下,就平衡了。
顺便更新h。
insert完了,然后find,predecessor,successor。
find,predecessor,successor就和二叉查找树一样。
明天讲讲delete。
附代码:
这个题是BZOJ1588(HNOI2002)就是求前驱后继的裸题。
其维护平衡的方式是:维护一个平衡因子h,即子树高度,如果左子树高度和右子树高度相差2,那么就旋转把它弄平衡。
这个二叉树明显不平衡,可以发现全部左偏,于是右旋。
右旋就是当前节点的左儿子 的 右儿子是当前节点。
如果当前节点有右儿子,怎么办?
那么把这个右儿子拆下来然后装在当前节点的左儿子上。
如图:
这个二叉树明显不平衡,可以发现全部右偏,于是左旋。
左旋就是当前节点的右儿子 的 左儿子是当前节点。
如果当前节点有左儿子,怎么办?
那么把这个左儿子拆下来然后装在当前节点的右儿子上。
这个不给图了。
这个二叉树明显不平衡,下面右偏上面左偏,于是先左旋再右旋。
这个二叉树明显不平衡,下面左偏上面右偏,于是先右旋再左旋。
说白了就是全部反着来,是不是很好懂?
旋转完了,然后insert。
insert就是先插入进去,然后如果不平衡就旋转一下,就平衡了。
顺便更新h。
insert完了,然后find,predecessor,successor。
find,predecessor,successor就和二叉查找树一样。
明天讲讲delete。
附代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; struct node{ int h,v,lc,rc; }tree[40010]; int cnt,ans,n,val,pred,succ,rt; int abs(int x) { return x<0?-x:x; } int zig(int r) { int t=tree[r].lc; tree[r].lc=tree[t].rc; tree[t].rc=r; tree[r].h=max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1; tree[t].h=max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1; return t; } int zag(int r) { int t=tree[r].rc; tree[r].rc=tree[t].lc; tree[t].lc=r; tree[r].h=max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1; tree[t].h=max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1; return t; } int zigzag(int r) { tree[r].rc=zig(tree[r].rc); return zag(r); } int zagzig(int r) { tree[r].lc=zag(tree[r].lc); return zig(r); } int insert(int r,int x) { if(r==0) { tree[++cnt].v=x; tree[cnt].h=1; return cnt; } if(x<tree[r].v) { tree[r].lc=insert(tree[r].lc,x); if(tree[tree[r].lc].h==tree[tree[r].rc].h+2) { if(x<tree[tree[r].lc].v)r=zig(r); else if(x>tree[tree[r].lc].v)r=zagzig(r); } } else if(x>tree[r].v) { tree[r].rc=insert(tree[r].rc,x); if(tree[tree[r].rc].h==tree[tree[r].lc].h+2) { if(x>tree[tree[r].rc].v)r=zag(r); else if(x<tree[tree[r].rc].v)r=zigzag(r); } } tree[r].h=max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1; return r; } bool find(int r,int x) { if(r==0)return 0; if(tree[r].v==x)return 1; if(tree[r].v<x)return find(tree[r].rc,x); if(tree[r].v>x)return find(tree[r].lc,x); } void predecessor(int r,int x) { if(r==0)return; if(tree[r].v<x) { pred=tree[r].v; predecessor(tree[r].rc,x); } else predecessor(tree[r].lc,x); } void successor(int r,int x) { if(r==0)return; if(tree[r].v>x) { succ=tree[r].v; successor(tree[r].lc,x); } else successor(tree[r].rc,x); } int main() { scanf("%d%d",&n,&ans); rt=insert(rt,-99999999); rt=insert(rt,99999999); rt=insert(rt,ans); for(int i=1;i<n;++i) { scanf("%d",&val); if(find(rt,val))continue; pred=succ=0; predecessor(rt,val); successor(rt,val); ans+=min(abs(pred-val),abs(succ-val)); rt=insert(rt,val); } printf("%d\n",ans); }
这个题是BZOJ1588(HNOI2002)就是求前驱后继的裸题。
相关文章推荐
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构揭秘一
- 数据结构之Treap详解
- JavaScript数据结构和算法之图和图算法
- Java数据结构及算法实例:冒泡排序 Bubble Sort
- Java数据结构及算法实例:插入排序 Insertion Sort
- Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture
- java数据结构之java实现栈
- java数据结构之实现双向链表的示例
- Java数据结构及算法实例:选择排序 Selection Sort
- Java数据结构及算法实例:朴素字符匹配 Brute Force
- Java数据结构及算法实例:汉诺塔问题 Hanoi
- Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit Counting)
- java数据结构和算法学习之汉诺塔示例
- Java数据结构及算法实例:三角数字
- Java数据结构之简单链表的定义与实现方法示例
- 数据结构之AVL树详解
- qqwry.dat的数据结构图文解释第1/2页
- JavaScript中数据结构与算法(五):经典KMP算法