有没有时间你不会使用递归?

我有一个大学实验室的问题;

编写一个简短的程序,输出通过使用字符’c’,’a’,’r’,’b’,’o’和’n’形成的所有可能的字符串。

这似乎是一个常见的面试问题,并有详细记录。

所以我使用递归方法用Java编写它并不太难, 何时或为什么你会选择不使用递归?最简单的方法是什么?

我开始编写一个计数器,该计数器将在基数6上倒数,然后输出将引用char并打印字符串。

谢谢,

是的,有很多次我不会使用递归。 递归不是免费的,它在堆栈空间中有成本,并且通常比其他一些资源更有限。 在设置和拆除堆栈帧时,还有一个时间成本,无论多么小。

举例来说,大肆吹嘘的因子函数是我可能选择迭代方法的函数,其中数字很大。 计算10000! 有:

def factorial (n): if n = 1 return 1 return n * factorial (n-1) 

将使用10,000个堆栈帧(假设编译器没有将其优化为迭代解决方案),相当多。 迭代解决方案:

 def factorial (n) r = 1 while n > 1: r = r * n n = n - 1 return r 

将只使用一个堆栈框架和其他珍贵的东西。

确实,递归解决方案通常是更优雅的代码,但您必须根据环境的限制来调整它。

你的carbon示例是我实际使用递归的例子,因为:

  • 它最多使用六个堆栈帧(字符串中每个字符一个); 和
  • 它相对优雅,至少远远超过六个嵌套循环和巨大的相等检查。

例如,以下Python代码可以解决这个问题:

 def recur (str, pref = ""): # Terminating condition. if str == "": print pref return # Rotate string so all letters get a chance to be first. for i in range (len (str)): recur (str[1:], pref + str[:1]) str = str[1:] + str[:1] recur ("abc") 

生产:

 abc acb bca bac cab cba 

当然,如果你的字符串长度可以是10K,我会重新考虑它,因为这会涉及更多的堆栈级别,但是,如果你保持足够低,递归是一个可行的解决方案。

只需使用循环,您将避免使用递归。 通常避免递归,因为它使代码不易读取并且难以维护和调试。 如果您的资源很少,因为paxdiablo说堆栈空间可能对您有价值,所以您也应该避免使用它。

当数据本质上是分层/嵌套时使用递归。 当数据是线性/平坦时使用迭代。

在您的情况下,您可以对组合施加自然顺序,因此您可以将数据视为线性,但如果将其视为树,则最终会采用递归方法。

如果算法的结构反映了底层问题的结构,那么最终会得到更易于理解的更简单的代码。 不要仅仅因为你的CS201教授认为它是如此使用递归! 凉!

Niklaus Wirth的算法和数据结构有一节“何时不使用递归”,但递归是程序员的有用工具。 我认为理解递归对于程序员来说是“必须的”。

你对排列问题有一个聪明的方法。 它可以递归地解决(伪代码):

 private void PermutationsRecursive(string prefix, string s) { int N = s.Length; if (N > 0) for (int i = 0; i < N; i++) PermutationsRecursive(prefix + s[i], s.Substring(0, i) + s.Substring(i + 1, N - i - 1)); else WriteLine(prefix); } PermutationsRecursive("", "carbon"); 

当有大量的递归调用时,你的堆栈可能会爆炸,让你得到StackOverflowError。 好的例子是计算Fibonacci数(或河内塔问题)的基本递归,你将无法计算其中许多数字。 您可以使用非经常性版本。 基本上递归会创建漂亮的解决方案,这是一种美德。 通过使用尾递归,您可能仍然可以获得良好的工作递归解决方案

正如上面的人写的那样,递归并不总是最佳解决方案(函数调用可能很昂贵并且它们会消耗堆栈,除非编译器可以优化尾递归)。 但是,它特别适合您的问题。

虽然理论上可以用迭代表示每个递归算法(例如通过用数组手动模拟调用堆栈),但有时候等效的迭代解决方案不那么优雅。 这是一个示例:

 text = 'carbon' n = len(text) for permutation_i in range(factorial(n)): free_letters = list(text) divisor = 1 for character_i in range(n, 0, -1): letter = free_letters.pop(permutation_i//divisor%character_i) print(letter, end='') divisor *= character_i print()