区间树是在红黑树基础上进行扩展得到的支持以区间为元素的动态集合的操作,其中每个节点的关键值是区间的左端点。通过建立这种特定的结构,可是使区间的元素的查找和插入都可以在O(lgn)的时间内完成。
相比于基础的数据结构,增加了一个max[x],即以x为根的子树中所有区间的断点的最大值。区间树如下图所示:
这里的区间查找的并不是精确查找,而是查找和给定区间重叠的元素,重叠的定义如下图所示:
图中(a)表示两个区间重叠的情况,其他的(b)、(c)表示没有重叠的情况。
区间查找
实现INTERVAL-SEARCH(T, i),返回一个和区间i重叠的区间,若无,则返回nil[T]。基本思想是我们通过左子树的max进行划分:如果左子树的max值小于low[i],则左子树不存在这样的区间和i重叠,转到右子树;否则,转到右子树,因为左子树的端点小于右子树,若左子树无可能,右子树也必然不可能。
INTERVAL-SEARCH(T, i)整个过程如下:
- INTERVAL-SEARCH(T, i)
- x ← root[T]
- while x≠nil[T] and i does not overlap x
- do if left[x]≠nil[T] and max[left[x]]≥low[i]
- then x ← left[x]
- else x ← right[x]
- return x
每次调用,必定会下降一层,故INTERVAL-SEARCH的时间复杂度为O(lgn)。
问题思考,如何利用区间树来解决一些问题呢?
14.3-7 VLSI数据库通常将一块集成电路表示成一组矩形。假设每个矩形的边都平行于x轴或y轴,因而矩形的表示中有最小和最大的x和y坐标。请给出一个能在O(nlgn)时间里确定n个这样表示的矩形集合中是否含有两个重叠的算法。你给出的算法不一定药输出所有相交的矩形,但要能在一个矩形完全被另一个覆盖时给出正确的判断。(提示:将一条线移过所有的矩形)
分析与解答:
其实我们经常会有这样的感觉,如何将一个未知的问题转化我我们熟知的问题这个过程是最难的。这道题可以用区间树来进行求解,具体过程如下:
每个矩形可以用两个区间来进行描述<x, y>,其中[low[x], high[x]]为矩形的水平范围,[low[y], high[y]]为矩形的垂直范围;那么两个矩形<x1, y1>和<x2, y2>重叠的充要条件为:
x1 overlap x2 && y1 overlap y2
现在有n个区间<x1, y1>, <x2, y2> ... <xn, yn>,如何判断是否有重叠呢?
正如提示所示,我们可以先对水平方向所有断点进行排序,有n个区间,即共有2n个端点,排序所需的时间共为2nlog(2n)。然后按从小到大的顺序对水平方向每个端点进行检测:
整个算法过程如下:
1. 如果这个端点是某个区间的起点,那么在区间树中查找是否有和y重叠的区间。如果有的话,说明这两个矩形重叠。将对应矩形的y区间加入到区间树中。
2. 如果这个端点是某个区间的终点,那么将对应矩形的y区间删除。
因为区间树中的查找和删除都是O(lgn)的时间复杂度,因此总的时间复杂度为O(nlgn)。
接下来需要说明算法的正确性:
因为是按x进行排序的,所以区间树中保留的是low[x]比较小的矩形的y区间。
对于情况1,如果当前的矩形是<xk, yk>,检测水平方向区间xk的左端点。根据加入的先后顺序有low[xk]>low[x],同时low[xk]<high[x],其中x是区间树中的所有矩形。这说明当前加入的矩形的水平区间xk和x都是重叠的,因此我们只需要判断垂直方向是否有重叠区间即可。
对于情况2,如果当前的矩形是<xk, yk>,检测水平方向区间xk的右端点。易知区间树中的所有矩形元素都没有和当前矩形重叠的。那么对应将来要加入的矩形呢?因为将来加入的矩形根据前面的排序特性low[x']>high[xk],其中x'为待加入的矩形的水平区间。即水平方向就不重叠的,即矩形也不可能重叠。
证毕