数据结构与算法分析(二)

作者: 阿琦 | 2021-05-09 | 阅读

   

对于大量的输入数据,链表的线性访问时间太慢,不宜使用。有一种简单的数据结构,其大部分操作的运行时间平均为 O(logN),这种数据结构叫做二叉查找树。二叉查找树是两种库集合类 TreeSet 和 TreeMap 实现的基础。

树(tree)可以用几种方式定义。定义树的一种自然的方式是递归的方式。一棵树是一些节点的集合。这个集合可以是空集;若不是空集,则树由称作根(root)的节点r 以及 0 个或多个非空的(子)树 T1,T2, … , T4 组成,这些子树中每一颗的根都来自根 r 的一条有向的边(edge)所连结。

每一颗子树的根 r 的儿子(child),而 r 是每一颗子树的根的父亲(parent)。如下图显示用递归定义的典型的树。

从递归定义发现,一棵树是 N 个节点和 N-1 条边的集合,其中的一个节点叫做根。存在 N-1 条边的结论是由下面的事实得出的:每条边都将某个节点连接到它的父亲,而除去根节点外每个节点都有一个父亲,如下图:

二叉树

二叉树是一棵树,其中每个节点都不能有多于两个的儿子。

下图 显示一颗由一个根和两颗子树组成的二叉树,子树 \(T_ L\) 和 \(T_ R\) 均可能为空。

二叉树的一个性质是一颗平均二叉树的深度要比节点个数 N 小得多。分析表明,其平均深度为 \(O(\sqrt{N})\) 而对于特殊类型的二叉树,即二叉查找树,其深度的平均值是 O(logN)。最坏情形的二叉树,深度可以达到 N - 1 .

最坏情形的二叉树

AVL 树

AVL 树是带有平衡条件的二叉查找树。这个平衡条件必须要容易保持,而且它保证树的深度须是 O(logN)。最简单的想法是要求左右子树具有相同的高度。

一颗坏的二叉树。只要求在根节点平衡是不够的

当进行插入操作时,需要更新通向根节点路径上那些节点的所有平衡信息,而插入操作,插入一个节点可能破坏 AVL 树的特性(如下图,将 6 插入到图中,将破坏关键字 8 的节点处的平衡条件)。如果发生这种情况,那么就要在考虑这一步插入完成之前恢复平衡的性质。通过对树进行简单的修正来做到称为旋转。

两颗二叉查找树,只有左边的树是 AVL 树

单旋转:

双旋转:

红黑树

历史上 AVL 树流行的另一变种是红黑树。对红黑树的操作在最坏情形下花费 O(logN)时间。

红黑树是具有下列着色性质的二叉查找树:

  1. 每一个节点或者着色成红色,或者着色成黑色。
  2. 根是黑色的。
  3. 如果一个节点是红色的,那么它的子节点必须是黑色的。
  4. 从一个节点到一个 null 引用的每一条路径必须包含相同数目的黑色节点。

着色法则的一个结论是,红黑树的高度最多是 2log(N+1)。因此查找操作保证是一种对数的操作。如下图显示一颗红黑树。

和通常一样,困难在于将一个新项插入到树中。通常把新项作为树叶放到树中。如果把该项涂成黑色,那么肯定违反条件 4,因为将会建立一条更长的黑色路径。因此,这一项必须涂成红色。如果它的父节点是黑色的,则插入完成。如果它的父节点已经是红色的,那么得到连续红色的节点,这就违反了条件 3。在这种情况下,我们必须调整该树以确保满足条件 3(且又不引起条件 4 被破坏)。用于完成这项任务的基本操作是颜色的改变和树的旋转。


版权声明:本文由 阿琦 在 2021年05月09日发表。本文采用CC BY-NC-SA 4.0许可协议,非商业转载请注明出处,不得用于商业目的。
文章题目及链接:《数据结构与算法分析(二)》




  相关文章:


留言区:

TOP