如何扩张数据结构
对基本数据进行扩张以支持一些附加功能,在算法设计过程中是相当常见的。所以扩张一种数据结构大概可以分为如下4个步骤:
- 选择一种基础数据结构
- 确定基础数据结构中要维护的附加信息
- 检验基础数据结构上的基本修改操作能否维护附加信息
- 设计一些新操作
以上仅作为一个一般模式,大多数的设计工作都包含试探和纠错的成分,过程中所有步骤通常可以并行进行
区间树
扩张红黑树来支持由区间构成的动态集合上的一些操作。闭区间(closed interval)是一个实数的有序对
[
t
1
,
t
2
]
[t_1,t_2]
[t1,t2],其中
t
1
≤
t
2
t_1\le t_2
t1≤t2,区间
[
t
1
,
t
2
]
[t_1,t_2]
[t1,t2]表示了集合
{
t
∈
R
:
t
1
≤
t
≤
t
2
}
\{ t \in R: t_1 \le t \le t_2\}
{t∈R:t1≤t≤t2},开区间和半开区间分别略去了集合的两个或一个端点。
我们可以把一个区间
[
t
1
,
t
2
]
[t_1,t_2]
[t1,t2]表示成一个对象
i
i
i,其中属性
i
.
l
o
w
=
t
1
i.low = t_1
i.low=t1为低端点,属性
i
.
h
i
g
h
=
t
2
i.high=t_2
i.high=t2为高端点,我们称区间
i
i
i和
i
1
i^1
i1重叠,如果
i
∩
i
1
≠
ϕ
i \cap i^1\ne \phi
i∩i1=ϕ,即如果
i
.
l
o
w
≤
i
1
.
h
i
g
h
i.low \le i^1.high
i.low≤i1.high 且
i
1
.
l
o
w
≤
i
.
h
i
g
h
i^1.low \le i.high
i1.low≤i.high。如下图所示:任何两个区间
i
i
i和
i
1
i^1
i1满足区间三分律,即下面三条性质之一成立:
a.
i
i
i和
i
1
i^1
i1重叠
b.
i
i
i在
i
1
i^1
i1的左边(
i
.
h
i
g
h
<
i
1
.
l
o
w
i.high<i^1.low
i.high<i1.low)
c.
i
i
i在
i
1
i^1
i1的右边(
i
1
.
h
i
g
h
t
<
i
.
l
o
w
i^1.hight<i.low
i1.hight<i.low)
区间树是一种对动态集合进行维护的红黑树,其中每个元素
x
x
x都包含一个区间
x
.
i
n
t
x.int
x.int,下图说明了区间树是如何表达一个区间集合的。
一棵区间树,(a)10个区间的集合,它们按左端点自底向上顺序出,(b)表示它们的区间树,每个节点
x
x
x包含一个区间,显示在虚线的上方,一个以
x
x
x为根的子树中所包含的区间端点的最大值,显示在虚线的下方。
-
步骤1:基础数据结构
选择一棵红黑树,其每个节点 x x x包含一个区间属性 x . i n t x.int x.int,且 x x x的关键字为区间的低端点 x . i n t . l o w x.int.low x.int.low -
步骤2:附加信息
每个节点 x x x中除了自身区间信息之外,还包含一个值 x . m a x x.max x.max,它是以 x x x为根的子树中所有区间的端点的最大值 -
步骤3:对信息的维护
n n n个节点的区间树上的插入和删除操作能否在 O ( l g n ) O(lgn) O(lgn)时间内完成。通过给定区间 x . i n t x.int x.int和节点 x x x的子节点的 m a x max max值,可以确定 x . m a x x.max x.max值: x . m a x = m a x ( x . i n t . h i g h , x . l e f t . m a x , x . r i g h t . m a x ) x.max = max(x.int.high, x.left.max, x.right.max) x.max=max(x.int.high,x.left.max,x.right.max)
更新 m a x max max属性只需要 O ( 1 ) O(1) O(1)的时间,所以插入和删除操作运行时间保持为 O ( l g n ) O(lgn) O(lgn) -
步骤4:设计新的操作
我们需要设计一个新的操作 interval_search(T, i),它是用来找出树T中与区间 i i i重叠的那个节点。
如下为实现函数:
def interval_search(T, i):
x = T.root
# i does not overlap x.int
while x!=T.nil and not (i.low<=x.high and x.low<=i.high):
if x.left!=T.nil and x.left.max>=i.low:
x = x.left
else:
x = x.right
return x