常见树形结构

常见树形结构

树结构是一种非线性存储结构,存储的是具有“一对多”关系的数据元素的集合。

术语:

节点深度
对任意节点x,x节点的深度表示为根节点到x节点的路径长度。所以根节点深度为0,第二层节点深度为1,以此类推

节点高度
对任意节点x,叶子节点到x节点的路径长度就是节点x的高度

树的深度
一棵树中节点的最大深度就是树的深度,也称为高度

父节点
若一个节点含有子节点,则这个节点称为其子节点的父节点

子节点
一个节点含有的子树的根节点称为该节点的子节点

节点的层次
从根节点开始,根节点为第一层,根的子节点为第二层,以此类推

兄弟节点
拥有共同父节点的节点互称为兄弟节点


节点的子树数目就是节点的度

叶子节点
度为零的节点就是叶子节点

祖先
对任意节点x,从根节点到节点x的所有节点都是x的祖先(节点x也是自己的祖先)

后代
对任意节点x,从节点x到叶子节点的所有节点都是x的后代(节点x也是自己的后代)

森林
m颗互不相交的树构成的集合就是森林

树的特点

树形数据结构,具有以下的结构特点:

  1. 每个节点都只有有限个子节点或无子节点;
  2. 没有父节点的节点称为根节点;
  3. 每一个非根节点有且只有一个父节点;
  4. 除了根节点外,每个子节点可以分为多个不相交的子树;
  5. 树里面没有环路,意思就是从一个节点出发,除非往返,否则不能回到起点

树的种类

无序树
树的任意节点的子节点没有顺序关系。

有序树
树的任意节点的子节点有顺序关系。

二叉树

树的任意节点至多包含两棵子树。

二叉树遍历
二叉树的遍历是指从二叉树的根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次,且仅被访问一次。

二叉树的访问次序可以分为四种:

  • 前序遍历 (即根-左-右遍历)
  • 中序遍历 (即左-根-右遍历)
  • 后序遍历 (即左-右-根遍历)
  • 层次遍历

局限性及应用

一个二叉查找树是由n个节点随机构成,所以,对于某些情况,二叉查找树会退化成一个有n个节点的线性链.

满二叉树
叶子节点都在同一层并且除叶子节点外的所有节点都有两个子节点。

完全二叉树
对于一颗二叉树,假设其深度为d(d>1)。除第d层外的所有节点构成满二叉树,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;

完满二叉树
除了叶子结点之外的每个节点都有两个孩子,每一层(当然包含最后一层)都被完全填充。

霍夫曼树
带权路径最短的二叉树称为哈夫曼树或最优二叉树。

二叉查找树

二叉查找树(二叉搜索树、二叉排序树、BST)[这几个都是别名]
若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。

查询效率
二叉查找树的查询复杂度取决于目标节点的深度,因此当节点的深度比较大时,最坏的查询效率是O(n),其中n是树中的节点个数。

实际应用中有很多改进版的二叉查找树,目的是尽可能使得每个节点的深度不要过深,从而提高查询效率。比如AVL树和红黑树,可以将最坏效率降低至O(log n)

平衡二叉树
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,同时,平衡二叉树必定是二叉搜索树。
其中左右子树的高度差:平衡因子

AVL树

在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树

AVL树本质上还是一棵二叉搜索树,它的特点是:

  1. 本身首先是一棵二叉搜索树。
  2. 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
    也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

AVL树的旋转
一旦由于插入或删除导致左右子树的高度差大于1,此时就需要旋转某些节点调整树高度,使其再次达到平衡状态,这个过程称为旋转再平衡

保持树平衡的目的是可以控制查找、插入和删除在平均和最坏情况下的时间复杂度都是O(log n),相比普通二叉树最坏情况的时间复杂度是 O(n) ,AVL树把最坏情况的复杂度控制在可接受范围,非常合适对算法执行时间敏感类的应用。

使用场景
AVL树适合用于插入删除次数比较少,但查找多的情况。
也在Windows进程地址空间管理中得到了使用
旋转的目的是为了降低树的高度,使其平衡

AVL树特点
AVL树是一棵二叉搜索树
AVL树的左右子节点也是AVL树
AVL树拥有二叉搜索树的所有基本特点
每个节点的左右子节点的高度之差的绝对值最多为1,即平衡因子为范围为[-1,1]

红黑树

红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色
性质2. 根节点是黑色。
性质3. 每个叶子节点都是黑色的空节点(NIL节点)。
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点(简称黑高)。

一种自平衡二叉查找树, 通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保从根到叶子节点的最长路径不会是最短路径的两倍,用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决

使用场景
红黑树多用于搜索,插入,删除操作多的情况下, 红黑树应用比较广泛:

  1. 广泛用在C++的STL中。map和set都是用红黑树实现的。
  2. 著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块
  3. epoll在内核中的实现,用红黑树管理事件块
  4. nginx中,用红黑树管理timer等

原因
红黑树的查询性能略微逊色于AVL树,因为比AVL树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的AVL树最多多一次比较,但是,红黑树在插入和删除上完爆AVL树,AVL树每次插入删除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,相较于AVL树为了维持平衡的开销要小得多

