BST、AVL、B-TREE、B+TREE、红黑树

BST 二叉搜索树(左子树值<=根值<=右子树)

1.1 定义
1 首先它也是一个二叉树,故满足递归定义;

2 其次每个节点只存在一个值;

3 需满足左子树值<=根值<=右子树,BST的中序遍历必定是严格递增的

 

 

在实际场景中,用的最多的是二叉平衡树,

一般操作的执行时间福再度为O(lgn)。2.但若是一棵具有n个结点的线性链,则此些操作最坏情况运行时间为O(n)。

1.2   BST的搜索
       从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字;

二叉树在搜索上的优势(和数组)

       数组的搜索比较方便,可以直接使用下标,数组如果不用二分查找,时间复杂度O(n),但删除或者插入就比较麻烦了,而链表与之相反,删除和插入都比较简单,但是查找很慢,这自然也与这两种数据结构的存储方式有关,数组是取一段相连的空间,而链表是每创建一个节点便取一个节点所需的空间,只是使用指针进行连接,空间上并不是连续的。而二叉树就既有链表的好处,又有数组的优点。

BST和二分查找

如果二叉查找树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么二叉查找树的搜索性能逼近二分查找O(logN),但它比连续内存空间的二分查找的优点是,改变二叉查找树结构(插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销;连续内存空间(数组)

1.3   插入删除
BST涉及操作主要增,删,查,除了删麻烦一点,其他操作均可递归实现

AVL平衡二叉搜索树


定义:平衡二叉树或为空树,或为如下性质的二叉排序树:

  (1)左右子树深度之差的绝对值不超过1;

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

B-树(B树、平衡多路)

B-tree是一种平衡多路搜索树(并不一定是二叉的)B-tree树即B树,如人们可能会以为B-树是一种树,是不对的

B树,一般用于外存储索引结构。系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的。二叉树、红黑树 [复杂度O(h)]导致树高度非常高(平衡二叉树一个节点只能有左子树和右子树),逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,IO次数多查找慢,效率低。

特点:

(1)根节点的左子树和右子树的深度最多相差1.(确保了不会出现上图右边的极端现象)

(2)是一个平衡多路搜索树,单个节点能放多个子节点

(3)所有结点都有存储关键字(数据);

(4)不太稳定,可能走不到叶子节点

3.1   搜索过程
B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点。

搜索性能等价于在关键字全集内做一次二分查找;

3.2   应用
       在数据索引上,系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。每个磁盘块作为一个节点

 

 

每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】
比较关键字29在区间(17,35),找到磁盘块1的指针P2。
根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】
比较关键字29在区间(26,30),找到磁盘块3的指针P2。
根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】
在磁盘块8中的关键字列表中找到关键字29。
分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

B树的大部分操作所需的磁盘存取次数和B树的高度成正比

B+TREE

B+树是B-树的变体,也是一种平衡多路搜索树,非叶子节点只做索引,所有数据都保存在叶子节点中。

和B树区别

1:根节点和分支节点中不保存数据,只用于索引  。数据和索引分离

2:所有数据都保存在叶子节点中

B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;

B+Tree内节点去掉了data域,只做索引,减少了io次数,因此可以拥有更大的出度,拥有更好的性能。只利用索引快速定位数据索引范围,先定位索引再通过索引高效快速定位数据。

红黑树

5.1   什么是红黑树,六大特征
本质上是一个平衡搜索二叉树,和Btree不一样,可以说是AVL树的变种,牺牲了一定查询效率,减少了维护平衡的时间。log(n) 中序排序都能得到递增序列。

1)每个结点要么是红的,要么是黑的。(没有其他颜色)

2)根结点是黑的。

3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。(叶子节点即为树尾端的NIL指针,或者说NULL节点。)

4)如果一个结点是红的,那么它的俩个儿子都是黑的。(父子节点不能是红色的)

5)对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。(最长路径是最小路径的2倍)

6)最多三次旋转,可以达到平衡

5.2   删除新增怎么达到平衡
旋转:通过左旋 右旋 变化颜色来达到平衡。

答:一切的操作都是为了保持那红黑树五条性质。,现在推导不出来,需要一定时间

