有序表TreeMap/TreeSet底层实现:AVL树、傻逼树SBT、红黑树RBT、跳表SkipMap失衡类型
提示:这段时间,讲有序表、跳表的底层数据结构,平衡搜索二叉树:AVL树,SB树,红黑树
基础知识:
【1】求二叉树中节点x的后继节点和前驱结点
【2】二叉树,二叉树的归先序遍历,中序遍历,后序遍历,递归和非递归实现
【3】平衡搜索二叉树BST底层的增删改查原理,左旋右旋的目的
题目
学习了解有序表treeMap,treeSet底层实现:傻逼树SBT(Size Balanced Tree)陈启峰平衡搜索二叉树
这个SBT可能面试官不让你手撕代码,但是你想要在互联网大厂长期干,混得不错,还得好好学这个知识
你得学习傻逼树SBT,AVL树,红黑树RBT,跳表,
尤其是SBT和跳表,这是你必须会的,面试场上可能直接让你手撕跳表的代码!
尤其是SBT和跳表,这是你必须会的,面试场上可能直接让你手撕跳表的代码!
尤其是SBT和跳表,这是你必须会的,面试场上可能直接让你手撕跳表的代码!
系统有序表TreeMap,TreeSet是刷题经常用的数据结构
有序表TreeMap经常我们联合堆结构,在互联网大厂的笔试题第一题用,用来解决贪心算法类的题目。
当年我学过哈希表HashMap,它不能排序,乱序的,但是操作复杂度为o(1)
今天要学:有序表TreeMap,它是一个自动给你排序key的数据结构,操作复杂度是o(log(n))
咱们玩几个案例:
//系统有序表TreeMap,TreeSet是刷题经常用的数据结构
public static void test(){
TreeMap<Integer, Integer> treeMap = new TreeMap<>();
treeMap.put(5, 2);
treeMap.put(1, 2);
treeMap.put(3, 2);
treeMap.put(4, 2);
treeMap.put(2, 2);
//你会发现key是自动排序好的
for(Integer i:treeMap.keySet()) System.out.print(i +" ");
}
public static void main(String[] args) {
test();
}
1 2 3 4 5
添加或者更新操作:变key的value即可,put
得到key的value操作,get
treeMap.put(2, 3);
System.out.println(treeMap.get(2));
3
删除操作,删除key=2的
treeMap.remove(2);
for(Integer i:treeMap.keySet()) System.out.print(i +" ");
1 3 4 5
首个key,尾部key
System.out.println(treeMap.firstKey());
System.out.println(treeMap.lastKey());
1
5
查询>=key的最近那个键:ceilingKey
查询<=key的最近那个键:floorKey
目前有序表是1 3 4 5
System.out.println(treeMap.ceilingKey(2));
System.out.println(treeMap.floorKey(7));
3
5
查询key是否存在?
System.out.println(treeMap.containsKey(2));
false
再说一下TreeSet实际上和哈希集HashSet类似,是没有value的key集合,只不过TreeSet的key也是有序的
你可以看到,TreeMap实际上就是一个key自动排序【可比较的】接口,以o(log(n))复杂度玩各种类似于哈希表的操作
为啥这个有序表的复杂度是o(log(n))???
因为有序表TreeSet和TreeMap底层是一个平衡搜索二叉树BST(balanced search tree),自然操作复杂度就是o(log(n))
关于平衡搜索二叉树的基础知识,看下面文章:
【3】平衡搜索二叉树BST底层的增删改查原理,左旋右旋的目的
有序表底层的几种数据结构:AVL树,SBT傻逼树,红黑树RBT,跳表SkipMap
今天我们先简洁这些数据结构的基本原理,后续文章我们会详尽地讲解SBT和跳表,因为跳表是大厂面试可能会让你手撕代码的地方,而傻逼树SBT是极其经典的一种树,但凡参加ACM极限编程比赛的大佬们,都用SBT干题
AVL树:
AVL树的名字来源于它的发明作者G.M. Adelson-Velsky 和 E.M. Landis。
就像bfprt算法一样,它是根据五个发明这个算法的人的名字起的。
AVL树是最先发明的自平衡二叉搜索树(Self-Balancing Binary Search Tree,简称平衡二叉树)
它或者是一颗空树,
或者具有以下性质的二叉排序树:
它的左子树和右子树的深度之差(平衡因子)的绝对值不超过1(<=1),
且它的左子树和右子树,各自也都是一颗平衡搜索二叉树。
关于AVL树的根基知识,咱们前面讲过,如何判断一棵二叉树,是平衡搜索二叉树?你去学学。
求二叉树中,包含的最大二叉搜索子树的头节点是谁,它包含的节点数量是多少
SBT傻逼树:
傻逼树SBT是一个中国高中生发明的树
是针对AVL的缺陷做的改进,AVL树,但凡增删改查一个key,就非常容易扰动整个树,导致二叉树的平衡性被打破
你可能会经常要把AVL树拿过来想办法调平衡,麻烦死了……
作为高中生的陈启峰,在2006年在一个国际知名大赛中发明了节点大小平衡树(Size Balanced Tree,SBT),SBT如今在信息学领域广泛应用。
傻逼树SBT改进了AVL的平衡条件,不再是严格限制左右子的高度差<=1了
而是微微放宽了限制:让叔侄的节点数量势均力敌!
让x的兄弟节点【叔叔节点】,与x的左右子节点数量【叔叔的侄子节点】满足如下关系:
下图:
(1)叔叔b的节点数目>=任何以一个侄子的节点f/g数目
(2)叔叔c的节点数目>=任何以一个侄子的节点d/e数目
一旦违反(1)或(2)中任意一个条件,都不叫傻逼树SBT,需要调平衡。
但是总体来说,你增删改查,可能对二叉树的变动没那么大,扰动小,比AVL树调平操作的次数少多了,就没那么麻烦了,所以速度快一点,更好一些,因此SBT还挺经典的。
红黑树RBT:
红黑树的定义很特别,也复杂,这是所有二叉树中最复杂度的之一
必须满足下面几个条件才行:
(1)红黑树必须由红色或者黑色节点组成
(2)头结点和叶节点必须是黑节点
(3)红节点出现后,它的子必须是黑节点,黑节点的子可以是黑节点
(4)红黑红黑……这条最长的长链的长度N1必须=2×【2倍】黑黑黑黑……最短的短链长度N2
反正面试官是不可能考你红黑树的代码手撕的,否则它就是变态!
唯独华为牛逼的员工,要裁员时,谁能手撕红黑树,说明他真的很聪明,记忆力牛逼,他就不用被裁了!
你能吗?
……
恐怖
跳表SkipMap
今天不说跳表,后续有文章会说,跳表是最重要的!要现场手撕代码的!
AVL树,SBT傻逼树,红黑树RBT不平衡需要调平,涉及左右旋
当AVL树,SBT傻逼树,红黑树RBT不平衡时,就需要左旋和右旋:
之前咱们就说过左旋和右旋的骚操作!
【3】平衡搜索二叉树BST底层的增删改查原理,左旋右旋的目的
那么不平衡的原因,是因为左子的问题?还是右子的问题?
因为不同的问题,导致的失衡状况,所需调平的方案是不同的
拿AVL树举例吧!
AVL树的左边高h1和右边高h2,高度差dh=|h1-h2|>1的话就是失衡了!
那么你得追问:究竟是h1那边高了,还是h2那边高了呢?
【这个AVL树可以作为了解的知识点,后面咱们要重点学傻逼树的失衡原因】
四种情况:
(1)由于x.l.l过高导致的,那就是LL型,即左子的左树引发的
(2)由于x.l.r过高导致的,那就是LR型,即左子的右树引发的
(2)由于x.r.l过高导致的,那就是RL型,即右子的左树引发的
(2)由于x.r.r过高导致的,那就是RR型,即右子的右树引发的
【所有树的失衡,大致就这四类,看看哪个孙子引发的问题,就这么命名】
LL型失衡及调平方案
(1)由于x.l.l过高导致的,那就是LL型,即左子的左树引发的
调平方案很简单:让a右旋即可
上图a右旋,导致a的节点数量或者高度可能变化,b的数量是原来a的数量,b的左右高度可能变化。
RR型失衡及调平方案
(4)由于x.r.r过高导致的,那就是RR型,即右子的右树引发的
与(1)相反的,让a左旋即可,因为右子右树引发的问题
下图左边就能判断
调平方案:让a左旋
调平之后,a和b左右高度可能都发生变化
LR型失衡及调平方案
(2)由于x.l.r过高导致的,那就是LR型,即左子的右树引发的
看下图这种情况就是,左树高7,右树高5,超过1的差,显然左树引发的,而且是左子的右树引发的,LR型
和RL类型相似的调平方案(下面说),都需要完成一个目标:即让x的肇事者孙子节点来替代x的位置
那必然调平比LL和RR多一步:先让孙子C替左子,再让孙子C替自己
本题LR引发的
1)先让a左旋,让孙子C接替左子
1)再让x右旋,让孙子C接替自己
目标已达成
只让左子左旋还不够的,中间那个图,仍然不平衡
还得让孙子c来接替x,这样才平衡了,右图看看
c从孙子节点一步一步上来接替自己,就完成了调平
你会发现:a,x,c仨节点的高度,或者节点数都变化了
RL型失衡及调平方案
(3)由于x.r.l过高导致的,那就是RL型,即右子的左树引发的
下图右树高7,左树高5,差大于1,右子的左树高度6,引发的问题,故RL型
和LR类型相似的调平方案(上面说),都需要完成一个目标:即让x的肇事者孙子节点来替代x的位置
那必然调平比LL和RR多一步:先让孙子C替右子b,再让孙子C替自己
本题RL引发的
1)先让b右旋,让孙子C接替右子
1)再让x左旋,让孙子C接替自己
目标已达成
上图b先右旋,让c上去,得到中间图,然后x左旋,让c上来,得到最右图,完成调平
总结
提示:重要经验:
1)有序表TreeMap,TreeSet底层实现是AVL树、傻逼树SBT、红黑树RBT、跳表SkipMap;当所有这些树失衡了之后,就需要调平,调平的四种方案:LL,RR,LR,RL操作都不一样,但是问题不大
2)傻逼树SBT和跳表是最重要的,系统有序表的实现往往是跳表实现的,有序表的各种操作类似于哈希表,但是操作复杂度是o(log(n))
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。