数据结构的扩张——基于现有结构进行改造以适应新需求

目录

  • 1.如何扩张数据结构
    1.1 扩张数据结构的一种推荐方法
    1.2 对红黑树的扩张
  • 2.示例
    2.1 顺序统计树
    2.2 区间数
    2.3 二叉查找树与平衡查找树
    2.4 二叉查找树与B树之间的关系
    2.5 二叉查找树与k-d树之间的关系
    2.6 二叉堆与可合并堆及查找树之间的关系
    2.7 二叉堆与d-堆之间的关系

1. 如何扩张数据结构

1.1 扩张数据结构的一种推荐方法

  • 许多应用需要对现有数据结构进行少许地创新和改造,但是只有很少情况需要创造出一类全新类型的数据结构。
    更经常的是,通过存储额外信息的方法来扩张一种标准的数据结构,然后对这种数据结构,编写新的操作来支持所需要的应用。添加的信息必须要能够被该数据结构上的常规操作更新和维护。

扩张数据结构的两个目的:

  • 1)满足新操作的需要
  • 2)利用附加信息来加速已有的操作

扩张一种数据结构可以分为4个步骤:

  • 1)选择一种基础数据结构
  • 2)确定基础数据结构中要维护的附加信息
  • 3)检验基础数据结构上的基本修改操作能否维护附加信息
  • 4)设计一些新操作

以上仅作为一个一般模式,不应盲目地按照上面给定的次序来执行这些步骤。大多数设计工作都包含试探和纠错的成分,所有步骤都可以并行进行。

1.2 对红黑树的扩张

定理 红黑树扩张对附加信息的维护时间不超过O(lgn)

  • 设f是n个结点的红黑树T扩张的属性,且假设对任一结点x,f的值仅依赖于结点x、x.left和x.right的信息,还可能包括x.left.f和x.right.f。那么,可以在插入和删除操作期间对T的所有结点f值进行维护,并且不影响这两个操作的O(lgn)渐近时间性能。

证明:

  • 主要思想是:对树中某结点x的f属性的变动只会影响到x的祖先。如此沿树而上进行更新,直到树根,更新过程结束。因为红黑树的高度为O(lgn),所以改变某结点f属性要耗费O(lgn),来更新被该修改所影响的所有结点。
  • 插入操作:
    1)第一阶段,将x作为一个已有结点x.p的孩子被插入。x.f可以在O(1)时间内计算出来,因为x的子节点都是T.nil。计算出出来后,变化沿树向上传播。插入的第一阶段时间为O(lgn)。
    2)第二阶段,树结构的仅有变动来源于旋转操作。由于在一次旋转过程中仅有两个结点发生变化,所以每次旋转更新f属性的全部时间为O(lgn)。又因为插入操作中的旋转次数至多为2,所以插入的总时间为O(lgn)。
  • 删除操作:
    1)第一阶段,当被删除的结点从树中移除时,树发生变化。如果被删除的结点当时有两个孩子,那么它的后继移入被删除结点的位置。这些变化引起f的更新传播的代价至多为O(lgn),因为这些变化对树的修改是局部的。
    2)第二阶段,对红黑树的修复至多需要三次旋转,且每次旋转至多需要O(lgn)的时间就可完成f的更新传播。所以删除的总时间也是O(lgn)。

2.示例

2.1 顺序统计树

  • 顺序统计量:n个元素集合中的第i(i∈{1,2,...,n}个顺序统计量就是该集合中具有第i小关键字的元素)。
  • 希望设计一种数据结构,使得可以在O(lgn)时间内确定任何的顺序统计量。
    并在O(lgn)时间内计算一个元素的秩,即它在集合线性序中的位置;如果有相等关键字,则定义为在中序遍历树时输出的位置。

2.1.1 选择基础数据结构——红黑树

红黑树是一种合适的选择,它能有效地支持一些基于全序的动态集合操作,如MINIMUM、MAXIMUM、SUCCESSOR和PREDECESSOR。

2.1.2 附加信息——size属性

在每个结点x中的size属性存储了以x为根的子树的大小。
定义T.nil的大小为0.


数据结构的扩张——基于现有结构进行改造以适应新需求_第1张图片

2.1.3 对附加信息的维护——保证插入和删除仍能在O(lgn)时间内维护size属性

1) 插入
第一阶段,从根开始沿树下降,将新结点作为某个节点的孩子插入。遍历的路径上共有O(lgn)个结点,故维护size属性的额外代价为O(lgn)。
第二阶段,沿树上升,做一些变色和旋转操作来保持红黑树性质。对红黑树结构上的改变仅仅是有旋转所致,旋转次数至多为2。此外,旋转是一种局部操作:它仅会使两个结点的size属性失效。更新size属性只需要O(1)的额外时间。
左旋LEFT-ROTATE(T,x)增加两行代码:


数据结构的扩张——基于现有结构进行改造以适应新需求_第2张图片

因此,对一棵有n个结点的顺序统计树插入元素所需要的总时间为O(lgn),从渐近意义上看,这与一般的红黑树是一样的。

2) 删除
第一阶段,删除结点。要么将结点y从树中删除,要么将它在树中上移。为了更新子树的规模,我们只需要遍历一条由结点y(从它在树中的原始位置开始)至根的简单路径,并减少路径上每个结点的size属性的值。因此时间为O(lgn)。
第二阶段,修复性质,至多三次旋转。因此只需O(1)时间。
因此删除操作,包括维护size属性,都只需要O(lgn)的时间。

