动态有序统计
- 主要操作:
OS-Select(i)//返回动态集中第i小的元素。
OS-Rank(x) //返回动态集排序序列中元素x的位置。 - 新增数据:
在每个结点中保存其子树的结点个数。
size[x]=size[left[x]]+size[right[x]]+1
size[nil]=0
- 处理nil的通用技巧:
标记法,给空结点分配空间,并用一个伪记录内容作为标记。
- 处理nil的通用技巧:
- OS-Select(x,i)(递归函数伪码):
k ← size[left[x]]+1
if i=k then return x
if i<k then return OS-Select(left[x],i)
else return OS-Select(right[x],i-k)
Ex:
OS-Select(root,i) → return ptr to “H”
- 时间分析:
显而易见,OS-Select(i)、 OS-Rank(x)运行时间为O(lgn)。
如果直接记录每个结点在动态集排序序列中元素x的位置,为维持此数据,红黑树自身数据结构的操作时间复杂度会比较高。
记录子树结点个数策略下,修改红黑树的插入、删除操作,使其在插入、删除操作中完成子树结点个数数据项的更新。 - Ex(插入“K”):
- BST插入,结点数更新:
- 重建红黑树:
改色是常数时间内的操作。
旋转,只需根据子节点来进行重建,因此每次旋转也是常数时间内的操作。
Ex:
扩充后的插入、删除操作的运行时间仍然为O(lgn)。
- BST插入,结点数更新:
扩充数据结构
一般步骤(以有序统计树为例):
1.选择一个基础的数据结构: 选择红黑树。 2.决定附加的数据项: 在每个结点中附加其子树的结点个数的数据项。 3.验证数据结构的修改操作能够维护这个新增数据: 红黑树的修改删除操作中增加维护附加数据项的操作。 4.建立新增的数据结构操作(使用附加的数据项)。 创建OS-Select(i)和OS-Rank(x)操作。
上述步骤可以用来作为检测清单,不必要一定要按此步骤进行数据结构的扩充。
区间树
用来保存一系列的区间,例如时间区间。
- 例如区间i=[7,10],则有low[i]=7,high[i]=10。
定义查询操作,查询区间树中与已知区间有重叠的区间。
创建区间树
步骤
1.选择的数据结构为红黑树,将区间左端作为红黑树的构造键值。
2.在每个结点中附加其子树中最大端点值的数据项m。
3.修改红黑树的原操作:- 插入操作:
在从上向下的键值比较操作过程中,加上m值的比较过程,更新相应的m值。
旋转过程:
在O(1)时间内完成操作。
插入操作的总用时为O(lgn)。 - 删除操作:
删除操作带来的重建工作要比插入复杂,但都是局部的常数时间内的操作,所以删除操作的时间复杂度也为O(lgn)。
4.创建新的函操作:
Interval-Search(i): x ← root while x≠nil and (low[i]>high[int[x]] or low[int[x]]>high[i]) if left[x]≠nil and low[i]<=m[left[x]] then x ← left[x] else x ← right[x] return x
- Ex:
[14,16] → 返回[15,18]
[12,14] → 返回nil - 运行时间:
返回一个重叠区间,时间为O(lgn)。
返回所有重叠区间,可以找到一个删除一个,设重叠区间的总数为k,则时间为O(klgn)。说明此算法为输出敏感算法,即算法的时间复杂度与输出的结果数量有关。 - 正确性分析:
- 插入操作: