【问题标题】:Recursive Permutation Generator, swapping list items not working递归排列生成器,交换列表项不起作用
【发布时间】:2011-04-09 00:47:20
【问题描述】:

我想系统地生成字母表的排列。 我不能不想使用 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(将位置 0 与位置 1 交换)

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

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

    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(将位置 0 交换为位置 1) 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

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

谢谢大家!欢迎对我的方法或任何内容发表评论。

【问题讨论】:

  • 首先,除非您做错了,否则 itertools 不会预先生成列表。其次,它是坏了还是你只是想要更好的代码?如果您正在寻找更好的代码,您只需在 codereview.stackexchange.com 上发布代码以供审核
  • 我会在那里修改和转发,谢谢
  • 第二温斯顿·尤尔特; itertools.permutations 不会预先生成所有排列,据我所知,这正是您所需要的。也许您尝试执行诸如打印所有结果之类的操作,或者将它们粘贴在一个列表中,这导致它必须全部生成它们才能满足请求?
  • 只有在可行的情况下才这样做。该站点用于改进工作代码而不是修复损坏的代码。从您的帖子中我不清楚代码是否损坏。如果是,您需要在此网站上明确说明它与您的预期有何不同。

标签: python recursion generator permutation


【解决方案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

【讨论】:

    【解决方案2】:

    我认为您的想法非常好,但是跟踪位置可能有点难以处理。我见过的递归生成排列的一般方法是一个函数,它接受两个字符串参数:一个从 (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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-23
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 2018-11-06
      • 1970-01-01
      • 2016-04-19
      相关资源
      最近更新 更多