2.1.4 设计新操作——OS-SELECT和OS-RANK

1)OS-SELECT(x, i)——O(lgn)
返回一个指针,指向以x为根的子树中包含第i小关键的结点。
找出顺序统计树T中的第i小关键字,调用过程OS-SELECT(T.root, i)。

数据结构的扩张——基于现有结构进行改造以适应新需求_第3张图片

2)OS-RANK(T, i)——最坏情况O(lgn)
返回对T中序遍历对应的线性序中x的位置。

数据结构的扩张——基于现有结构进行改造以适应新需求_第4张图片

循环不变式:该程序while循环的每次迭代开始,r为以结点y为根的子树中x.key的秩。
用归纳法证明:关键在于,假设r是在循环体开始处以r位根的子树中x.key的秩,那么循环体结尾处r是以y.p为根的子树中x.key的秩。

  • 考虑以y.p为根的子树,x.key的秩 = y为根的子树中先与x的结点个数 + y的兄弟节点为根的子树中先于x的结点个数 + 0/1(y.p是否先于x)
  • y是左孩子,y.p和y.p右子树都不会先于x,故r保持不变
  • y是右孩子,y.p和y.p左子树都先于x,故r = r + y.p.left.size + 1

2.2 区间树

1)区间的一些概念

  • 闭区间:是一个实数的有序对[t1, t2],其中t1 <= t2。区间[t1, t2]表示了集合{t ∈R: t1 <= t <= t2}。开区间和半开区间分别略去了集合的两个和或一个端点。
  • 高端点和低端点:[t1, t2]表示成对象i
    低端点i.low = t1
    高端点i.high = t2
  • 重叠:i和i'重叠,满足
    i ∩i' ≠ ∅ ≡ i.low ≤ i'.high & i'.low ≤ i.high(四种情况)


    重叠的四种情况
  • i在i'的左边 ≡ i.high < i'.low
    i在i'的右边 ≡ i'.high < i.low


2)区间树
区间树是一种对动态集合进行维护的红黑树,其中每个元素x都包含一个区间x.int。区间树支持下列操作:

  • INTERVAL-INSERT(T, x):将包含区间属性int的元素x插入到区间树T中
  • INTERVAL-DELETE(T, x):从区间树T中删除元素x
  • (新操作)INTERVAL-SEARCH(T, i):返回一个指向区间树T中元素x的指针,使x.int与i重叠;若此元素不存在,则返回T.nil

2.2.1 选择基础数据结构——红黑树

选择这样一棵红黑树,其每个结点x包含一个区间属性x.int,且x的关键字为区间的低端点x.int.low。因此,该数据结构按中序遍历列出的就是按低端点的次序排列的各区间。

2.2.2 附加信息

每个结点x中除了自身区间信息之外,还包含一个值x.max,它是以x为根的子树中所有区间的端点的最大值。


数据结构的扩张——基于现有结构进行改造以适应新需求_第5张图片

2.2.3 对附加信息的维护

必须验证n个结点的区间树上的插入和删除操作能否在O(lgn)时间内完成。
通过给定x.int和结点x的子结点的max值,可以确定x.max值:
x.max = max(x.int.high, x.left.max, x.right.max)
因此根据定理可知,插入和删除的时间为O(lgn)。

2.2.4 设计新的操作

数据结构的扩张——基于现有结构进行改造以适应新需求_第6张图片

正确性证明:INTERVAL-SEARCH(T, i)的任意一次执行,或者返回一个其区间与i重叠的结点,或者返回T.nil,此时树T中没有任何结点的区间与i重叠。
证明:

  • 循环不变式:如果树T包含与i重叠的区间,那么以x为根的子树必包含此区间。
  • 初始化:第一次迭代之前,x为T的根,成立
  • 保持:在while1循环的每次迭代中,第4行或第5行被执行。
    1)如果执行第5行(转到右子树),证明x.left不包含与i重叠的任何区间。
    有x.left= T.nil(显然不包含)或者x.left.max < i.low(对于x左子树的任一区间i',有i'.high <= x.left.max < i.low,因此x的左子树不包含与i重叠的任何区间);这两种情况置x为x.right使循环式保持不变。
    数据结构的扩张——基于现有结构进行改造以适应新需求_第7张图片

    2)如果执行第4行(转到左子树),证明如果在以x.left为根的子树中没有与i重叠的区间,则树的其他部分也不会包含与i重叠的区间。
    在左子树中存在i',满足i'.high = x.left.max >= i.low。因为i和i'不重叠,有i.high < i'.low
    区间树是以区间的低端点为关键字的,所以对于x右子树的任意区间i",有i.high < i'.low <= i''low
    因此i和i"不重叠,因此当x.left中不存在时,x.right肯定不会存在。
    数据结构的扩张——基于现有结构进行改造以适应新需求_第8张图片

2.3 二叉查找树与平衡查找树

参考查找树(搜索树)
参考红黑树专题

  • 二叉查找树与AVL树、伸展树之间的关系
  • 二叉查找树与红黑树之间的关系

2.4 二叉查找树与B树之间的关系

参考查找树(搜索树)中的B树

2.5 二叉查找树与k-d树之间的关系

参考k-d树——二叉搜索树的多维推广

2.6 二叉堆与可合并堆及查找树之间的关系

参考优先队列——堆

2.7 二叉堆与d-堆之间的关系

参考优先队列——堆

你可能感兴趣的:(数据结构的扩张——基于现有结构进行改造以适应新需求)