看了这么多篇红黑树文章,你理解了嘛?

很早以前就想写一篇关于红黑树的文章,可是因为担忧本身理解的不透彻,就一直不敢下笔。因而在从新看了不少篇文章和资料以后,决定不折不扣的把红黑树搞清楚。也但愿让你在面试中游刃有余。OK,废话很少说,开始今天的文章。java

整篇文章的思路是这样的,红黑树其实就是一种数据结构,设计它的目的就是为了高效地进行增删改查,因此咱们文章的顺序也会按照这个思路来进行。咱们先从二叉查找树逐渐引入到红黑树,而后再详细的讲解。你若是看过其余文章想必也必定清楚,红黑树比较麻烦,但愿你有点耐心,认真理解每一张图再往下分析。linux

1、二叉查找树

在正式开始了解红黑树以前呢,咱们先来看一下二叉查找树的概念,从浅入深,但愿你不要着急,下面就是是一颗二叉查找树:面试

从这张图咱们会发现以下的规律:算法

(1)左子树上全部结点的值均小于或等于它的根结点的值。微信

(2)右子树上全部结点的值均大于或等于它的根结点的值。数据结构

若是咱们想要查找一个数字11,过程是怎么样的呢?app

上面的过程已经很清晰了,在查找的时候,先与根节点比较,比根节点大则从右子树查找,比根节点小则从左子树查找,而后重复上面的过程,一直到找到咱们须要的元素为止。spa

这个过程是查找操做,对于添加和删除呢?其实原理也是同样的,咱们第一步就是找到咱们须要插入的位置,而后把元素插入便可。这样看二叉查找树挺好的呀?别着急咱们继续往下看这种状况。.net

若是咱们在刚刚开始的时候仍是以9为根节点,而后依次插入1三、1五、1七、19。咱们看会发生什么状况:设计

好好地一棵树变成了这个鬼样子,成了“一边倒”了。这时候再去查找19呢?

这效率也过低下了吧,一颗二叉查找树的优点彻底丧失了。怎么办呢?既然上面的二叉查找树在插入的时候变成了“一条腿”,也就是丧失了平衡,那咱们干脆作出一点改进,使用平衡二叉树吧。

2、平衡二叉树

下面就是一颗平衡二叉树。

上面这颗二叉树就是平衡二叉树,也叫做AVL树。仔细分析你会发现以下特色:

(1)从任何一个节点出发,左右子树深度之差的绝对值不超过1。

(2)左右子树仍然为平衡二叉树。

如今咱们再往里插入一个元素4,这时候会发生什么呢?

从图中咱们能够看到,插入了4以后破坏了平衡,怎么办呢?既然破坏了平衡,那就想办法纠正过来。

咱们发现通过调整以后,咱们二叉树就从新回到了平衡。对于其余插入的状况,你们能够本身私下试一遍,最终你会发现一个结论,那就是平衡二叉树在插入时最多只须要两次旋转就会从新恢复平衡。

从上面这个过程咱们会发现,平衡二叉树真的很不错,在查找时既有着二叉查找树的优越性,在插入时还能经过调整继续保持着。那么为何还要使用到红黑树呢?我以为能够从如下两个方面来考虑:

(1)删除:对于平衡二叉树来讲,在最坏状况下,须要维护从被删节点到根节点这条路径上全部节点的平衡性,旋转的量级是O(logN)。可是红黑树就不同了,最多只需3次旋转就会从新平衡,旋转的量级是O(1)。

(2)保持平衡:平衡二叉树高度平衡,这也就意味着在大量插入和删除节点的场景下,平衡二叉树为了保持平衡须要调整的频率会更高。

注意:在大量查找的状况下,平衡二叉树的效率更高,也是首要选择。

在大量增删的状况下,红黑树是首选。

鉴于以上缘由,所以咱们才使用到了红黑树这种更好的结构。上面提了这么屡次红黑树,相信你已经火烧眉毛的想要认识一下了。下面就正式拉开红黑树的序幕。

3、红黑树

红黑树听名字就知道,里面涉及到两种颜色:红色和黑色。咱们直接来看一下:

上面这张图就是红黑树,你会发现他有以下特征(下面的特征最好看一个特征从新看一遍红黑树):

(1)每一个节点只有两种颜色:红色和黑色。

(2)根节点是黑色的。

(3)每一个叶子节点(NIL)都是黑色的空节点。

(4)从根节点到叶子节点,不会出现两个连续的红色节点。

(5)从任何一个节点出发,到叶子节点,这条路径上都有相同数目的黑色节点。

这五条就是红黑树的特征,你每看一个特征最好从新看一遍图,这样能够加深理解。这五条特征看起来真的很复杂,不过正是因为这些复杂的特征才保证了红黑树的良好特性。如何保证的呢?咱们从增删改查四个角度来一个一个分析一下:

一、查询节点

查询节点是最简单的一个,他的查找过程和二叉查找树同样,查找元素比当前节点大,就从右子树继续查找比较,查找元素比当前节点小,就从左子树继续查找比较。查找过程就再也不赘述了。

二、插入节点

插入节点是最麻烦的一个,它分为三种状况。咱们一种一种看,这样比较有条理性。

第一种状况:新节点没有父节点

没有父节点只有一种状况,就是插入的节点是整棵树第一个节点,也就是根节点,为此咱们只须要把插入节点涂成黑色就OK了。这也就保证了性质2:根节点是黑色的。

