二叉查找树(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++实现:

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实现

2.右单旋转(rotate right):

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

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

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的左儿子(上述过程完成右旋转)。

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

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

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

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

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

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

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

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

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

性质2. 根是黑色

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

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

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

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

插入:红黑树结点的插入与二叉查找树基本一样,不一样的是红黑树把新插入的结点标记为红色,如果新插入的结点的父节点也为红色,那么就按照下面三种情况,做出调整,以维护红黑树的性质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做一次右旋转。

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

删除:红黑树结点的删除与二叉查找树基本一样,不一样的是如果删除的结点是黑色,则破坏了红黑树的性质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做一次做旋转,调整到此完毕。

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

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

[转载]二叉树(BST,AVT,RBT)的更多相关文章

  1. 【转载】Morris遍历二叉树 & BST(二叉搜索树) Traverse & 空间O(1) 时间O(n)

    因为做一道Leetcode的题目(前面博客有:link),需要用Space O(1)空间复杂度来中序遍历树, 看了Discuss,也上网搜了一下,发现空间O(1)可以用 Morris遍历的方法.方法介 ...

  2. BST AVL RBT B- B+ 的一些理解

    BST(二叉查找树,排序二叉树),如果数据有序的话,组成的二叉树会形成单列的形式,导致查询效率低AVL(平衡二叉树) 使树的左右高度差的绝对值不超过2,保证了查询效率.但是插入和删除会带来多次旋转,导 ...

  3. 面试题21:如何判断二叉树是搜索二叉树BST?

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  4. C++二叉树的实现

    C++实现二叉查找树 啥是二叉查找树 在数据结构中,有一个奇葩的东西,说它奇葩,那是因为它重要,这就是树.而在树中,二叉树又是当中的贵族.二叉树的一个重要应用是它们在查找中的应用,于是就有了二叉查找树 ...

  5. C/C++二叉树搜索树操作集

    啥是二叉查找树 在数据结构中,有一个奇葩的东西,说它奇葩,那是因为它重要,这就是树.而在树中,二叉树又是当中的贵族.二叉树的一个重要应用是它们在查找中的应用,于是就有了二叉查找树. 使二叉树成为一颗二 ...

  6. 纯数据结构Java实现(4/11)(BST)

    个人感觉,BST(二叉查找树)应该是众多常见树的爸爸,而不是弟弟,尽管相比较而言,它比较简单. 二叉树基础 理论定义,代码定义,满,完全等定义 不同于线性结构,树结构用于存储的话,通常操作效率更高.就 ...

  7. 二叉查找树(Binary Sort Tree)(转)

    二叉查找树(Binary Sort Tree) 我们之前所学到的列表,栈等都是一种线性的数据结构,今天我们将学习计算机中经常用到的一种非线性的数据结构--树(Tree),由于其存储的所有元素之间具有明 ...

  8. 数据结构笔记--二叉查找树概述以及java代码实现

    一些概念: 二叉查找树的重要性质:对于树中的每一个节点X,它的左子树任一节点的值均小于X,右子树上任意节点的值均大于X. 二叉查找树是java的TreeSet和TreeMap类实现的基础. 由于树的递 ...

  9. Treap 实现名次树

    在主流STL版本中,set,map,都是BST实现的,具体来说是一种称为红黑树的动态平衡BST: 但是在竞赛中并不常用,因为红黑树过于复杂,他的插入 5 种,删除 6 中,代码量极大(如果你要改板子的 ...

随机推荐

  1. mybatis 使用tips - 使用多个参数

    执行如下命令: mvn -Dmybatis.generator.overwrite=true mybatis-generator:generate 可以使用mybatis generator myba ...

  2. Eclipse中Tomcat Server启动后马上又自动停止报错Address已经使用8005端口 Can't assign requested address (Bind failed)

    Eclipse中Tomcat Server启动后马上又自动停止报错 Can't assign requested address (Bind failed) ,打开Tomcat Server的配置页面 ...

  3. mysql设定或修改密码的三个方法

    为用户设定密码: 1.mysql>SET PASSWORD FOR 'USERNAME'@'HOST'=PASSWORD('password'); 2.# mysqladmin -uUSERNA ...

  4. WebLogic 两处任意文件上传漏洞动态分析(CVE-2018-2894)

    0x01 前言 CNCERT前几天发公告称发现Oracle公司出品的基于JavaEE结构的中间件WebLogic产品存在一个远程上传漏洞,并得到了厂商的确认,危害程度评分高达9.8分.鉴于厂商已进行了 ...

  5. driver.get()和driver.navigate().to()到底有什么不同?-----Selenium快速入门(四)

    大家都知道,这两个方法都是跳转到指定的url地址,那么这两个方法有什么不同呢?遇到这种情况,第一反应就是查查官方的文档. 官方文档的说法是:Load a new web page in the cur ...

  6. C#中字段、属性、只读、构造函数赋值、反射赋值的相关

    C#中字段.属性和构造函数赋值的问题 提出问题 首先提出几个问题: 1.如何实现自己的注入框架? 2.字段和自动属性的区别是什么? 3.字段和自动属性声明时的直接赋值和构造函数赋值有什么区别? 4.为 ...

  7. Http协议中关于Content-Length的解读【出现坑爹的视频中断】

    最近公司的视频设备在下载视频的时候,出现了很诡异的现象,在新旧服务器一样的tpp包,下载下来后,新服务器无法解析,旧服务器没问题.且tpp包并没有改动. 后面找了挺久,终于发现了视频下载的时候是断点续 ...

  8. Echart自定义属性3

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. [bzoj4009] [HNOI2015]接水果 整体二分+扫描线+dfs序+树状数组

    Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更 加 ...

  10. 【bzoj 2716】[Violet 3]天使玩偶 (CDQ+树状数组)

    题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它. 我们把 Ayu 生活的 ...