史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解

原文:http://baijiahao.baidu.com/s?id=1561409115312135&wfr=spider&for=pc

首先说也很重要的事情,此篇文章中关于旋转的问题,小编在写文章的时候查了很多资料,发现几乎没有资料可以参考,所有的文章都是一笔带过,小编认为这种行为很不负责,既然自己没有搞明白就不要发出来,耽误我们的时间,于是小编自己想了很久,给出了一个推理的过程(主要在旋转2.2 情形二中的情况),如果认为小编的有问题的小伙伴欢迎评论批评!!!!!!!!

此外呢,有个别图是down的其他人的博客的,因为自己画图实在太麻烦,但是小编还是画了几个,因为不画的话可能说不清楚。希望小伙伴们可以谅解,小编最近也很忙。

这些关系是为了后面集合中TreeMap的学习打下基础,讨论TressMap删除、插入的效率就是以红黑树为基础。而红黑树又是优化了的二叉查找树。

二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。

先来看一下基本的概念:

第一、二叉查找树(Binary Search Tree)和二叉排序树(Binary Sort Tree)都是一样的。

第二、二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;左、右子树也分别为二叉排序树;没有键值相等的节点(no duplicate nodes)。

因为一棵由n个结点随机构造的二叉查找树的高度为lgn,所以顺理成章,二叉查找树的一般操作的执行时间为O(lgn)。但二叉查找树若退化成了一棵具有n个结点的线性链后,则这些操作最坏情况运行时间为O(n)。

第三、平衡二叉树:AVL树是根据它的发明者G. M. Adelson-Velskii和E. M. Landis命名的。AVL树本质上还是一棵二叉搜索树,它的特点是:

本身首先是一棵二叉查找树。带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。

第四、红黑树:虽然本质上是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。

算法导论里是这样定义一棵红黑树的,

每个结点或是红色的,或是黑色的

根节点是黑色的每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。如果一个结点是红的,那么它的两个儿子都是黑的。对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

这里的NIL就是叶节点。有时候我们也称之为NULL节点,它只是指针而已。

或者说成:每个叶子结点都带有两个空的黑色结点(被称为黑哨兵),如果一个结点n的只有一个左孩子,那么n的右孩子是一个黑哨兵;如果结点n只有一个右孩子,那么n的左孩子是一个黑哨兵。

一句话总结就是:有红必有黑,但有黑未必有红。小编是依据红黑树这个名字来记的。既然是红黑,自然有红就一定有黑。

第五、树的旋转

网上有很多讲解树的旋转的知识点,在这里小编简单的总结归纳一下各个博客里讲的好的点以及自己的见解。

旋转的原因是:添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性。

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

在这里对X进行左旋,意味着”将x变成一个左节点”。

左旋的伪代码《算法导论》:参考上面的示意图和下面的伪代码,理解“红黑树T的节点x进行左旋”是如何进行的。

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

下面看一个实际的例子:

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

右旋转同理可得哈!

第六、树的插入

在讨论红黑树的插入操作之前必须要明白,任何一个即将插入的新结点的初始颜色都为红色。这一点很容易理解,因为插入黑点会增加某条路径上黑结点的数目,从而导致整棵树黑高度的不平衡。但如果新结点父结点为红色时(如下图所示),将会违返红黑树性质:一条路径上不能出现相邻的两个红色结点。这时就需要通过一系列操作来使红黑树保持平衡。

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

为了清楚地表示插入操作,以下在结点中使用“新”字表示一个新插入的结点;使用“父”字表示新插入点的父结点;使用“叔”字表示“父”结点的兄弟结点;使用“祖”字表示“父”结点的父结点。插入操作分为以下几种情况:

1、黑父

如果新点的父结点为黑色结点,那么插入一个红点将不会影响红黑树的平衡,此时插入操作完成。红黑树比AVL树优秀的地方之一在于黑父的情况比较常见,从而使红黑树需要旋转的几率相对AVL树来说会少一些。

2.红父

如果新点的父结点为红色,这时就需要进行一系列操作以保证整棵树红黑性质。如下图所示,由于父结点为红色,此时可以判定,祖父结点必定为黑色。这时需要根据叔父结点的颜色来决定做什么样的操作。青色结点表示颜色未知。由于有可能需要根结点到新点的路径上进行多次旋转操作,而每次进行不平衡判断的起始点(我们可将其视为新点)都不一样。所以我们在此使用一个蓝色箭头指向这个起始点,并称之为判定点。

2.1红叔

当叔父结点为红色时,如下图所示,无需进行旋转操作,只要将父和叔结点变为黑色,将祖父结点变为红色即可。但由于祖父结点的父结点有可能为红色,从而违反红黑树性质。此时必须将祖父结点作为新的判定点继续向上进行平衡操作。

需要注意,无论“父”在“叔”的左边还是右边,无论“新”是“父”的左孩子还是右孩子,它们的操作都完全一样。

2.2黑叔

当叔父结点为黑色时,需要进行旋转,以下图示了所有的旋转可能:

LL:插入一个新节点到根节点的左子树(Left)的左子树(Left)

情形1:

情形1是右旋,以“祖”结点为圆心,”父”结点右旋,结果如上图。

情形2:

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》
《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

左旋转根据伪代码《算法导论》推理,而第二步的右旋转跟第一步一样,就不做解释了,很简单。

情形3:

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

同理可得,这一步也是左旋转,根据《算法导论》伪代码中描述的那样,父的左孩子1是祖的右孩子。最后就是改变颜色。遵守root结点必须是黑结点的原则。

情形4:

《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》
《史上最通俗易懂的关于二叉查找树、平衡二叉树、红黑树的关系讲解》

可以观察到,当旋转完成后,新的旋转根全部为黑色,此时不需要再向上回溯进行平衡操作,插入操作完成。需要注意,上面四张图的“叔”、“1”、“2”、“3”结点有可能为黑哨兵结点。

其实红黑树的插入操作不是很难,甚至比AVL树的插入操作还更简单些。但删除操作就远远比AVL树复杂得多。这里就不给出删除操作了,想了解的小伙伴可以上网搜一下!

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/notOnlyRush/article/details/79997472
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