一尘不染

高效的数据结构,用于存储长序列(大多数是连续的)整数

algorithm

我想要一种数据结构来有效地存储一长串数字。数字应该始终是整数,比方说Longs。

我想利用(声称“效率”)输入的特征是多头将 大部分是 连续的。可能缺少值。并且这些值可以不按顺序交互。

我希望数据结构支持以下操作:

  • addVal(n):添加一个值n
  • addRange(n,m):将n和m之间的所有值相加,包括
  • delVal(n):删除单个值n
  • delRange(n,m):删除n和m之间的所有值,包括
  • containsVal(n):返回结构中是否存在单个值n
  • containsRange(n,m):返回结构中是否存在n和m之间的所有值(包括)

从本质上讲,这是一种更特定的Set数据结构,可以利用数据的连续性来使用少于O(n)的内存,其中n是存储的值的数量。

需要明确的是,尽管我认为有效地实现这种数据结构将需要我们在内部存储间隔,这对于用户而言是不可见的或不相关的。有一些间隔树分别存储多个间隔,并允许操作查找与给定点或间隔重叠的间隔数。但是从用户的角度来看,它的行为应完全类似于集合(基于范围的操作除外,因此可以有效地处理批量添加和删除操作)。

例:

dataStructure = ...
dataStructure.addRange(1,100) // [(1, 100)]
dataStructure.addRange(200,300) // [(1, 100), (200, 300)]
dataStructure.addVal(199) // [(1, 100), (199, 300)]
dataStructure.delRange(50,250) // [(1, 49), (251, 300)]

我的假设是最好通过某些基于树的结构来实现,但是我对如何做到这一点还没有很好的印象。我想了解是否存在一些已经满足此用例的常用数据结构,因为我不想重蹈覆辙。如果没有,我想听听您如何认为最好的实施方式。


阅读 243

收藏
2020-07-28

共1个答案

一尘不染

如果您不关心重复项,那么您的间隔是不重叠的。您需要创建一个维护该不变性的结构。如果您需要类似numIntervalsContaining(n)的查询,那就是另一个问题。

您可以使用BST来存储一对端点,就像在C
++中一样std::set<std::pair<long,long>>。解释是每个条目对应于间隔[n,m]。您需要弱排序-
这是左端点上通常的整数排序。单个intlong
n插入作为[n,n]。我们必须维护所有节点间隔都不重叠的属性。对操作顺序的简要评估如下。既然您已经指定了,n我将使用N树的大小。

  • addVal(n):添加单个值n:,O(log N)与a相同std::set<int>。由于间隔是不重叠的,因此您需要找到的前任n,可以及时完成O(log n)(按https://www.quora.com/How-can-you-find-successors-和前辈按顺序进行二进制搜索树)。查看此前任节点的右端点,并根据需要延长间隔或添加其他节点[n,n],按照左端点顺序,该节点始终是正确的子节点。请注意,如果间隔被扩展(插入[n+1,n+1]树中,其中节点[a,n]构成节点[a,n+1]),它现在可能会碰到下一个左端点,因此需要再次合并。因此,需要考虑一些边缘情况。比简单的BST稍微复杂一点,但仍然如此O(log N)

  • addRange(n,m):,O(log N)过程类似。如果插入的间隔与另一个间隔不平凡,请合并间隔,以保持非重叠属性。O(n)下面指出的是最坏情况下的性能,因为我们要插入的子间隔所消耗的子间隔数没有上限。

  • delVal(n):,这O(log N)也是O(n)最坏的情况,因为我们不知道要删除的间隔中包含多少个间隔。

  • delRange(n,m):删除n和m之间的所有值,包括: O(log N)
  • containsVal(n):返回结构中是否存在单个值n: O(log N)
  • containsRange(n,m):返回结构中是否存在n和m之间的所有值(包括端点): O(log N)

请注意,我们可以使用正确的add()和addRange()方法维护非重叠属性,而delete方法已经维护了该属性。我们需要O(n)在最坏的情况下进行存储。

请注意,所有的操作都O(log N)和插入的范围[n,m]是不一样O(m-n)O(log(m-n))之类的东西。

我假设您不在乎重复项,而只是会员资格。否则,您可能需要间隔树或KD树或其他东西,但它们与浮点数据更相关…

2020-07-28