范围查询的数据结构

时间:2012-10-04 04:59:10

标签: algorithm data-structures

我最近被问到有关以下问题的编码问题。 我有一些解决这个问题的方法,但我不太确定它们是否最有效。


问题:

编写程序以跟踪文本范围集。起点和终点将是字符串。

Text range example : [AbA-Ef]
 Aa would fall before this range
 AB would fall inside this range
 etc.

字符串比较就像'A'< 'a'< 'B'< 'b'......'Z'< 'Z'

我们需要支持此范围内的以下操作

  • 添加范围 - 这应合并范围(如果适用)
  • 删除范围 - 这会从跟踪的范围中删除范围并重新计算范围
  • 查询范围 - 给定一个字符,函数应返回它是否属于任何跟踪范围。

请注意,跟踪范围可能是不连续的。


我的解决方案:

我提出了两种方法。

  1. 将范围存储为双向链接列表或
  2. 将范围存储为某种平衡树,其中叶节点具有实际数据,并且它们作为链表互连。
  3. 您认为这个解决方案是否足够好,或者您可以考虑采用更好的方法来实现这三个API,从而提供最佳性能?

4 个答案:

答案 0 :(得分:9)

您可能正在寻找 interval tree

将数据结构与自定义比较器一起使用以指示“范围内的内容”,您将能够有效地执行所需的操作。

注意,区间树实际上是实现第二个想法的有效方式(Store ranges as a some sort of balanced tree

答案 1 :(得分:1)

我不清楚“删除范围”操作应该做什么。是吗;

  • 删除先前插入的范围,并重新计算剩余范围的合并?

  • 停止跟踪已删除的范围,无论其中添加了多少部分。

这在算法上没有太大的区别;这只是簿记。但澄清是很重要的。范围是关闭还是半开? (另一个不影响算法但确实影响实现的细节。)

解决此问题的基本方法是将跟踪集合并为不相交(非重叠)范围的排序列表;无论是作为向量还是二元搜索树,或基本上任何支持O(log n)搜索的结构。

一种方法是将每个不相交范围的两个端点放入数据结构中。要确定目标值是否在某个范围内,请找到大于目标的最小端点的索引。如果索引是奇数,则目标在某个范围内;甚至意味着它在外面。

或者,通过起始点索引所有不相交的范围;通过搜索不大于目标的最大起点找到目标,然后将目标与相关的终点进行比较。

我通常使用带有排序向量的第一种方法,如果(a)空间利用率很重要且(b)插入和合并相对较少,这是合理的。使用二叉搜索树,我会采用第二种方法。但它们的细节和常数不同。

合并和删除并不困难,但有一些令人烦恼的案例。首先找到与要插入/删除的范围的端点相对应的范围(使用标准查找操作),删除两者之间的所有范围,然后摆弄端点以纠正部分重叠的范围。虽然查找操作始终为O(log n),但树/向量操作为o(n)(如果插入/删除的范围很大,无论如何)。

答案 2 :(得分:0)

大多数语言(包括Java和C ++)都有某种有序映射或有序集,您可以在其中查找值并查找值之后的下一个值或第一个值。您可以将其用作构建块 - 如果它包含一组不相交的范围,那么它将具有范围的最小元素,后跟范围的最大元素,后跟范围的最小元素,后跟最大元素范围等。添加范围时,您可以检查是否保留了此属性。如果没有,则需要合并范围。同样,您希望在删除时保留此项。然后,您可以通过查看查询点之前是否存在最少元素以及之后的最大元素来进行查询。

如果你想从头开始创建自己的数据结构,我会考虑某种基数结构,因为这样可以避免进行大量重复的字符串比较。

答案 3 :(得分:0)

我认为你会选择B +树,就像你提到的第二种方法一样。

以下是B +树的一些属性:

  1. 所有数据都存储在叶节点中。
  2. 每片叶子处于同一水平。
  3. 所有叶节点都有指向其他叶节点的链接。
  4. 这里有几个应用程序B + tree:

    1. 它减少了在树中查找元素所需的I / O操作数。
    2. 经常用于实现数据库索引。
    3. B +树的主要价值在于存储数据,以便在面向块的存储环境中进行有效检索 - 特别是文件系统。
    4. NTFS使用B +树进行目录索引。
    5. 基本上它有助于范围查询查找,最小化树遍历。