【问题标题】:mapping from one set to another从一组映射到另一组
【发布时间】:2012-08-17 12:32:16
【问题描述】:

我有一组连续的整数值和对应的一组非连续值,例如:

0 -> 22
1 -> 712
2 -> 53
3 -> 12323
...

等等。

项目数量非常庞大(大约为 10^9...10^10),因此不能只使用普通数组。

是否存在能够从第一个值快速映射到另一个具有中等内存需求的数据结构?例如:

ret = map(0); // returns 22
ret = map(3); // returns 12323

编辑:该集合中的值实际上是使用伪随机数生成器生成的,因此无法建议某些特定分布。问题是 - 是否可以降低内存要求(可能是以查找速度为代价)?我的意思是使用“完美哈希”之类的东西——生成这种“完美哈希”所需的时间并不重要。

【问题讨论】:

  • 在你的例子中,你的关系是 1;1,是现实还是这个例子的特征/
  • @High Performance Mark 是的,每个索引只有一个关联的值,因此仅由于内存需求,无法使用数组。
  • 您说的内存要求适中,但 10^10 int -> int 将在不压缩的情况下运行 100s GB。您能告诉我们有关数据集的其他信息吗?
  • 您可以将数组存储在文件中,这会减慢速度。坦率地说,我没有看到任何方法(除了压缩)将相同的数据放入内存中。
  • 如果第二组值是完全随机的,你怎么能比普通数组使用更少的内存?

标签: c algorithm data-structures


【解决方案1】:

由于您的范围是连续的,显而易见的解决方案是将您的值存储在一个连续的 int[] 中。那么值 i 是arr[i]。作为 PRNG 生成的值,将难以应用进一步的压缩。

另一种以时间换空间的解决方案是存储 RNG 的种子并即时重新计算。通过存储中间种子,这种方法可以及时改进,并在空间上恶化。 IE。密钥 1000、2000 等的种子。

【讨论】:

    【解决方案2】:

    您可以通过恰好使用每个值所需的位数来节省一些空间。例如,如果您的值只有 24 位,您可以在 32 位整数上保存一个字节。也就是说,您可以节省的内存只有这么多。

    在 64 位机器上,mmap() 一个文件到一个内存地址是可行的,从而以性能为代价通过使用磁盘存储来克服物理内存限制。

    但是,既然您提到使用伪随机生成器来生成值,那么仅存储特定索引的 RNG 种子并根据需要计算其余值怎么样?例如,您可以存储索引 0、100、200... 的种子并计算例如102 通过将 RNG 重新播种为 100 并调用生成器函数 3 次。

    这种方法会大大减少所需的内存(在本例中为 100),并且您可以通过捆绑或缓存查询来降低性能成本。

    【讨论】:

      【解决方案3】:

      如果您的函数范围是由伪随机数生成器按顺序生成的一组数字,那么您可以将序列压缩到生成序列的代码加上开始之前 PRNG 的状态.例如,包含 pi 的十进制扩展的(无限)数字系列很容易(并且在技术上是无限地)压缩为代码以生成该系列;您的系列可以被视为几乎相同的一个例子。

      因此,如果您愿意等待很长时间以获取系列中的最后一个元素,则可以通过将系列不写入数据结构而是写入函数来获得非常好的压缩。这是您的时间/空间权衡范围的一端。

      在频谱的另一端是所有数字的数组;这会占用大量空间,但可以非常快速地 (O(1)) 访问集合中的任何所需元素。出于各种原因,这似乎对您没有吸引力,但我不确定比数组更聪明的数据结构是否会节省大量空间,或者就此而言是否节省时间。

      我看到的一个明显的解决方案是每隔一段时间保存一组 PRNG 的中间状态,因此您的“数据”结构将变为:

      ret(0) = prng(seed, other_parameters, ...)
      ret(10^5-1)  = prng(seed', other_parameters, ...)
      ret(2*(10^5)-1) = prng(seed'', other_parameters, ...)
      

      等等。然后,要获取元素 9765,比方说,您读取(PRNG 的状态)ret(0),然后生成第 9765 个伪随机数。

      【讨论】:

        【解决方案4】:

        好的,所以我们的目的是用速度换取更少的内存使用。

        假设您有某种循环填充数组。

        int array[intendedArraySize];
        
        seed = 3;
        for (size_t z = 0; z < intendedArraySize; z++)
        {
             array[z] = some_int_psn_generator(seed);
        }
        

        之后您可以显示值。

        for (size_t z = 0; z < intendedArraySize; z++)
        {
            std::cout << z << " " << array[z] << std::endl;
        }
        

        如果确实如此,请考虑完全丢弃数组,只需每次重新计算值即可。

        for (size_t z = 0; z < intendedArraySize; z++)
        {
            std::cout << z << " " << some_int_psn_generator(z) << std::endl;
        }
        

        【讨论】:

          猜你喜欢
          • 2022-01-25
          • 2015-07-14
          • 2017-05-26
          • 2014-07-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-14
          • 1970-01-01
          相关资源
          最近更新 更多