[转载]二叉树(BST,AVT,RBT)

news/2024/7/3 4:45:14

二叉查找树(Binary Search Tree)是满足如下性质的二叉树:①若它的左子树非空,则左子树上所有结点的值均小于根结点的值;②若它的右子树非空,则右子树上所有结点的值均大于根结点的值;③左、右子树本身又各是一棵二叉查找树。

通俗的讲,二叉查找树的左子树上的结点不比父结点大,右子树上的结点不比父结点小,即,设x为二叉查找树中的一个结点,如果y是x的左子树中的一个结点,则key[y]<=key[x];如果y是x的右子树中的一个结点,则key[x]<=key[y]。此处的key[x],key[y]表示的是x结点和y结点的关键字。

1.最小关键字元素:要查找二叉查找树中具有最小关键字的元素,只要从根节点开始,沿着各节点的left指针查找下去,直到遇到NULL为止。查找最大关键字元素情况类似。

TREE-MINIMUM (x)

1 while left[x] ≠ NULL

2   do x ← left[x]

3 return x

2.后继:如果所有的关键字均不相同,则某一结点x的后继即是具有大于key[X]中的关键字中最小者的那个结点。查找结点X的后继包含两种情况(1)如果结点X的右子树非空,结点X的后继即是右子树中具有最小关键字的结点。(2)如果结点x的右子树为空,且假设结点X的后继为Y,则Y是X的最低祖先结点,且Y的左孩子是X的祖先。前驱的情况类似。

TREE-SUCCESSOR(x)

1 if right[x] ≠ NULL

2   then return TREE-MINIMUM (right[x])

3 yp[x]

4 while y ≠ NULL and x = right[y]

5   do xy

6   yp[y]

7 return y

下面是后继的C++实现:

二叉树之BST、AVL和RBT

3.插入:根据二叉查找树的性质,我们先将要插入的元素跟根元素,如果大于根结点的key,则插入到其右子树中,如果小于根结点的key值,则插入到其左子树中。

4.删除:将给定结点Z从二叉查找树中删除的过程是以指向Z的指针作为参数。删除步骤分为三种:

(1)如果Z没有子女,则修改其父节点P[Z],使NULL为其子女,替换Z。

(2)如果结点只有一个孩子,则通过在其子节点与父节点之间建立一条链来删除Z。

(3)最后若Z有两个子女,先删除Z的后继Y(后继Y没有左孩子,注意这时真正删除的是结点Y),再用Y的内容替换Z的内容。

TREE-DELETE(T, z)

1 if left[z] = NULL or right[z] = NULL

2   then yz

3 else y ← TREE-SUCCESSOR(z)

4 if left[y] ≠ NULL

5   then xleft[y]

6 else xright[y]

7 if x ≠ NULL

8   then p[x] ← p[y]

9 if p[y] = NULL

10   then root[T] ← x

11 else if y = left[p[y]]

12   then left[p[y]] ← x

13 else right[p[y]] ← x

14 if yz

15   then key[z] ← key[y]

16   copy y's satellite data into z

17 return y

=======================================  AVL树 ========================================

一棵AVL树是一棵平衡树,除了二叉查找树的性质外,还有这个性质:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1。这个性质保证了N个元素的AVL树的高度总为LogN,所以它查找的最坏复杂度仍然是LogN,所以说它是一种严格平衡的二叉查找树。

下面是一个Flash做的动态模拟AVL树上结点的插入与删除的过程,非常有趣,对了解AVL树也非常有用:http://www.qmatica.com/DataStructures/Trees/AVL/AVLTree.swf

如果在一棵原本是平衡的AVL树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。平衡化旋转有两类:单旋转(左旋和右旋)和双旋转(左平衡和右平衡)。下面先依次介绍旋转的方法。

1.左单旋转(rotate left):

适用情况:见下图。在A的右孩子B的右子树C上插入结点,使得A结点的平衡因子从﹣1变成﹣2,需要对A进行一次左单旋转。(其中A平衡因子为left[A]->height - right[A]->height)

方法:以A的右孩子结点B为轴,节点A逆时针旋转,成为节点B的左儿子,节点B原左子树成为节点A的右子树。下面是左旋转的cpp实现

二叉树之BST、AVL和RBT

2.右单旋转(rotate right):

