递归排列生成器,交换列表项不起作用

时间:2011-04-09 00:47:21

标签: python recursion generator permutation

我想系统地生成字母表的排列。 我不能不想使用python itertools.permutation,因为预生成每个排列的列表会导致我的计算机崩溃(第一次我实际上让它强制关闭,它非常棒)。

因此,我的新方法是动态生成和测试每个密钥。目前,我试图通过递归来处理这个问题。

我的想法是从最大的列表开始(我将使用3个元素列表作为示例),递归到较小的列表,直到列表是两个元素长。然后,它将打印列表,交换最后两个,再次打印列表,然后返回一个级别并重复。

例如,对于123

  

123(与位置0交换位置0)

    23    --> 123 (swap position 1 with position 1)
    32    --> 132 (swap position 1 with position 2)
     

213(与位置1交换位置0)

    13    --> 213 (swap position 1 with position 1)
    31    --> 231 (swap position 1 with position 2)
     

321(与位置2交换位置0)

    21    --> 321 (swap position 1 with position 1)
    12    --> 312 (swap position 1 with position 2)

表示四个字母的数字(1234)

  

1234(交换位置0与位置0)

    234    (swap position 1 with position 1)

           34 --> 1234
           43 --> 1243
    324    (swap position 1 with position 2)
           24 --> 1324
           42 --> 1342
    432    (swap position 1 with position 3)
           32 --> 1432
           23 --> 1423
     

2134(位置1的交换位置0)           134(交换位置1与位置1)                  34 - > 2134                  43 - > 2143           314(交换位置1与位置2)                  14 - > 2314                  41 - > 2341           431(交换位置1与位置3)                  31 - > 2431                  13 - > 2413

这是我目前用于递归的代码,但它给我带来了很多的悲伤,递归不是我的强项。这就是我所拥有的。

def perm(x, y, key):
    print "Perm called: X=",x,", Y=",y,", key=",key
    while (x<y):

        print "\tLooping Inward"

        print "\t", x," ",y," ", key
        x=x+1
        key=perm(x, y, key)
        swap(x,y,key)
        print "\tAfter 'swap':",x," ",y," ", key, "\n"

    print "\nFull Depth Reached"
    #print key, " SWAPPED:? ",swap(x,y,key)
    print swap(x, y, key)
    print " X=",x,", Y=",y,", key=",key
    return key

def swap(x, y, key):
    v=key[x]
    key[x]=key[y]
    key[y]=v
    return key

非常感谢任何帮助,这是一个非常酷的项目,我不想放弃它。

感谢大家!欢迎评论我的方法或任何东西。

2 个答案:

答案 0 :(得分:1)

在我职业生涯的后期发生了我的旧问题

要有效地执行此操作,您需要编写生成器

不是返回所有排列的列表,而是要求将它们(所有这些)存储在内存中,生成器返回一个排列(此列表的一个元素),然后暂停,然后在你要求的时候计算下一个。

发电机的优点是:

  • 占用更少的空间。
    • 生成器占用40到80个字节的空间。一台发电机可以产生数百万件物品。
    • 包含一个项目的列表占用40个字节。包含1000个项目的列表占用4560字节
  • 效率更高
    • 仅根据需要计算多个值。在置换字母表时,如果在列表结尾之前找到了正确的排列,那么产生所有其他排列的时间就会浪费掉。

(Itertools.permutation是发电机的一个例子)

如何编写生成器?

在python中编写生成器实际上非常简单。
基本上,编写可用于生成排列列表的代码。现在,不要写resultList+=[ resultItem ],而是写yield(resultItem)

现在你已经制作了一台发电机。如果我想循环我的生成器,我可以写

for i in myGenerator:

就这么简单。


下面是我很久以前尝试写的代码的生成器:

def permutations(iterable, r=None):
    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    # permutations(range(3)) --> 012 021 102 120 201 210
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    if r > n:
        return
    indices = range(n)
    cycles = range(n, n-r, -1)
    yield tuple(pool[i] for i in indices[:r])
    while n:
        for i in reversed(range(r)):
            cycles[i] -= 1
            if cycles[i] == 0:
                indices[i:] = indices[i+1:] + indices[i:i+1]
                cycles[i] = n - i
            else:
                j = cycles[i]
                indices[i], indices[-j] = indices[-j], indices[i]
                yield tuple(pool[i] for i in indices[:r])
                break
        else:
            return

答案 1 :(得分:0)

我认为你有一个非常好的主意,但跟踪这些位置可能会有点难以处理。我看到递归生成排列的一般方法是一个函数,它接受两个字符串参数:一个用于从(str)中删除字符,另一个用于将字符添加到(soFar)。

在生成排列时,我们可以考虑从str中获取字符并将其添加到soFar。假设我们有一个函数perm,它接受​​这两个参数并找到str的所有排列。然后我们可以考虑当前字符串str。我们将从str中的每个字符开始排列,因此我们只需要循环str,将每个字符用作初始字符并在字符串中剩余的字符上调用perm:

// half python half pseudocode    
def perm(str, soFar):
    if(str == ""):
        print soFar // here we have a valid permutation
        return

    for i = 0 to str.length:
        next = soFar + str[i]
        remaining = str.substr(0, i) + str.substr(i+1)
        perm(remaining, next)