【问题标题】:How to effectively store a large set of permutations?如何有效地存储大量排列?
【发布时间】:2012-02-01 19:03:40
【问题描述】:

假设我们有一个元素列表:

[{dog,1},{dog,2},{cat,1},{cat,2},{bird,1},{bird,2},...]

我想将此列表中所有可能的permutations 存储在 RAM 中。

由于列表可能很长(10 个或更多元素),存储它需要大量空间(阶乘 N)。

例如,如果我有一个列表,它消耗大约 70 字节的空间并且有 12 个元素,那么我需要12! * 70 ~ 31 GB。如果我在列表中再添加一个元素,那么将排列存储在 RAM 中可能会变得不可行。

有没有比下面的 Erlang 表示更有效的表示来将所有排列保留在内存中?

[{dog,1},{dog,2},{cat,1},{cat,2},{bird,1},{bird,2},...]

(我知道原子dog在原子表中只存储一次,但由于它在每个排列中都重复,因此需要N个内存)。

也许这些排列可以以某种字节表示形式存储? (对不起,我是字节和二进制的新手)。

毕竟只是相同的元素,只是以不同的方式重新排列。

【问题讨论】:

    标签: erlang permutation ram data-representation


    【解决方案1】:

    为什么不懒惰地生产它们呢?从每个列表中保留一个索引,当被要求提供一个新元素时,您可以即时生成组合。这样,您只需要随时将源元素的初始列表和索引存储在内存中。

    例如(如果您需要遍历排列):

    -record(perm, {list_a, list_b, index_a, index_b}).
    

    每次达到index_b 的最大值时,将其重置为0 并将index_a 加一。然后,访问列表的第 N 个元素(其中 N 是索引),您可以重新创建任何排列实例。

    当然,这意味着每次产生排列时都必须遍历列表。为避免这种情况,您可以将列表本身用作索引:

    -record(perm2, {list_a, list_b, list_b_orig}).
    

    要生成下一个排列,从list_b 弹出新元素并将其附加到list_a 的头部。如果list_b 为空,则删除list_a 的头部并通过将list_b 设置为保存在list_b_orig 中的原始值重新开始。

    【讨论】:

    • 亚当,您能否详细说明您的答案?以我有限的知识,我只知道我应该有一个(DB?矩阵?)表,其中包含行中的所有唯一列表元素和列中的所有排列。相应的单元格应存储特定列表(排列)中特定元素的确切索引(位置编号)。我相信你的回答意味着一个更优雅的解决方案。
    • 查看更新后的帖子。关键是永远不要一次完全创建所有排列。
    • 很抱歉我是个新手,但我不明白应该如何使用您提供的记录结构。我应该在 list_a 和 list_b 中存储什么?是 Erlang 列表数据类型的 index_a 和 index_b 还是其他?
    • 好吧,我主要是想说明,您需要跟踪当前所在的排列是单个元素的列表和指出列表中位置的索引(一个数字) .
    【解决方案2】:

    如果你有一个包含 N 个元素的列表,那么就有 N 个!排列。因此,如果我们能够生成从数字 1 到 N 的映射! (或 0 到 N!-1)以可重现的方式对这些排列进行排序,我们不需要存储 N!元素列表,但只有 N!数字。

    但是停止 - 我们为什么要存储 N!数字?我们不需要存储它们,因为它们不会改变。我们只需要上限,它由最大元素索引定义,即 N,它应该已经存储在您的代码中。

    很抱歉不知道 Erlang,但 I wrote a functional algorithm in Scala 允许以可重现的方式产生任意大小的排列。

    例如,数字(1 到 12)的第 123456790 个排列是列表(4、2、1、5、12、7、10、8、11、9、3、6)。

    作为一个特殊的好处,这个算法以排序的方式产生排列。只是以可复制的方式找到所有排列但没有顺序更简单:

    def permutationIndex (idx: Int, list: List [Int]) : List [Int] = {
      if (list.isEmpty) list else {
        val el = list (idx % list.size) 
        el :: permutationIndex (idx / list.size, list.remove (_ == el))}}
    

    【讨论】:

      【解决方案3】:

      也许压缩它可以完成这项工作?

      Zlib 模块似乎做了这样的事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-06
        • 2015-11-09
        • 1970-01-01
        • 1970-01-01
        • 2017-04-09
        • 2011-01-25
        • 2011-06-26
        • 2011-02-06
        相关资源
        最近更新 更多