3

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

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

我想将此列表的所有可能排列存储在 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 个内存)。

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

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

4

3 回答 3

3

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

例如(如果您需要迭代排列):

-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

于 2012-01-04T09:01:58.783 回答
1

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

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

很抱歉不知道 Erlang,但我在 Scala 中编写了一个函数式算法,它允许以可重现的方式产生任意大小的排列。

例如,数字 (1 到 12) 的第 123456790 次排列是 List (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))}}
于 2012-01-23T09:31:54.330 回答
0

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

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

于 2012-01-04T07:50:28.713 回答