binary tree & BST
二叉树是比较常见的树,可用于实现BST,二叉堆或二叉排序树。下面是两个基本概念:
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层有叶子节点,并且叶子节点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶结点都处在最底层的二叉树。
二叉查找树(Binary Search Tree),或者是一棵空树,或者是具有下列性质的二叉树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树。
BST的基本操作:
- Search
- minimum
- Maximum
- Predecessor
- Successor
- Insert
- Delete
下面分别总结算法原理的算法复杂性。
Search
根据BST的性质,对某个子树的根,如果与key相同,则返回,如果key小于这个节点,则进入左子树,否则进入右子树。这样该算法过程只与树的高度有关系,为O(h)。
minimum & Maximum
从根节点开始,沿着各个节点的left指针查找下去,直到遇到NULL为止,就可以找到min节点了。而一直沿着right指针查找下去,就找到max了,复杂度都是O(h)。
Predecessor & Successor
对于BST来说,in-order遍历是比较有用的,可以得到一个有序的列表。一个节点in-order的后继:若其右子树不为空,那右子树中的min就是其后继;若右子树为空,且当前节点是其父的左节点,则其父就是后继,若当前节点是其父的右节点,则需要继续向上查找并判断是否为右孩子、左孩子。复杂度为O(h)。
Insert
插入过称也是利用BST的性质,向左走或者向右走,找到合适的位置,然后插入。这样的插入过程比较简单,但是也会造成潜在的问题:BST会变得很不平衡。导致高度h接近树的size,这样就基本退化为链表了,效率也会大大降低。
Delete
删除时分3种情况:z没有子女,直接删;z只有一个子女,z子女成为z父的子女,然后删z;z有两个子女,找到z的后继,替换到z的位置,删掉z的后继。所以复杂性主要由第三种情况决定,最坏情况下为O(h)。
注意:BST很可能不平衡,h并不是接近lgn的,我们也不能做这样的假设,为了让h接近lgn,可以使用随机构造的方式使得树的平均高度解决lgn。
RB tree
红黑树也是一种BST。不过它通过在每个节点上存储一个颜色位来使得该树接近平衡。
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
红黑树也是一种BST,所以BST的所有常用操作也都是适用的,这里只介绍特殊的操作:
Rotate
红黑树的插入和删除操作会破坏红黑树的性质,为保持树中节点的颜色以及指针结构,就需要使用旋转操作。旋转操作都是O(1)的。
Insert:
插入操作的第一部分工作跟BST的是一样的,找到合适的位置,插入,并设置为红色。一旦设置为红色,就可能破坏红黑性质,就是靠fixup过程来修复。这一部分有另外一篇博文专门介绍插入后的fixup过程的。两部分的复杂度都是O(lgn)的。
Delete
删除操作的第一部分跟BST也是一样的,找到合适的节点,删掉。这时就会造成红黑性质的破坏,应该来说,影响只在被删除的节点附近。复杂度也是O(lgn)。
B tree