适用情况:在C的左孩子B的左子树A上插入结点,使得C结点的平衡因子从1变成2,需要对C进行一次右单旋转。

方法:以C的左孩子结点B为轴,节点C顺时针旋转,成为节点B的右儿子,节点B原右子树成为节点C的左子树

二叉树之BST、AVL和RBT

 

3. 先左后右双旋转(rotation left right

适用情况:见下图。在C的左孩子A的右子树B上插入结点,使得C结点的平衡因子从1变成2,需要对C进行先左后右双旋转。

方法:以C的左孩子A的右孩子B为轴,将节点A逆时针旋转,成为节点B的左儿子,现在C的左孩子为B(上述过程完成左旋转);以C的左孩子B为轴,将节点C顺时针旋转,成为节点B的右儿子(上述过程完成右旋转)。

4. 先右后左双旋转(rotation right left

适用情况:在A的右孩子C的左子树上B插入结点,使得A结点的平衡因子从-1变成-2,需要对A进行先右后左双旋转。

方法:以A的右孩子C的左孩子B为轴,将节点C顺时针旋转,成为节点B的右儿子,现在A的右孩子为B(上述过程完成左旋转);以A的右孩子B为轴,将节点A逆时针旋转,成为节点B的左儿子(上述过程完成右旋转)。

二叉树之BST、AVL和RBT

AVL树的插入操作与BST相同,插入后从插入结点到根节点从下到上依次检查该路径上各个结点的平衡度,按照四种情况,做出对应的旋转。

AVL树的删除操作:首先定位要删除的节点。

(1)如果该节点有左孩子,则用左子树的最大结点替换替换该节点,替换后递归删除左子树的最大结点;

(2)如果该节点没有左孩子有右孩子,则用右子树的最小结点替换替换该节点,替换后递归删除右子树的最小结点;

(3)如果该节点没有孩子,则删除该结点。

删除后从删除结点到根节点从下到上依次调整高度,该旋转的旋转。

======================================= 红黑树 ========================================

红黑树的定义也是它的性质,有以下五条:

性质1. 节点是红色或黑色

性质2. 根是黑色

性质3. 所有叶子都是黑色(叶子是NULL节点)

性质4. 如果一个节点是红的,则它的两个儿子都是黑的

性质5. 从任一节点到其叶子的所有简单路径都包含相同数目的黑色节点。

另外为了便于处理红黑树代码的边界条件,我们常常采用一个哨兵来代表NULL。哨兵是一个与树内普通结点具有相同域的对象。所有指向NULL的指针都替换成指向哨兵的指针。

二叉树之BST、AVL和RBT

插入:红黑树结点的插入与二叉查找树基本一样,不一样的是红黑树把新插入的结点标记为红色,如果新插入的结点的父节点也为红色,那么就按照下面三种情况,做出调整,以维护红黑树的性质4或是2。新插入的结点为N,N的叔叔结点为U。实际情况应该有六种,下面的三种情况中P都是G的左孩子,当P是G的右孩子时,处理方法类似,旋转的方向相反。

(1)N的叔叔U为红色:将N的父节点P[N]与U标记为黑色,将P[P[Z]]标记为红色,然后把P[P[Z]]当做新插入的结点,往上循环调整。

(2) N的叔叔U是黑色的,而且N是右孩子:将P[N]做一次左旋,使P[N]成为N的左孩子,并将旋转前的P[N]作为新插入的结点N。这样情况(2)就转化成了情况(3)。

(3) N的叔叔U是黑色的,而且N是左孩子:改变P与G的颜色,对G做一次右旋转。

二叉树之BST、AVL和RBT

下面是红黑树插入操作的C++实现(截图部分只有上面三种情况):

二叉树之BST、AVL和RBT

删除:红黑树结点的删除与二叉查找树基本一样,不一样的是如果删除的结点是黑色,则破坏了红黑树的性质5,需要调整,如果删除的结点是红色,那么就不需要调整。现在假设删除结点的孩子为N,如果N是红色的,那么直接将N调整成黑色就能维持红黑树的性质。否则的话,按下面的四种情况处理。实际情况应该有八种,下面的四种情况中N都是其父节点P的左孩子,当N是P的右孩子时,处理方法类似,旋转的方向相反。

(1)N的兄弟S是红色:改变P和S的颜色,对P进行一次左旋转,这样情况(1)就转换成了情况(2)、(3)、(4);

(2)N的兄弟S是黑色,而且S的两个孩子都是黑色:将S改成红色,将P为新的X循环处理;

(3) N的兄弟S是黑色,而且S的左孩子SL是红色,S的右孩子SR是黑色:改变SL与S的颜色,并对S进行一次右旋转,这样情况(3)就转化成了情况(4)

(4) N的兄弟S是黑色,而且S的右孩子SR是红色:改变P和S的颜色,并对P做一次做旋转,调整到此完毕。

二叉树之BST、AVL和RBT

红黑树删除结点操作的C++实现:

二叉树之BST、AVL和RBT

c++完整实现:

二叉查找树:http://www.oschina.net/code/snippet_176897_14148

AVL树:http://www.oschina.net/code/snippet_176897_14149

红黑树:http://www.oschina.net/code/snippet_176897_14155

转载于:https://www.cnblogs.com/wxquare/p/5211568.html


http://lihuaxi.xjx100.cn/news/269281.html

相关文章

一文读懂:GoogleNet的Inception从v1到v4的演变

来源 | 机器学习炼丹术GoogleNet和VGG是ImageNet挑战赛中的第一名和第二名。共同特点就是两个网络的层次都更深了。但是&#xff1a;VGG继承了LeNet和AlexNet的一些框架结构而GoogleNet则做了更大胆的尝试&#xff0c;虽然深度有22层&#xff0c;但是参数却是Alexnet的1/12.而V…

初学者必学的C++项目!花3天搞定

学C应该都知道Google测试框架&#xff0c;它是一个非常重要的测试软件&#xff0c;一直广泛应用于C/C项目测试。重点是&#xff0c;它的设计过程几乎覆盖C项目开发中常遇到的问题。所以Google测试框架常常被当作初学者训练工程代码、巩固基础语法最合适的项目。如果你对自己做没…

禁用编译优化_Tomcat8史上最全优化实践

Tomcat8优化1、Tomcat8优化1.1、Tomcat配置优化1.1.1、部署安装tomcat81.1.2 禁用AJP连接1.1.3、执行器&#xff08;线程池&#xff09;1.1.4 3种运行模式1.3、使用Apache JMeter进行测试1.3.1、下载安装1.3.2、修改主题和语言1.3.3、创建首页的测试用例1.3.4、启动、进行测试1…

Git简介

Git简介 Git 是目前世界上最先进的分布式版本控制系统&#xff08;没有之一&#xff09; 作用 源代码管理 为什么要进行源代码管理? 方便多人协同开发方便版本控制 Git的诞生 作者是 Linux 之父&#xff1a;Linus Benedict Torvalds当初开发 Git 仅仅是为了辅助 Linux 内核…

一个故事讲完 CPU 的工作原理

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶”重磅干货&#xff0c;第一时间送达来自 | 知乎 作者 | 柳两丛 www.zhihu.com/question/40571490/answer/718942643上二年级的小明正坐在教室里。现在是数学课&#xff0c;下午第一节&#xff0c;窗外的蝉…

jQuery实例——仿京东仿淘宝列表导航菜单

以前看着京东&#xff0c;淘宝的导航做的真好&#xff0c;真想哪一天自己也能做出来这么漂亮功能全的导航菜单。今天弄了一下午终于自制成功&#xff0c;主要使用jQuery和CSS&#xff0c;实现功能基本和京东一样。 功能介绍&#xff1a; 1、鼠标停留导航&#xff1b; 2、根据子…

实战:人脸识别实战项目(源码共享)

首先我想问个问题&#xff1a;现在什么工程师最值钱&#xff1f;毫无疑问&#xff0c;我想超 90% 的都会说&#xff1a;人工智能工程师。也难怪&#xff0c;随着近几年人工智能的发展&#xff0c;已经逐渐渗透到了各个领域&#xff0c;比如&#xff1a;医疗、教育、机械自动化、…

工作流入门链接

百度百科-工作流 http://baike.baidu.com/link?urlZjElBNByyZz_ItLtd_Uqt3Sadcwv0-4CDO806vKQWJDuUOFybbkzpg8GOB1EU71w8bT4x64RoRXBrFXa7o_dK 企业应用工作流的好处http://jingyan.baidu.com/article/90895e0fe9c56164ec6b0b24.html工作流管理的好处http://blog.sina.com.cn/…