存储递归的结果

时间:2018-03-08 15:24:01

标签: python algorithm performance recursion

我有这个代码,它将打印列表的所有排列:

def permute(iterable,fixed=0):
    for i in range(fixed,len(iterable)):
        iterable[fixed:] = [iterable[i]] + iterable[fixed:i] + iterable[i+1:]
        if fixed==len(iterable)-1:
            print iterable
        permute(iterable,fixed+1)
        iterable[fixed:] = iterable[fixed+1:i+1] + [iterable[fixed]] + iterable[i+1:]

现在我想要返回此结果而不是打印它,我发现这样做的最好方法是将打印的内容存储在文件中,然后读取文件,提取数据并将其放入回到我返回的列表中:

import string
from random import *
import os

def randString(minLen=16,maxLen=32,charset=string.ascii_letters+string.digits):
    if(minLen>=maxLen):
        maxLen=minLen+1
    return "".join(choice(charset) for x in range(randint(minLen, maxLen)))

def permutations(iterable):
    def permute(iterable,f,fixed=0):
        for i in range(fixed,len(iterable)):
            iterable[fixed:] = [iterable[i]] + iterable[fixed:i] + iterable[i+1:]
            if fixed==len(iterable)-1:
                f.write(''.join(iterable)+" ")
            permute(iterable,f,fixed+1)
            iterable[fixed:] = iterable[fixed+1:i+1] + [iterable[fixed]] + iterable[i+1:]

    filename="."+randString()+".txt"
    f=open(filename,"w+")
    permute(list(iterable),f)
    f=open(filename,"r+")
    result=[]
    for i in f.read().split():
        result.append([])
        for j in i:
            result[-1].append(j)
    os.remove(filename)
    return result

问题是:这会使代码更长,并且至少慢3倍,因为我将所有排列存储在文件中,然后我必须再次遍历每个排列以将其存储回来列表。

我试图通过使用全局变量或通过将结果列表作为参数传递给函数来解决此问题,但它不起作用(因为递归)。

以下代码无效

列表作为参数

def permute2(iterable,fixed=0,permutations=[]):
    for i in range(fixed,len(iterable)):
        iterable[fixed:] = [iterable[i]] + iterable[fixed:i] + iterable[i+1:]
        if fixed==len(iterable)-1:
            return iterable
        permutation = permute2(iterable,fixed+1)
        if permutation:
            permutations.append(permutation)
        iterable[fixed:] = iterable[fixed+1:i+1] + [iterable[fixed]] + iterable[i+1:]
    return permutations

全局变量

第一

def permute(iterable,fixed=0):
    for i in range(fixed,len(iterable)):
        iterable[fixed:] = [iterable[i]] + iterable[fixed:i] + iterable[i+1:]
        if fixed==len(iterable)-1:
            global perms
            perms.append(iterable)
        permute(iterable,fixed+1)
        iterable[fixed:] = iterable[fixed+1:i+1] + [iterable[fixed]] + iterable[i+1:]

def permutations(iterable):
    global perms
    perms=[]
    permute(list(iterable))
    return perms

第二

def permute(iterable,fixed=0):
    for i in range(fixed,len(iterable)):
        iterable[fixed:] = [iterable[i]] + iterable[fixed:i] + iterable[i+1:]
        if fixed==len(iterable)-1:
            addPermutation(iterable)
        permute(iterable,fixed+1)
        iterable[fixed:] = iterable[fixed+1:i+1] + [iterable[fixed]] + iterable[i+1:]

def addPermutation(item):
    addPermutation.perms.append(item)

def permutations(iterable):
    addPermutation.perms=[]
    permute(list(iterable))
    return addPermutation.perms

这三个坏代码几乎都做同样的事情:它们返回一个包含n的列表!第一次排列的时间。

有没有办法解决这个问题,或者我是否必须使用该文件的代码?

编辑:在@DavidKemp和@ uwain12345的评论之后,我尝试使用了一个类。

def permutations(iterable):
    class Permut:
        def __init__(self, iterable):
            self.iterable = list(iterable)
            self.permutations = []
            self.permute()

        def permute(self,fixed=0):
            for i in range(fixed,len(self.iterable)):
                self.iterable[fixed:] = [self.iterable[i]] + self.iterable[fixed:i] + self.iterable[i+1:]
                if fixed==len(self.iterable)-1:
                    self.permutations.append(self.iterable)
                self.permute(fixed+1)
                self.iterable[fixed:] = self.iterable[fixed+1:i+1] + [self.iterable[fixed]] + self.iterable[i+1:]

    p = Permut(list(iterable))
    return p.permutations

但是我仍然得到与上述代码完全相同的结果(n!第一次排列的次数)。

2 个答案:

答案 0 :(得分:2)

你的问题是改变列表iterable是一个糟糕的策略。对iterbale所做的更改将始终得到反映,因为它们都是相同的对象。如果我们使用元组代替,我们可以避免这种情况。这是我提出的递归排列代码:

def permute(iterable):
    iterable = tuple(iterable)
    if len(iterable) <= 1:
        yield iterable
        return
    for i, x in enumerate(iterable):
        for sub_permutation in permute(iterable[:i] + iterable[i+1:]):
            yield (x,) +  sub_permutation

答案 1 :(得分:1)

除非这是一项练习,否则我建议您遵循Patrick Haugh的建议并使用itertools.permutations。但是,如果您仍然坚持自己滚动而不是print,请使用yield关键字:

def permute(iterable, fixed=0):
    for i in range(fixed,len(iterable)):
        iterable[fixed:] = [iterable[i]] + iterable[fixed:i] + iterable[i+1:]
        if fixed==len(iterable)-1:
            yield iterable
        for e in permute(iterable,fixed+1):
            yield e
        iterable[fixed:] = iterable[fixed+1:i+1] + [iterable[fixed]] + iterable[i+1:]

# Test out
for e in permute(['a', 'b', 'c']):
    print(e)

输出:

['a', 'b', 'c']
['a', 'c', 'b']
['b', 'a', 'c']
['b', 'c', 'a']
['c', 'a', 'b']
['c', 'b', 'a']

注释

  • yield语句将&#34;返回&#34;一次一个项目,但不退出该功能。这个函数返回一个生成器,所以请阅读Python生成器以了解更多信息。
  • 考虑以下块:

    for element in permute(iterable, fixed + 1):
        yield element
    

    如果您使用的是Python 3,则可以用

    替换该块
    yield from permute(iterable, fixed + 1)