5.3   红黑树相比于BST和AVL树有什么优点? 
        红黑树是牺牲了严格的高度平衡的优越条件为代价,它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。红黑树能够以O(log2 n)的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,还有一些更好的,但实现起来更复杂的数据结构能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。

       相比于BST,因为红黑树可以能确保树的最长路径不大于两倍的最短路径的长度,所以可以看出它的查找效果是有最低保证的。在最坏的情况下也可以保证O(logN)的,这是要好于二叉查找树的。因为二叉查找树最坏情况可以让查找达到O(N)。红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高,所以在插入和删除中所做的后期维护操作肯定会比红黑树要耗时好多

     但是他们的查找效率都是O(logN),所以红黑树应用还是高于AVL树的. 实际上插入 AVL 树和红黑树的速度取决于你所插入的数据.如果你的数据分布较好,则比较宜于采用 AVL树(例如随机产生系列数),但是如果你想处理比较杂乱的情况,则红黑树是比较快的。
---------------------
作者:千丈之松
来源:CSDN
原文:https://blog.csdn.net/hu948162999/article/details/81407950

背景:这几天在看《高性能Mysql》,在看到创建高性能的索引,书上说mysql的存储引擎InnoDB采用的索引类型是B+Tree,那么,大家有没有产生这样一个疑问,对于数据索引,为什么要使用B+Tree这种数据结构,和其它树相比,它能体现的优点在哪里? 看完这篇文章你就会了解到这些数据结构的原理以及它们各自的应用场景.

Part Two

二叉查找树

简介

二叉查找树也称为有序二叉查找树,满足二叉查找树的一般性质,是指一棵空树具有如下性质:

  • 任意节点左子树不为空,则左子树的值均小于根节点的值.
  • 任意节点右子树不为空,则右子树的值均大于于根节点的值.
  • 任意节点的左右子树也分别是二叉查找树.
  • 没有键值相等的节点.

局限性及应用

一个二叉查找树是由n个节点随机构成,所以,对于某些情况,二叉查找树会退化成一个有n个节点的线性链.如下图: 
这里写图片描述 
b图为一个普通的二叉查找树,大家看a图,如果我们的根节点选择是最小或者最大的数,那么二叉查找树就完全退化成了线性结构,因此,在二叉查找树的基础上,又出现了AVL树,红黑树,它们两个都是基于二叉查找树,只是在二叉查找树的基础上又对其做了限制.

AVL树

简介

AVL树是带有平衡条件的二叉查找树,一般是用平衡因子差值判断是否平衡并通过旋转来实现平衡,左右子树树高不超过1,和红黑树相比,它是严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1).不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的,由此我们可以知道AVL树适合用于插入删除次数比较少,但查找多的情况。 
这里写图片描述 
从上面这张图我们可以看出,任意节点的左右子树的平衡因子差值都不会大于1.

局限性

由于维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多,更多的地方是用追求局部而不是非常严格整体平衡的红黑树.当然,如果应用场景中对插入删除不频繁,只是对查找要求较高,那么AVL还是较优于红黑树.

应用

Windows NT内核中广泛存在.

红黑树

简介

