Binary Search Trees:
BST树里首先讲了插入删除查找等操作,比较常规。查找:最差O(n),最好O(logn),平均O(logn);插入:成功的插入平均O(logn),最差也是O(n);删除里有三种情况,对于一次成功的删除,待删除的结点v的子结点个数只可能是0、1、2,如果是0的话就直接删除无妨,是1的话就把其子结点作为待删除结点的父节点的子结点(原话是:make that child the child of the parent of v),如果有2个子结点的话,就从左子树里面找出最大的结点代替v就可以了。
BST树中还讲了最优BST树的问题,之前的一些文章里也有涉及(高级数据结构),直接列公式:C[i,j] = min{C[i,k-1] + C[k+1,j] + p[i,j] - pk}, i <= k <= j,其中p[i,j]表示pi~pj的和,C[i,j]表示一段区间内的最优BST树的代价,所以用动态规划的思想就可以解决,但三层循环i,j,k,不难发现复杂度是O(n^3),其实是比较高的。文中提出了一个优化的思想,用R[i,j]来记录对应的根结点编号,发现它的表格形式里关于行和列都是单调递增的,于是对于C[i,j]的R[i,j],只要尝试R[i,j-1]到R[i+1,j]中的所有R就可以了,不难证明此时的复杂度可以降到O(n^2)。
Red-black Trees:
红黑树在之前专门有提到过,此处不再讲述具体的内容。但在这之前作者提到了2-3-4树(每一个内部节点的孩子结点数目是2/3/4,而且所有的叶子结点在一个高度),不难算出高度为h的2-3-4树的最大节点数和最小节点数都是常数的h次幂,所以一般操作都是O(logn)的。值得一提的2-3-4树和RB树有一个对应的关系。
Amortized Analysis:
摊还分析对算法的设计产生了深远的影响,之后我们将会看到一些数据结构,通过摊还分析可以看到它的本质。
第一个提到的模型是binary counting,假设一个数以二进制的形式存在数组A里面,下面的代码来计算存在A里面的数:
1 loop i = 0; 2 while A[i] = 1 do A[i] = 0; i++ endwhile; 3 A[i] = 1. 4 forever
比如从0数到15需要变化bit一共26次,对于一个数n最多是[logn] + 1位,所以最多变化n([logn] + 1)次,还有几种分析的方法:
第一种叫做aggregation:我们可以找规律发现对于数n,有j个后缀1的小于等于n = 2^k - 1的数i一共有2^(k-j) = (n+1) / 2^j,然后再对j求一个期望可以得到总的操作次数是小于2n+2的,这样一来我们可以摊还到每一个操作,平均代价是常数级别的;
第二种叫做accounting:比如我们把0->1的变化付2元,1->0的变化付0元,而0->1的2元实际上分为两部分,一部分是bit change,另一部分是bit不变,也就是0-1-1,后面的1元用来偿还之后的1-0的价钱,也就是说最后的代价是最多是2n;
第三种方法比较奇特,叫做势函数,ci表示实际操作代价,ai = ci + pi - p(i-1),则sum(ai) = sum(ci) + pn - p0,其中是关于状态i的一个代价,使得p0 = 0, pn >= 0,这就保证所有的ai之和大于等于ci,即我们构造的代价cover了实际的代价。设pi为数字i中的1的个数,bi为后缀1的个数,则pi - p(i-1) = bi - b(i-1) = (b(i-1) - t(i-1) + 1) - b(i-1) = 1 - t(i-1), ci + pi - p(i-1) = 1 + t(i-1) + 1 - t(i-1) = 2, 那么所有的ai之和就是2n,也就是说所有的代价之后小于等于2n,平均每次也是常数次的代价。
Splay Trees:
splay树中涉及一个代价的问题,这在之前高级数据结构一章中有所介绍,不再介绍。
Homework:
问题1:考虑数组A[1,n],其中A[1] >= A[2], A[n-1] <= A[n]。我们说i是一个局部最小值如果A[i-1] >= A[i] <= A[i+1],注意A至少有一个局部最小值。1)我们显然可以在O(n)的条件下找出这个点i,请你设计出更高效的算法。2)分析自己设计的算法
问题2:一颗树有n个顶点,如何在O(n)的时间内求出最小点覆盖(是一个点的集合,每条边都有对应的端点在这个集合里面,而且是这样的集合中点的数目最少的)
问题3:证明2n次旋转足以把一颗有n个结点的bst转换另一个结点相同但是结构不同的bst
问题4:设计一个数据结构,存储具有(key, cost)的结点,要求完成以下四个操作,而且每个操作每个操作最多耗费为logn。
1)add(k,c),加入(k,c)这个结点. 2)remove(k,c),删除key = k的结点. 3)max(k1,k2)(k1 <= k2),返回k1 <= key <= k2的所有结点中最大的cost,4)count(c1,c2)(c1 <= c2),返回cost在c1~c2中的节点个数
原文地址:https://www.cnblogs.com/zyna/p/12242353.html