数据结构|区间树

96 阅读4分钟

区间树(Interval Tree)

参考资料

维基百科-区间树

博客园SovietPower-区间树 学习笔记

实现的功能

给定nn个区间(线段),对于给定的查询区间或点,可以在O(logn+K)O(logn+K)时间内求出与查询区间相交/包含查询点的所有区间(KK是答案区间的数量)。

构造

区间树是一个二叉树。依据所有区间确定一个中间点xcenterx_{center},设每个区间的左右端点分别为llrr。对于r<xcenterr<x_{center}的区间分到左子树中构造;l>xcenterl>x_{center}的区间分到右子树中继续构造;剩下的就是包含xcenterx_{center}的区间,分别按ll升序、rr降序的两种序列存在当前节点中。也就是每个节点包含五个信息:

  • 中心点 xcenterx_{center}
  • 指向另一个节点的指针 lsonlson,该节点包含完全位于xcenterx_{center}左侧的所有区间
  • 指向另一个节点的指针 rsonrson,该节点包含完全位于xcenterx_{center}右侧的所有区间
  • 所有包含xcenterx_{center}的区间按照左端点排序(记为SaS_a)
  • 所有包含xcenterx_{center}的区间按照右端点排序(记为SbS_b)

xcenterx_{center}的选取要使得划分到左右子树中的区间数相近。对所有区间的左右端点排序后,取中位数作为xcenterx_{center}通常可以满足要求。

(逻辑:左子树的区间的两个端点都在xcenterx_{center}左侧,右子树的区间的两个端点都在xcenterx_{center}右侧。排序后的中位数将左右端点划分为两部分,两侧端点数量接近相等。)

取所有区间的端点时间复杂度为O(n)O(n),对所有端点排序的时间复杂度为O(nlogn)O(nlogn)。因此构建区间树的时间复杂度为O(nlogn)O(nlogn),空间复杂度为O(n)O(n)

查询包含点qq的区间(stabbing query)

从根节点开始,若q<xcenterq<x_{center},则查询当前节点以及左子树;若q>xcenterq>x_{center},查询当前节点以及右子树;若q=xcenterq=x_{center},当前节点所有的区间就是答案。

查询节点包含qq的区间,只需要找到满足l<=q<=rl<=q<=r的区间。

q<xcenterq<x_{center},则节点所有区间都满足r>qr>q,所以只需要找满足l<=ql<=q的区间即可,从SaS_a(区间按照左端点排好序)中枚举即可。

q>xcenterq>x_{center},则节点所有区间都满足l<ql<q,所以只需要找满足r>=qr>=q的区间即可,从SbS_b(区间按照右端点排好序)中枚举即可。

区间树查询包含查询点qq的时间复杂度为O(logn+K)O(logn+K),具体分析如下:

  1. 树的搜索过程

    区间树是一棵平衡二叉树,其高度为O(logn)O(logn)。搜索时,从根节点开始,按照查询点qq与区间中心点的关系递归向下,最多访问节点数量为树的高度,即O(logn)O(logn)个节点。

  2. 结果处理

    访问每个节点时,处理与查询点qq相关的区间,总计KK个。

因此,时间复杂度为两部分的加和O(logn)+O(K)=O(logn+K)O(logn)+O(K)=O(logn+K)

查询与给定区间相交的所有区间

要使结果区间[x.l,x.r][x.l, x.r]与查询区间[q.l,q.r][q.l, q.r]相交,必须满足以下条件之一:

  • xx的起点或终点位于qq
  • xx完全包围qq
IMG_0D17B3EC321F-1.jpeg

首先找满足第一个条件的区间,即起点和/或终点位于qq内的所有区间。

我们可以使用区间集合内所有的起点和终点构建一棵二叉搜索树,二叉搜索树的每个节点都有一个指向其对应区间(起点或终点等于该节点值)的指针。在O(logn)O(logn)时间内搜索节点值在[q.l,q.r][q.l, q.r]的节点,将这些节点指向的区间添加到结果列表中。(有个疑问,这里的时间复杂度不是O(n)O(n)吗?例如当qq完全覆盖所有区间时,需要遍历搜索树中的所有节点。)

起点和终点都在qq内的区间可能被重复添加,因此可以通过在每个区间上使用二进制标志来标记它是否已经被添加到结果列表中。

接着找满足第二个条件的区间,有个技巧:在qq内选择任意一点并利用Interval Tree查找与该点相交的所有区间,找到的区间一定包含所有完全包含qq的区间。找到的区间可能与条件一重复,注意删除重复项。查找满足第二个条件的区间的复杂度为O(logn+K)O(logn+K)

综合条件一和条件二,查询与给定区间相交的所有区间的时间复杂度仍为O(logn+K)O(logn+K)