二叉查找树(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. struts2+ckeditor配置图片上传

    又是一个漫漫长夜. 公司的编辑器坏了,用的是百度编辑器,上传图片的网址被框架给拦截了,我们本地怎么测试都没问题,放到服务器就这样了.和老李找了半天,疯了,没原因的. 笔者以前用过jsp+ckedito ...

  2. 在TFS 2013的迭代视图中修改工作项数目限制

    当TFS迭代中的工作项数目超过500时,在TFS的网页(Web Access)显示中就会出现红色警告提示"积压工作(backlog)中的项数超出配置的限制500.当前总数为529-.&quo ...

  3. 对SIP摘要认证方案的理解

    一.口令认证常见机制 基于口令认证的系统一般有以下几种口令验证方式: 1.客户端以明文形式将用户名密码通过网络发送到服务器,服务器与已经保存在服务端的用户名密码进行比较,一致则通过验证: HTTP基本 ...

  4. Lambda 表达式浅谈- 01

    已经有一段时间没有发布博文了... 今天就写一写lambda的一些简单的使用方法 Lambda 在Msdn 上的描述: Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 ...

  5. indows 2008 r2/做了SPS2007---2013后,发现添加原来域中的域组添加不上

    根据上次的网络包的分析, 我们在AD中找到了wtc-beijing-it的组, 不过在SharePoint日志中我们没有发现搜索成功的记录. - SearchResultEntry: CN=WTC-B ...

  6. Schema validation found non-datatype errors

    Private Sub UpdateClaim(ByVal Status As String, ByVal Request As String) '======================' Im ...

  7. html开发基础

    1 Doctype Doctype告诉浏览器使用什么样的html或xhtml规范来解析html文档 有和无的区别 BackCompat:标准兼容模式未开启(或叫怪异模式[Quirks mode].混杂 ...

  8. 关于Tomcat控制台乱码解决办法___ 解决 IntelliJ IDEA Tomcat 控制台中文输出乱码问题

    Tomcat 控制台UTF-8乱码问题 1.修改cmd的编码格式 快捷键win+R打开运行程序,输入regedit打开注册表,找到以下路劲并且修改. [HKEY_LOCAL_MACHINE\SOFTW ...

  9. springmvc 通过@ResponseBody 返回json的中文乱码解决方案2个

    1.方法上面的RequestMapping要加上红色的部分.   @ResponseBody     @RequestMapping(value = "/search", prod ...

  10. 洛谷P3676 小清新数据结构题(动态点分治+树链剖分)

    传送门 感觉这题做下来心态有点崩……$RMQ$求$LCA$没有树剖快我可以理解为是常数太大……然而我明明用了自以为不会退化的点分然而为什么比会退化的点分跑得反而更慢啊啊啊啊~~~ 先膜一波zsy大佬 ...