红黑树 VS 平衡二叉树(AVL树)

  • 插入和删除操作,一般认为红黑树的删除和插入会比AVL树更快。因为,红黑树不像AVL 树那样严格的要求平衡因子小于等于1,这就减少了为了达到平衡而进行的旋转操作次数,可以说是牺牲严格平衡性来换取更快的插入和删除时间。
  • 红黑树不要求有不严格的平衡性控制,但是红黑树的特点,使得任何不平衡都会在三次旋转之内解决。而AVL树如果不平衡,并不会控制旋转操作次数,旋转直到平衡为止。
  • 查找操作,AVL树的效率更高。因为AVL树设计比红黑树更加平衡,不会出现平衡因子超过1 的情况,减少了树的平均搜索长度。

伸展树

伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作
它由丹尼尔·斯立特Daniel Sleator 和 罗伯特·恩卓·塔扬Robert Endre Tarjan 在1985年发明的。
在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法, 在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。伸展树应运而生。伸展树是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。
它的优势在于不需要记录用于平衡树的冗余信息

替罪羊树

替罪羊树是计算机科学中,一种基于部分重建的自平衡二叉搜索树。在替罪羊树上,插入或删除节点的平摊最坏时间复杂度是O(log n),搜索节点的最坏时间复杂度是O(log n)。
在非平衡的二叉搜索树中,每次操作以后检查操作路径,找到最高的满足max(size(son_L),size(son_R))>alpha*size(this)的结点,重建整个子树。这样就得到了替罪羊树,而被重建的子树的原来的根就被称为替罪羊节点。
替罪羊树替罪羊树是一棵自平衡二叉搜索树,由ArneAndersson提出。替罪羊树的主要思想就是将不平衡的树压成一个序列,然后暴力重构成一颗平衡的树

B-tree(B-树或者B树)

一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树
它或者是空树,或者是满足下列性质的树:

  1. 根结点至少有两个子女;
  2. 每个非根节点所包含的关键字个数j满足:┌m/2┐ - 1 <= j <= m - 1;
  3. 除根结点以外的所有结点(不包括叶子结点)的度数正好是关键字总数加1,故内部子树个数 k 满足:┌m/2┐ <= k <=m ;
  4. 所有的叶子结点都位于同一层。
    备注:┌m/2┐表示向上取整

B树(B-Tree)是一种自平衡的树,它是一种多路搜索树(并不是二叉的),能够保证数据有序。同时它还保证了在查找、插入、删除等操作时性能都能保持在O(logn),为大块数据的读写操作做了优化,同时它也可以用来描述外部存储(支持对保存在磁盘或者网络上的符号表进行外部查找)

特点

  1. B树是所有节点的平衡因子均等于0的多路查找树(AVL树是平衡因子不大于1 的二路查找树)。
  2. B树节点可以保存多个数据,使得B树可以不用像AVL树那样为了保持平衡频繁的旋转节点。
  3. B树的多路的特性,降低了树的高度,所以B树相比于平衡二叉树显得矮胖很多。
  4. B树非常适合保存在磁盘中的数据读取,因为每次读取都会有一次磁盘IO,高度降低减少了磁盘IO的次数。

B树常用于实现数据库索引,典型的实现,MongoDB索引用B树实现,MySQL的Innodb 存储引擎用B+树存放索引。

B+树

B+树是B树的一种变形形式,B+树上的叶子结点存储关键字以及相应记录的地址,叶子结点以上各层作为索引使用。一棵m阶的B+树定义如下:

  1. 每个结点至多有m个子女;
  2. 除根结点外,每个结点至少有[m/2]个子女,根结点至少有两个子女;
  3. 有k个子女的结点必有k个关键字。

B+树的查找与B树不同,当索引部分某个结点的关键字与所查的关键字相等时,并不停止查找,应继续沿着这个关键字左边的指针向下,一直查到该关键字所在的叶子结点为止

B+的特性:

  1. 所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的
  2. 不可能在非叶子结点命中
  3. 非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层
  4. 更适合文件索引系统

原因增删文件(节点)时,效率更高,因为B+树的叶子节点包含所有关键字,并以有序的链表结构存储,这样可很好提高增删效率

使用场景
文件系统和数据库系统中常用的B/B+树
通过对每个节点存储个数的扩展,使得对连续的数据能够进行较快的定位和访问,能够有效减少查找时间,提高存储的空间局部性从而减少IO操作。他广泛用于文件系统及数据库中,如:

  1. Windows:HPFS 文件系统
  2. Mac:HFS,HFS+ 文件系统
  3. Linux:ResiserFS,XFS,Ext3FS,JFS 文件系统
  4. 数据库:ORACLE,MYSQL,SQLSERVER 等中

B树:有序数组+平衡多叉树
B+树:有序数组链表+平衡多叉树

B+ 树的优点

  1. 层级更低,IO 次数更少
  2. 每次都需要查询到叶子节点,查询性能稳定
  3. 叶子节点形成有序链表,范围查询方便

B+树还有一个最大的好处,方便扫库,B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持range-query非常方便,而B树不支持。这是数据库选用B+树的最主要原因。

B*\树

B*树是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针;B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3(代替B+树的1/2)。

B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;

B*\树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针;
所以,B*树分配新结点的概率比B+树要低,空间使用率更高;

字典树

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计
它的优点是:
利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
有3个基本性质:

  1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符;
  2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
  3. 每个节点的所有子节点包含的字符都不相同。

线索二叉树

在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化。

猜你喜欢

转载自blog.csdn.net/u010523811/article/details/132768459