之前也没有系统的学过数据结构,但是平时用到的数组,链表等还是比较简单的,理解的时候即便没有接触过但是撸一撸源码,看一看画的图,基本上也就会了,树,二叉树,二叉搜索树,平衡二叉树,2-3树(完美平衡二叉树),红黑树。这次主要是在整理Java基本的数据类型Collection和Map子类的时候,发现要想吃透的话,还是绕不过这一块,更别提现在的hashMap和CurrentHashMap在容量大于8时,也抛弃了用链表转向红黑树的实现,这些种种都说明了树对于一个由码农进阶程序员的人来说有多重要。
树对于所有人来说,都是相当熟悉的,本码农以前是学建筑设计的,所以树对于我来说都不知道画了多少颗,树分为树根,树干,树枝,树叶,而对于程序员来说,就是用数字来连接的的一颗树,有根节点(树根),子节点(数干树枝交叉的地方),叶子节点(树叶)。其实这么看起来也很简单(刚开始学的时候也是这么想的),渐渐的接触到二叉树,其实就是一个根最多只有俩树干,每个树干最多只有俩树枝,每个树枝上只有俩树叶,其实学到这里我还是不太理解,树的作用在哪,完全没有规律可寻。我根本就不知道我要插一个数据往哪插,删除一个数据去哪找。我有个坏习惯,看一个东西总想知道为啥要这么写,而且不知道为啥有时候有点没法往下看(虽然我平时都跟女朋友说学习遇到不会的地方先放着,不要一根筋O(∩_∩)O),找遍了网上确实没看到怎么实现,没办法只能先往后看了。
接下来就到了二叉搜索树,这玩意其实很简单,就是在插入的时候如果树里面没有节点,那就是根节点,树里面有节点的话,就跟当前节点比,大的继续查找右子树,小的继续查找左子树,依次类推,直到没有子树,就找到这个节点应该放的位置了,然后放进去就可以了(具体的实现呢,网上有很多,大同小异,找个自己好理解的就可以了:https://blog.csdn.net/WeiJiFeng_/article/details/80227811)。
痛苦的日子开始了,平衡二叉树的学习,有点伤头发的。平衡二叉树,又称AVL树,据说是发明这个伤头发东西的三个科学家的首字母(第一次看到心里还小污了一把,结果发现是我心思不够纯洁,阿弥陀佛),书上给它的定义其实很简单:
1.它是一颗二叉排序树(左边儿子比爸爸小,右边儿子比爸爸大)
2.它的左右两个子树的高度差(平衡因子)的绝对值不超过1并且左右两个字树都是一颗平衡二叉树(其实就是从任意一个节点往下数,节点个数数量不能相差超过1个,ps:相差一个是允许的)
不知道大家有没有发现一个问题,平衡二叉树定义里面居然也写了平衡二叉树,这不是递归吗!!!(划重点了),定义写的真有内涵,这不用递归来实现都对不起AV大神们啊。来来来,再给大家推荐一个个人认为整理的还不错的文章:https://www.cnblogs.com/qm-article/p/9349681.html 这篇文章已经写的很棒了,回头复习可以再来看看,哈哈,我不是因为懒才用别人的。个人建议大家学的时候一定要先把出现需要旋转的场景摸透,其实是有规律可循的,比如说当插入数据在失衡节点的左字树的左边,那就直接用右旋就可以搞定了,而当插入节点在失衡节点的左子树的右边,那就先将左子树左旋(其实大家可以将这块理解为先把失衡节点左子树的右边给旋转到左边去),然后再将失衡节点右旋。还有两种其实也是一样的,具体可以看我推荐的那篇文章。
还有一个点就是刚开始学的时候,完全不知道失衡节点怎么找,其实就是这个节点他的左右字数相差大于1了,然后把他和他的子树可以当作一颗树来旋转,比如下面两颗树:左边插入28变成右边,这时候20这个节点变成了失衡节点(左边只有一个节点,右边最高有30-25-28 3个节点,3-1=2>1,所以失衡啦),那如果我加一个27,会加到28的左子节点,这时候30就变成了失衡节点,将30及下面的子树当成一棵树进行旋转就可以了(很明显27再30左子树25的右边,先将25进行右旋,再将30进行左旋,可以自己画图试试)
看起来确实是很复杂,我要是用链表,加一个数据怎么也不用你翻来覆去这么折腾啊,那为啥我们要这么玩呢? 俗话说天生我才必有用,我平头大树哥
这么辛苦,怎么可能没用呢,吃得苦中苦,方为人上人嘛。 平衡二叉树的查找效率很高,比如上面左边的树,这些数据放到链表,我很有可能要找6次才能找到,而在我平头大树哥的英明领导下,你查三次必然能查得到,这还只是6个数据,如果60个,600个甚至更多呢,那么效率自然是差距越来越大,怎么样我平头大树哥还是很厉害的吧。
聊完了平衡二叉树,是不是觉得这树确实有点极端,你要求那么严格,那么我每次插入数据也太麻烦了吧,所以,牛逼的大佬们就想到要不要换个要求没那么高,我每次插入至少不用转来转去那么多次的啊。红黑树这时候就出来了,红黑树有的人说是2-3树的简化版,听到2-3树的名字呢大家应该可以想到这个树他其实就是2节点和3节点都可以的树,2节点就是我们普通的一个爸爸,两个儿子,3节点就比较厉害了,两个爸爸,三个儿子,左爸爸比右爸爸小,三个儿子刚好在两个爸爸左边中间和右边,如果这个时候又来一个儿子争宠,俩爸爸没位置了,那就分家吧,一个爸爸带俩儿子,一层层往上分,说起来挺容易,但是一想,这玩意让我用代码写,一个头2-3个大,所以就演变成红黑树,说了那么多,其实主角还是红黑树,因为这玩意用的确实多,为啥大家都喜欢用红黑树呢?
其实要了解红黑树为啥这么受欢迎,还要从他的定义说起,红黑树有5个定义:
1、每个节点不是红色就是黑色。
2、根节点为黑色。
3、每个叶子节点都是黑色的。
4、每个红色节点的子节点都是黑色。
5、任意节点,到其任意叶节点的所有路径都包含相同的黑色节点。
我们逐个分析一下这5点,首先第一点是废话,我们可以不用理他,第二点其实也很好理解,第三点其实第一次看有点疑惑,如果我插入一个红色节点,那我怎么保证他就不是叶子节点呢,后来百度了一下才知道,叶子节点都是黑色空节点。。。好吧厉害,第四点其实就是说,俩红色节点不能相连,第五点其实保证了每两个节点相差不能超过两倍(包含也不行),因为每个分支红色节点是不能超过黑色节点的。其实直到看到第五点,我才稍稍有些释然,这不就是平衡二叉树的平民版嘛,要求没那么高,所以,旋转也没那么多,但是查找的效率可能比平衡二叉树要差一点,但是也还是阔以的。在献上红黑树的文章https://www.cnblogs.com/rainple/p/9983786.html,写的确实还可以。
写这篇文章其实是觉得,我之前在学习的时候,很多都是为了学而学,根本就想不到这些东西在被设计出来的初衷是为了什么,其实现在很多人都是这样,为了拿高工资,面试顺利,去硬啃一些平时用不到的知识,大部分时候我也是为了以后进大厂,拿高工资去学习,但是在平时工作中,这些应该是可以用到的,所以慢慢的会觉得,学了这么多,完全不能融会贯通,真的太鸡肋了,自己想去了解一些背景,了解优略,了解用途,而不只是知道啃。希望有梦想的人都能梦想成真,希望我可以进阿里!!!
原文地址:https://www.cnblogs.com/gmt-hao/p/11831648.html