Centered Interval tree 介绍(中心区间树)

来源:互联网 发布:windows线程同步事件 编辑:程序博客网 时间:2024/04/29 22:33

参考:https://en.wikipedia.org/wiki/Interval_tree

百度很多关于interval tree和segment tree的感觉都有问题,于是去Wikipedia查了一下interval tree,在这里总结一下。

线段树用来索引线段,比如时间段[1,10], [3,7], [20,30],主要支持点查询,比如查找时间点4,会查出[1,10]和[3,7],范围查询会附加用一颗独立的树形结构如B+树辅助查询。

有两种interval tree的实现,这里介绍其中一种 Centered interval tree

Centered interval tree

1 整体介绍

Centered interval tree 是一颗三叉树,专门用来应对点查询。

给定 n 个线段,用 Ts 和 Te 表示起点和终点。首先确定一个中心点,中心点会把所有线段分成三部分:

  • a:Te 比 中心点 小的线段集合。
  • b:中心点 落在[Ts,Te]中间的线段。
  • c:Ts 比 中心点 大的线段。

a 为当前节点,b 为 a 的左子树,c 为 a 的右子树。树的整体构造过程就是这样,中心点的选择尽量使树平衡。

2 当前节点构造过程

当前节点维护五个信息:

  • 1:中心点的值
  • 2:指向左子树的指针
  • 3:指向右子树的指针
  • 4:按 Ts 将 a 中的线段排序
  • 5:按 Te 将 b 中的线段排序

下面以 7 条线段为例,给出一个 interval tree 的示意图(仅表示大概意思)

  • [1,5]
  • [2,4]
  • [6,13]
  • [7,11]
  • [8,12]
  • [17,21]
  • [18,22]

线段树

其中 10 ,3 ,20 是三个节点的中心点。3和20两颗子树没有子节点了。

3 点查询

查询包含点 p 的线段,从根节点开始,先和第一个节点开始查找,如果 p 等于当前中心点,则直接返回所有当前节点的线段,不再查找子树。如果 p 比中心点小,则递归查找左子树,p 比中心点大类似。

3.1 查询当前节点

当前节点维护的都是覆盖中心点的线段。如果 p 比中心点小,则所有线段的 Te 都比 p 大,只需要查找第 4 部分(按 Ts 将线段排序),所有小于 p 的 Ts 的线段都会覆盖 p ,满足查询条件。

其中x_center为中心点,x为查找的点。下图是节点内部的查找过程

这里写图片描述

3.2 点查询示例

查询7.5的示例图:首先查找根节点,因为7.5比10小,继续查找左子树。最后找到两个线段[6,13], [7,11]。

这里写图片描述

4 范围查询

给定查询范围[m, n],返回与[m, n] 相交的所有线段。需要一个一维树形结构辅助。一般用B+树。

两条线段相交有四种:其中黑色线段为查询条件,下边线段为相交的线段。

这里写图片描述

这四种可以进一步分为两种情况:

  • a,b,c :左右端点至少有一个在查询范围内。
  • d:完全覆盖查询范围。

4.1 范围查询过程

满足第一种情况的线段可以通过对所有线段建立一颗 B+ 树,将每个线段的左右端点插入到树中。范围查询可以直接查找开始节点和结束节点,中间端点链接的线段都满足要求。

第二种情况可以通过 interval tree来查,从查询范围中随便取一个点进行点查询。

最后进行合并去重。

4.2 范围查询示例:

查询[7.5, 9]。首先在 B+ 树中找到满足第一种情况的线段。

这里写图片描述

找到线段:[8,12]

再随便取个中间值 7.8 到 interval tree 中找到满足第二种情况的线段。

这里写图片描述

找到线段:[6,13], [7,11]

最后合并去重,得到结果集[8,12],[6,13], [7,11]

原创粉丝点击