This slide is based on Mark Allen Weiss's book.
中译本是《数据结构与算法分析 C++ 描述》张怀勇等译
首先考察第4章讨论过的 AVL 树的变种, 包括优化的伸展树、红黑树、(第10章讨论过的)跳跃表的确定性的形式、AA 树以及 treap 树.
然后考察一种可以用于多维数据的数据结构. 在这种情况下, 每一项均可有多个键. $k$-d 树对任何键都能进行相关的搜索.
最后, 考察配对堆(pairing heap), 它似乎是斐波那契堆的最实用变体.
第4章讨论了基本的伸展树操作. 当顶 $X$ 作为树叶被插入时, 称为{\bf 伸展(splay)}的一系列的树旋转使得 $X$ 成为树的新根.
伸展操作也在查找期间执行, 而且如果一项也没有找到, 那么就要对访问路径上的最后的结点施行一次伸展.
第11章指出一次伸展树操作的摊还开销为 $O(\log N)$.
历史上流行的 AVL 树的另一变种是红黑树(Red Black Tree). 红黑树是 Rudolf Bayer 在1972年发明的. 当时被称为平衡二叉 B 树(symmetric binary B-trees). 后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
为定义更加方便, 引入扩展二叉树的概念. 在二叉树的每个叶子结点添加两个儿子, 所形成的二叉树称为原二叉树的扩展二叉树. 所添加的结点称为原二叉树的外结点. 虽然我们在实现红黑树时并没有真的在原二叉查找树的基础上在每个叶子处添加真正的结点, 但从逻辑上我们认为叶子的两个虚结点是外结点.
红黑树是具有下列着色性质的(扩展)二叉查找树:
Prop. 红黑树的高度最多是 $2\log(N+1)$.
因此, 这保证了查找操作是一种对数复杂度的操作.
通常把新项作为树叶放到树中. 如果把该项涂成黑色, 那么肯定违反红黑树的着色规定 4, 因为新结点到根这条路径上的黑色结点数增加了 1. 破坏了红黑树的平衡. 故这一项必须涂成红色.
如果它的父结点是黑色的, 则插入完成. 如果它的父结点是红色的, 那么出现连续的两个红色结点, 这违反了红黑树的着色规定 3. 在这种情况下, 必须调整该树以便确保满足着色性质 3 (且又不违反着色性质 4). 完成这个任务的基本操作是颜色的改变和树的旋转.
如果父结点是红色的, 那么有几种情形, 每一种都有一个镜像对称的图像需要考虑.
treap 树由二叉查找树改造而来. 每个结点多一个整型变量用于存储该结点的优先级.
结点优先级满足堆序性质: 即任意结点的优先级必须至少和它父亲结点的优先级一样大. (优先级大的往下沉).
treap 树和跳跃表一样, 使用随机数并且对任意的输入都能给出 $O(\log N)$ 的期望时间的性能.
查找时间等同于非平衡二叉查找树(从而比平衡查找树要慢); 而插入时间只比递归非平衡二叉查找树的实现方法稍慢.
虽然删除操作要慢得多, 但仍然是 $O(\log N)$ 期望时间.
templateclass Treap { public: Treap() { nullNode = new TreapNode; nullNode->left = nullNode->right = nullNode; nullNode->priority = INT_MAX; root = nullNode; } Treap (const Treap & rhs); virtual ~Treap(); protected: private: struct TreapNode { Comparable element; TreapNode *left; TreapNode *right; int priority; TreapNode():left(NULL), right(NULL), priority(INT_MAX){} TreapNode(const Comparable & e, TreapNode *lt, TreapNode *rt, int pr) : element(e), left(lt), right(rt), priority(pr){} }; TreapNode *root; TreapNode *nullNode; Random randomNums; //Additional private member functions };