第二种状况:新节点的父节点是黑色

为此咱们举一个例子,好比说上面的红黑树中,咱们插入节点14。来看一下会发生什么状况?

这种状况咱们发现新插入节点14的父节点就是黑色的。如今为了保证红黑树的性质,咱们对照每一个特性来检查一遍。只要有一条不知足,咱们都须要调整。咱们从新对照以后会发现每一条都符合。此时不须要调整。

第三种状况:新节点的父亲节点为红色

咱们仍是举个例子,好比咱们在最开始的红黑树基础之上插入节点21,此时会发生什么状况呢?

此时仍是老规矩,对照着红黑树的5个特征一个一个来看,只要是违反了一条就须要作出调整。咱们来看一下:

(1)每一个节点只有两种颜色:红色和黑色。这一条知足。

(2)根节点是黑色的。这一条也知足。

(3)每一个叶子节点(NIL)都是黑色的空节点。这一条知足。

(4)从根节点到叶子节点,不会出现两个连续的红色节点。这一条发现不知足。

就是上面这一条规则没有知足,因此咱们此时须要调整?问题来了如何调整呢?由于直接看父节点没办法实现,因此还须要观察另外的节点,也就是新节点的叔叔节点。根据叔叔节点的颜色来调整。调整的方式有两种:变色和旋转。

(1)叔叔节点是红色:

此时插入的节点是21,可是叔叔节点是27,更好是红色。咱们直接来看调整的步骤:

第一步:把新节点21的父节点变成黑色。

此时从新看一下是否知足红黑树的五条特征了没,一条一条发现,第五条没有知足,也就是从任何一个节点出发,到叶子节点,这条路径上没有相同数目的黑色节点。好比从25出发。这时候怎么办呢?那就继续调整。

第二步:把22的父节点25变成红色

这时候仍是老规矩,不要嫌弃麻烦,由于只有经历了一步又一步的麻烦以后,你才能牢记那5条规则特征。咱们对照以后会发现节点25和节点27是两个连续的红色节点,这时候又破坏了规则4。怎么办呢?那就继续调整就OK了。

难道这时候还要继续往上调整吗?若是你这样作就错了,由于不断地往上调整最后就会把根节点变成了红色,会走进死胡同。咱们往下走。

第三步:把节点27变成黑色

来吧,继续从新审查那5条规则特征。很明显节点17和节点25是两个连续的红色,又破坏了。是否是心太累了,调整了这么久,仍是没有保证那5条规则,感受是否是尚未平衡二叉树好。若是你如今有这种感受,我只能说,但愿你继续坚持下去,胜利就在眼前。

第四步:把节点17和节点18都变成黑色节点


来来来,如今你再对照一下那5条规则,是否是彻底保证了。写到这真的是太累了,和你读这篇文章的感受同样同样的,不过这种状况也只是插入状况中的一种。继续往下看:

(1)叔叔节点是黑色:

这种状况下又分了两种状况:

第一种状况:新插入节点为父节点的左孩子


第二种状况:新插入节点为父节点的右孩子

按照第一遍的思路,咱们对这两种状况执行一样的操做,最终也能保证红黑树的5条特征。

到了这一步,插入操做的全部状况就讲解完毕。另外关于左旋和右旋的知识我在这里再也不说明了,由于你看到了红黑树这个程度,相信也必定看过平衡二叉树。左旋右旋哪几种状况,都会有介绍到。

三、删除节点

红黑树的删除说实话更加的复杂,若是你看过算法导论的话应该能明白一点,咱们在这里也进行一个大概的讲解。

删除大体分了三种状况,

(1)第一种状况:要删除的节点有零个子节点

这种状况下最简单,也就是删除的是根节点或者是叶子节点(这里的叶子节点都是指非NULL的叶子节点),根节点直接删除便可。若是叶子节点是红色的,也能够直接删除,若是叶子节点是黑色的,那么就须要进行调整,调整的步骤和插入时调整的步骤同样。

(2)第二种状况:要删除的节点有一个子节点

这时候。把子节点的值替换掉要删除的节点的值。

如今咱们的5把11替换掉以后,又回到了第一种状况。若是节点5是红色的,能够直接删除,若是节点5是黑色的,那么就须要进行调整,此时的节点5就是叶子节点。调整的步骤和插入时调整的步骤同样。

(3)第三种状况:要删除的节点有两个子节点

如今删除的节点有两个子节点,一样的咱们能够执行第二种状况的操做,

若节点13以前是叶子节点,那就和第一种状况同样了,若是节点13是红色的,能够直接删除,若是节点13是黑色的,那么就须要进行调整,此时的节点13就是叶子节点。调整的步骤和插入时调整的步骤同样。

若节点13以前还有子节点,那就和第二种状况同样了。那就继续替换和判断。

以上呢就是删除的状况,最后一种状况是修改,这种状况是查找和插入的结合体,也就是先找到要修改的元素,修改完值以后,继续进行调整便可。

如今还有最后一个问题了,都说红黑树很重要,为何重要呢?咱们来看一下使用场景。

4、使用场景

红黑树的应用真的是太多了,好比说java中的HashMap和TreeMap。还有就是linux也常用到。这种数据结构在面试的时候是一个常问问题,但愿你们可以明白和理解。如何用java手撕红黑树,在后续文章中我会添加。若有问题还请批评指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值