内存高效的电源设置算法

时间:2011-09-10 11:03:04

标签: algorithm language-agnostic recursion powerset

尝试计算9个字母的字符串'ABCDEFGHI'的所有子集(power set)。

使用标准递归方法,我的机器在完成之前会出现内存不足(1GB)错误。我没有更多的物理记忆。

如何做得更好?语言没有问题,发送到标准输出的结果也很好 - 在输出之前不需要全部保存在内存中。

4 个答案:

答案 0 :(得分:25)

从X = {A,B,C,D,E,F,G,H,I}的幂集到0到2 ^ | X |之间的数字集有一个简单的双射映射。 = 2 ^ 9:

Ø映射到000000000(基数2)

{A}映射到100000000(基数2)

{B}映射到010000000(基数2)

{C}映射到001000000(基数2)

...

{I}映射到000000001(基数2)

{A,B}映射到110000000(基数2)

{A,C}映射到101000000(基数2)

...

{A,B,C,D,E,F,G,H,I}映射到111111111(基数2)

你可以使用这个观察来创建像这样的幂集(伪代码):

Set powerset = new Set();
for(int i between 0 and 2^9)
{
  Set subset = new Set();
  for each enabled bit in i add the corresponding letter to subset
  add subset to powerset
}

通过这种方式,您可以避免任何递归(并且,根据您需要的powerset,您甚至可以“生成”powerset而无需分配许多数据结构 - 例如,如果您只需要打印出来电源组。)

答案 1 :(得分:1)

我会用分而治之的:

Set powerSet(Set set) {
  return merge(powerSet(Set leftHalf), powerSet(Set rightHalf));
}

merge(Set leftHalf, Set rightHalf) {
  return union(leftHalf, rightHalf, allPairwiseCombinations(leftHalf, rightHalf));
}

这样,你立即看到解决方案的数量是2 ^ | originalSet | - 这就是为什么它被称为"电源组"。在你的情况下,这将是2 ^ 9,因此1GB机器上不应该出现内存不足错误。我猜你的算法有一些错误。

答案 2 :(得分:1)

一个小方案解决方案

(define (power_set_iter set)
  (let loop ((res '(())) 
             (s    set ))
    (if (empty? s)
        res
        (loop (append (map (lambda (i) 
                             (cons (car s) i)) 
                           res) 
                      res) 
              (cdr s)))))

或者在R5RS Scheme中,更节省空间的版本

(define (pset s)
  (do ((r '(()))
       (s s (cdr s)))
      ((null? s) r)
    (for-each 
      (lambda (i) 
        (set! r (cons (cons (car s) i) 
                      r)))
      (reverse r))))

答案 3 :(得分:0)

我证实这很有效:

#include <iostream>

void print_combination(char* str, char* buffer, int len, int num, int pos)
{
  if(num == 0)
  {
    std::cout << buffer << std::endl;
    return;
  }

  for(int i = pos; i < len - num + 1; ++i)
  {
    buffer[num - 1] = str[i];
    print_combination(str, buffer, len, num - 1, i + 1);
  }
}

int main()
{
  char str[] = "ABCDEFGHI";
  char buffer[10];
  for(auto i = 1u; i <= sizeof(str); ++i)
  {
    buffer[i] = '\0';
    print_combination(str, buffer, 9, i, 0);
  }
}