您的位置:首页 > 理论基础 > 数据结构算法

MIT:算法导论——11.扩充的数据结构、动态有序统计和区间树

2014-06-19 11:20 721 查看
算法导论第14章 【数据结构的扩张】

为应对新的应用需求,经常是通过存储额外信息的方法来扩张一种标准的数据结构,

然后对这种数据结构,编写新的操作来支持所需要的应用。

一、动态顺序统计

一种支持一般动态集合上,顺序统计操作的数据结构。

通过这种数据结构,可以快速地找到一个集合中的第i小的数,(select)

或给出一个指定元素在集合的全序中的位置。(rank)

【已知】对于一个无序的集合,能够在O(n)的时间内确定任何的顺序统计量。

rank(x):获得x在数组中的位置,遍历数组并统计比x.key小的元素数即可。

select(i):利用random-partion()函数,二分地去定位即可。

【目标】修改红黑树,使得在O(lgn)时间内确定任何的顺序统计量。

【顺序统计树】在每个结点上存储附加信息的一棵红黑树。

除了基本结点属性x.key、x.color、x.p、x.left、x.right之外,还附加x.size属性。

设哨兵T.nil的x.size为0,则有等式: x.size = x.left.size + x.right.size + 1。

OS-SELECT( x, i ) // 过程返回一个指针,指向以x为根的子树中包含第i小关键字的结点
r = x.left.size + 1
if i == r
return x
else if i < r
return OS-SELECT( x.left, i )
else
return OS-SELECT( x.right, i - r )
OS-RANK( T, x ) // 过程返回T中序遍历对象的线性序中x的位置
r = x.left.size + 1
y = x
while y != T.root
if y == y.p.right
r += y.p.left.size + 1
y = y.p
return r
【OS-RANK解释】

如果y是y.p的左孩子,y.p和y.p的右子树中所有结点都不会先于x,r保持不变。

如果y是y.p的右孩子,y.p和y.p的左子树中所有结点都先于x,r要加上y.p.left.size + 1。

【对子树规模的维护】

LEFT-ROTATE( T, x )的代码,要添加下面两行:

y.size = x.size // y = x.right

x.size = x.left.size + x.right.size + 1

RIGHT-ROTATE( T, x )的代码,要添加下面两行:

y.size = x.size

x.size = x.left.size + x.right.size + 1

维护size时间复杂度:O(1)。所以插入、删除,包括维护size属性,都只需要O(lgn)时间。

二、如何扩张数据结构(Ex. OS-trees)

(1)选择一种基础数据结构。(red-black tree)

(2)确定基础数据结构中要维护的附加信息。(subtree size,直接记录秩也可以,不过速度太慢了)

(3)检验基础数据结构上的基本修改操作能否维护附加信息。(Insert、Delete/Rotate是否可以维持子树大小的信息)

(4)设计一些新操作。(怎么使用这些信息:OS-Select、OS-Rank)

【实际使用时】上面可能更像一个checklist,而设计时可以先设计一个些新操作(4),再去验证附加信息维护等。

【2+2】2组数据 + 2组操作:基础操作+附加操作 : 基本操作+新添操作

三、区间树

一个区间[t1, t2]表示成一个对象i,其中属性i.low = t1为低端点, i.high = t2为高端点。

【区间i与i'重叠(overlap)】

如果i与i'的交集非空,即如果i'.low <= i.high and i.low <= i'.high。

任何两个区间i与i'满足【区间三分定律】,即下面三条性质之一成立:

(1)i和i'重叠。

(2)i在i'的左边,即i.high < i'.low

(3)i在i'的右边,即i.low > i'.high

Example Interval Trees : Maintain a set of intervals.

eg : time intervals.

【区间树】一种对动态集合进行维护的红黑树,其中每个元素x都包含一个区间x.int。

区间树支持下列操作:

(1)INTERVAL-INSERT( T, x ):将包含区间属性的int的元素x插入到树T中。

(2)INTERVAL-DELETE( T, x ):从T删除x。

(3)INTERVAL-SEARCH( T, i ):返回一个指向T中元素x的指针,使x.int与i重叠。不存在返回T.nil。

【扩张数据结构】

步骤1:基础数据结构

一棵红黑树,每个结点x包含一个区间属性x.int,且x的关键字为区间int的低端点x.int.low。

所以该数据结构的中序遍历,就是按低端点的次序排列的各区间。

步骤2:附加信息

包含一个值x.max,它是以x为根的子树中,所有区间的端点的最大值。

步骤3:对信息维护

通过x.int和x子结点的max,有 x.max = max( x.int.right, x.left.max, x.right.max )。

故一次旋转后,更新max属性只要O(1)的时间;所以插入和删除的运行时间为O(lgn)。

步骤4:设计新操作。

INTERVAL-SEARCH( T, i )
x = T.root
while x != T.nil and i does not overlap x.int
if x.left != T.nil and x.left.max >= i.low // i'.low <= i.high
x = x.left
else
x = x.right
return x
【解释】

分支if执行时,如果在以x.left为根的子树中,没有与i重叠的区间,

则树的其他部分也不会包含与i重叠的区间。

分析:有x.left.max >= i.low,根据max属性定义,在x的左子树中必定存在某区间i',满足:

i'.high = x.left.max >= i.low,

如果i与i'不重叠,则i.high < i'.low <= i''.low,其中i''为右子树中任意区间,

所以右子树也不包含与i重叠的区间。

========================================================================

【图示化补充】

【顺序统计树】下面给出一个修改后的红黑树的例子,如下图所示:



【区间树】修改红黑树得到的区间树如下图所示:



从图可以看出,对区间树以每个节点的左端点值进行中序变量即可得到有序的序列。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: