如何重写递归函数来代替使用循环?

时间:2011-03-16 18:49:55

标签: python loops recursion permutation

这个堆栈溢出线程声称每个递归函数都可以写成循环。

Which recursive functions cannot be rewritten using loops?

这完全合情合理。但我不确定如何将以下递归函数表示为循环,因为它具有预递归逻辑和后递归逻辑。

显然解决方案不能使用goto语句。代码在这里:

def gen_perms(lst, k, m):

    if k == m:
        all_perms.append(list(lst))
    else:
        for i in xrange(k, m+1):

            #swap char
            tmp = lst[k]
            lst[k] = lst[i]
            lst[i] = tmp

            gen_perms(lst, k+1, m)

            #swap char
            tmp = lst[k]
            lst[k] = lst[i]
            lst[i] = tmp

调用它将是这样的:

all_perms = []
gen_perm([1, 2, 3], 0, 2)

并生成列表1,2,3的每个排列。

3 个答案:

答案 0 :(得分:3)

进行排列的最pythonic方法是使用:

>>> from itertools import permutations
>>> permutations([1,2,3])
>>> list(permutations([1,2,3]))
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

答案 1 :(得分:1)

假设你想要找到[1,2,3,4]的所有排列。这些中有24(= 4!),所以将它们编号为0-23。我们想要的是一种非递归的方法来找到第N个排列。

假设我们按照递增的数字顺序对排列进行排序。然后:

  • 排列0-5从1开始
  • 排列6-11从2开始
  • 排列12-17以3
  • 开头
  • 排列18-23以4
  • 开头

因此,我们可以通过将N除以6(= 3!)得到第一个排列数N,然后向上舍入。

我们如何获得下一个号码?查看排列0-5中的第二个数字:

  • 排列0-1的第二个数字为2。
  • 排列2-3具有第二个数字3。
  • 排列4-5有第二个数字4。

我们在排列6-11中看到类似的事情:

  • 排列6-7有第二个数字。
  • 排列8-9有第二个数字3。
  • 排列10-11的第二个数字为4.

一般情况下,先将除以6后的余数除以2(= 2!),然后向上舍入。这给你1,2或3,第二项是列表中剩下的第1,第2或第3项(在你取出第一项后)。

你可以继续这样做。以下是一些代码:

from math import factorial

def gen_perms(lst):
    all_perms = []

    # Find the number of permutations.
    num_perms = factorial(len(lst))

    for i in range(num_perms):
        # Generate the ith permutation.
        perm = []
        remainder = i

        # Clone the list so we can remove items from it as we
        # add them to our permutation.
        items = lst[:]

        # Pick out each item in turn.
        for j in range(len(lst) - 1):
            # Divide the remainder at the previous step by the
            # next factorial down, to get the item number.
            divisor = factorial(len(lst) - j - 1)
            item_num = remainder / divisor

            # Add the item to the permutation, and remove it
            # from the list of available items.
            perm.append(items[item_num])
            items.remove(items[item_num])

            # Take the remainder for the next step.
            remainder = remainder % divisor

        # Only one item left - add it to the permutation.
        perm.append(items[0])

        # Add the permutation to the list.
        all_perms.append(perm)

    return all_perms

答案 2 :(得分:0)

我对python语法不太熟悉,但是下面的代码(在'c'中)不应该太难翻译,假设python可以嵌套语句。

int list[3]={1,2,3};
int i,j,k;

for(i=0;i < SIZE;i++)
for(j=0;j < SIZE;j++)
for(k=0;k < SIZE;k++)
if(i!=j && j!=k && i!=k)
printf("%d%d%d\n",list[i],list[j],list[k]);