一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是red或black. 通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍.它是一种弱平衡二叉树(由于是若平衡,可以推出,相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,它的旋转次数变少,所以对于搜索,插入,删除操作多的情况下,我们就用红黑树.

性质

  • 每个节点非红即黑.
  • 根节点是黑的。
  • 每个叶节点(叶节点即树尾端NUL指针或NULL节点)都是黑的.
  • 如果一个节点是红的,那么它的两儿子都是黑的.
  • 对于任意节点而言,其到叶子点树NIL指针的每条路径都包含相同数目的黑节点. 
    这里写图片描述 
    每条路径都包含相同的黑节点.

应用

  • 广泛用于C++的STL中,map和set都是用红黑树实现的.
  • 著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块,进程的虚拟内存区域都存储在一颗红黑树上,每个虚拟地址区域都对应红黑树的一个节点,左指针指向相邻的地址虚拟存储区域,右指针指向相邻的高地址虚拟地址空间.
  • IO多路复用epoll的实现采用红黑树组织管理sockfd,以支持快速的增删改查.
  • ngnix中,用红黑树管理timer,因为红黑树是有序的,可以很快的得到距离当前最小的定时器.
  • java中TreeMap的实现.

B/B+树

注意B-树就是B树,-只是一个符号.

简介

B/B+树是为了磁盘或其它存储设备而设计的一种平衡多路查找树(相对于二叉,B树每个内节点有多个分支),与红黑树相比,在相同的的节点的情况下,一颗B/B+树的高度远远小于红黑树的高度(在下面B/B+树的性能分析中会提到).B/B+树上操作的时间通常由存取磁盘的时间和CPU计算时间这两部分构成,而CPU的速度非常快,所以B树的操作效率取决于访问磁盘的次数,关键字总数相同的情况下B树的高度越小,磁盘I/O所花的时间越少.

B树的性质

  • 定义任意非叶子结点最多只有M个儿子;且M>2;
  • 根结点的儿子数为[2, M];
  • 除根结点以外的非叶子结点的儿子数为[M/2, M];
  • 每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
  • 非叶子结点的关键字个数=指向儿子的指针个数-1;
  • 非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
  • 非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
  • 所有叶子结点位于同一层; 
    这里写图片描述
    这里只是一个简单的B树,在实际中B树节点中关键字很多的.上面的图中比如35节点,35代表一个key(索引),而小黑块代表的是这个key所指向的内容在内存中实际的存储位置.是一个指针.

B+树

B+树是应文件系统所需而产生的一种B树的变形树(文件的目录一级一级索引,只有最底层的叶子节点(文件)保存数据.),非叶子节点只保存索引,不保存实际的数据,数据都保存在叶子节点中.这不就是文件系统文件的查找吗?我们就举个文件查找的例子:有3个文件夹,a,b,c, a包含b,b包含c,一个文件yang.c, a,b,c就是索引(存储在非叶子节点), a,b,c只是要找到的yang.c的key,而实际的数据yang.c存储在叶子节点上. 
所有的非叶子节点都可以看成索引部分

B+树的性质(下面提到的都是和B树不相同的性质)

  • 非叶子节点的子树指针与关键字个数相同;
  • 非叶子节点的子树指针p[i],指向关键字值属于[k[i],k[i+1]]的子树.(B树是开区间,也就是说B树不允许关键字重复,B+树允许重复);
  • 为所有叶子节点增加一个链指针.
  • 所有关键字都在叶子节点出现(稠密索引). (且链表中的关键字恰好是有序的);
  • 非叶子节点相当于是叶子节点的索引(稀疏索引),叶子节点相当于是存储(关键字)数据的数据层.
  • 更适合于文件系统; 
    看下图: 
    这里写图片描述
    非叶子节点(比如5,28,65)只是一个key(索引),实际的数据存在叶子节点上(5,8,9)才是真正的数据或指向真实数据的指针.

应用  

B和B+树主要用在文件系统以及数据库做索引.比如Mysql;

B/B+树性能分析 

  • n个节点的平衡二叉树的高度为H(即logn),而n个节点的B/B+树的高度为logt((n+1)/2)+1;   
  • 若要作为内存中的查找表,B树却不一定比平衡二叉树好,尤其当m较大时更是如此.因为查找操作CPU的时间在B-树上是O(mlogtn)=O(lgn(m/lgt)),而m/lgt>1;所以m较大时O(mlogtn)比平衡二叉树的操作时间大得多. 因此在内存中使用B树必须取较小的m.(通常取最小值m=3,此时B-树中每个内部结点可以有2或3个孩子,这种3阶的B-树称为2-3树)。

为什么说B+tree比B树更适合实际应用中操作系统的文件索引和数据索引.  

      • B+-tree的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了.
      • 由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。 
        ps:我在知乎上看到有人是这样说的,我感觉说的也挺有道理的: 
        他们认为数据库索引采用B+树的主要原因是:B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生.B+树只需要去遍历叶子节点就可以实现整棵树的遍历.而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作(或者说效率太低).  
posted @ 2019-04-24 09:22  lllunaticer  阅读(327)  评论(0编辑  收藏  举报