使用O(1)访问将数字范围映射到单个元素

时间:2011-12-15 06:37:31

标签: data-structures mapping range big-o

问题很简单,我想将每个从0到N-1的数字映射到多个元素K< N这样: 1,2,3,...,i-1映射到元素1 i,i + 1,i + 2,...,i + k-1映射到元素2 ......等等 i + k + ... + z,i + k + ... + z + 1,i + k + ... + z + 2,...,N-1映射到元素K

注意:i,j,k,...,z是不同的值(否则我不会使用不同的字母:))。

有没有办法让结构和函数f(i)在时间O(1)中返回相应的元素占用合理的空间? (N个元素的向量,每个元素来自指向它所影响的元素的范围,不是合理的空间量)

我可以想到B树会给我一个O(log(n))访问时间,但我很好奇是否有O(1)有效的解决方案。

提前致谢!

布鲁诺

2 个答案:

答案 0 :(得分:2)

如果你的i,k,...,z是任意的,那么没有时间约束为O(1)且合理空间约束为< O(N)浮现在脑海中。如果你的界限有规律性,那么当然你可以使用它:例如如果每个范围包含偶数个元素,那么一个简单的解决方案就是使用[i_N / 2]来获取查找表。在一般情况下,您需要为您的数字0 ... N提供匹配的折叠函数 - 满足约束k-mapping(i)!= k-mapping(i + 1)=>折叠函数(i)!=折叠函数(i + 1)。

如果频繁访问地图中的某些元素,您还可以为映射构建缓存,导致缓存命中情况下的O(1)和缓存未命中的O(查找函数)。当然,缓存查找会影响每个元素花费的时间,即使在缓存未命中的情况下也是如此,但它不会影响算法的O复杂性。

修改

基本上,您要实现的内容可以表示为Pascal case语句,其中sets为标签:

case n of 
0..i-1:
  value:=0;
i..i+k-1:
  value:=1;
// ...
i+k+...+z+2..N-1:
  value:=K;
end

对于这个问题,谷歌搜索确实发现了一篇有趣的论文:

  

本文描述了一种构建静态搜索树的新方案,   使用多路基数搜索树。 [...]我们表明,对于稀疏案例   集合,该方法产生的平均代码比现有代码更快   方法,要求 O (1)时间与平均值的小常数   搜索范围。

     

Erlingsson,Krishnamoorthy,Raman Lucid and Efficient Case Analysis

唉,你没有稀疏的案例集,但据我所知,算法应该只需要对具有大量连续结果的密集案例集进行最小的自适应。

对于为case语句创建高效代码的一般问题,Zhao和Amarla有一个interesting paper that uses profiling来实现类似于使用缓存的东西。他们的论文对于相关工作部分也很有意思,它引用了一篇来自 Kannan和Proebsting 校正为案例陈述生成良好代码。)的论文,它需要一个O. (n ^ 2)群集的设置时间。但是,我没有访问这篇论文,听起来这只会产生一个极其优化的搜索树,因此导致O(log(n))的运行时间。

答案 1 :(得分:0)

如果我正确理解了这个问题,你应该可以使用div mod直接计算映射。 (见explanation of operators in C

例如在python中

def my_map(n,k,i):
  elements_per_bin = n/k if n%k is 0 else n/k + 1  #in case n is exactly divisible by k
  return i/elements_per_bin    

例如,设n = 10,k = 3

>>> n=10
>>> k=3
>>> def f(i):
      return my_map(n,k,i)
>>> range(n)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> map(f,range(n))
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2]

所以{0,1,2,3} - > 0,{4,5,6,7} - > 1等等。

我假设你已经拥有了内存中原始数组/数据结构的数据。您现在应该能够通过从映射计算数组索引来索引它(可能需要构建my_map的反函数)。

索引的计算是O(1),您只使用原始数组中的空格。


很抱歉,如果我误解了映射。