您的位置:首页 > 编程语言 > Go语言

Introduction to Algorithm(chapter 14)

2012-12-29 19:15 519 查看
数据结构的扩张,针对某些应用通过在原有的数据结构上增加某些信息(需要维护该类信息保持原有数据结构的性质不变)就可以添加一些操作来简化问题。

动态顺序统计:在红黑树的基础上,在每个节点i上增加一个域size,表示以该节点为根的子树中节点的个数(包括该节点本身)。

求取一系列数中的第j大的数,对于根节点root,根节点的左子树有t=size(left(root))个节点,那么根节点就是第t+1大的节点,如果j==t+1那么根节点即为所求,如果j<t+1,那么第j大的节点肯定在左子树中,否则肯定在右子树中,且为右子树中第(j-t-1)大,递归调用即可。伪代码如下:

OS-SELECT(x,i)

r = size(left(x))+1;

if x = i

return x;

else if i<r

return OS-SELECT(left(x),i);

else

return OS-SELECT(right(x),i-r);

利用快排中的选择算法的时间为O(n),而现在降为O(log n),因为红黑树的高度是logn,在每次递归调用后都在顺序统计树中下降一层,总时间与树的高度成正比。

确定x节点在树中的秩(即排序后的大小位置如第j大那么秩就为j),分析该问题:对这颗树进行中序遍历后,就可以确定x节点的秩,因此只需求出中序条件下排在x节点前面的节点个数即可。从树的高度角度来看,从x节点开始向上根节点进行归纳分析,对于节点x,它的左子树肯定排在它的前面,当它是父母的左孩子时x下面的节点仅有左子树在它前面,当它是父母的右孩子时,它的父母以及父母的左子树都排在它的前面,通过x不断上升到根节点即可得出总个排在它前面的节点个数。伪代码如下:

循环不变量是:r = rank of key[x] in subtree rooted at x. and y = x.

OS-RANK(T,x)

r = size(left(x))+1;

y=x;

//从当前节点不断上升到根节点进行统计

while y != root

if y = right(p(y))

r = r + 1 + size(left(p(y)));//这里加1是父亲节点,size(left(p(y)))是父亲的左子树个数

y=p(y);

return r;

y在每次迭代都上升一层,故时间与树的高度成正比,为O(log n)

对于插入和删除操作中对于size域的维护都需要O(log n)的时间

扩张数据结构的一般步骤:

1.选择合适的基础数据结构

2.确定要在基础数据结构中添加哪些信息

3.验证可用基础数据结构上的基本修改操作来维护这些新添加的信息

4.设计新的操作

measurement:将对操作的不利影响降低到最小,如果只影响局部信息的话不要影响全局信息;例如如果把每个节点的秩作为附加信息的话,那么OS-SELECT和OS-RANK将会更快,然而插入一个新节点时,将会影响到树中每个节点的秩,而附加信息是子树的规模,那么插入节点仅影响到O(logn)节点的附加信息,这样就将影响局限在局部范围内而不是全局范围。

区间树:在红黑树的基础上每个节点维护三个信息,low(x),high(x),max(x),其中[low(x),high(x)]代表该节点的区间,其中每个节点的关键字是low(x),而max(x)表示包括在x节点在内的所有子树节点中的最大的端点,即

max(x) = max(high(x),max(left(x)),max(right(x)))

查找重叠子区间和上面查找第i大的元素类似,都是从根开始下降到合适的位置(找到或者空):
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: