有没有什么时候你不会使用递归?

发布于 2024-09-24 10:31:50 字数 275 浏览 1 评论 0原文

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

输出一次使用字符“c”、“a”、“r”、“b”、“o”和“n”形成的所有可能的字符串。

编写一个简短的程序,仅 是一个常见的面试问题并且有据可查。

因此,我使用 Java 使用递归方法对其进行了编码,这并不太难,什么时候或为什么选择不使用递归以及最简单的方法是什么?

我开始编写一个以 6 为底数的计数器,然后输出将引用 char 并打印字符串。

谢谢,

I have a problem for a university lab;

Write a short program that outputs all possible strings formed by using characters ‘c’, ‘a’, ‘r’, ‘b’, ‘o’, and ‘n’ exactly once.

It seems to be a common interview question and well documented.

So I've coded it with Java using a recursive method which wasn't too hard, when or why would you choose not to use recursion and what would be the easiest way of doing it?

I started to code a counter that would count down on base 6, the output would then reference char's and print the string.

Thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

掩饰不了的爱 2024-10-01 10:31:50

是的,很多时候我不会使用递归。递归不是免费的,它会消耗堆栈空间,并且与其他资源相比,这通常是更有限的资源。设置和拆除堆栈框架也会产生时间成本,无论时间成本有多小。

举例来说,在备受推崇的阶乘函数中,当数字很大时,我可能会选择迭代方法。计算10000!使用Python:

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

将尝试使用多达10,000个堆栈帧(尽管Python会保护你免受这种情况的影响)。等效的迭代解决方案:

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长,我会重新考虑它,因为这会涉及更多的堆栈级别,但是,只要你保持足够低的水平,递归就是一个可行的解决方案。

Yes, there are plenty of times I would not use recursion. Recursion is not free, it has a cost in stack space and that can often be a much more limited resource than some others. There's also a time cost, however small, in setting up and tearing down stack frames.

By way of example, the much vaunted factorial function is one where I would probably opt for an iterative approach where the numbers were large. Calculating 10000! with the Python:

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

will attempt to use a whopping 10,000 stack frames (though Python will protect you against this). The equivalent iterative solution:

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

will use just the one stack frame and precious little else.

It's true that recursive solutions are often more elegant code but you have to temper that with the limitations of your environment.

Your carbon example is one where I would actually use recursion since:

  • it uses at most six stack frames (one per character in the string); and
  • it's relatively elegant, at least much more so than six nested loops and huge equality checks.

For example the following Python code does the trick:

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")

producing:

abc
acb
bca
bac
cab
cba

Of course, if your string can be 10K long, I'd rethink it, since that would involve a lot more stack levels but, provided you keep in low enough, recursion is a viable solution.

长途伴 2024-10-01 10:31:50

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

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

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

Use recursion when your data is inherently hierarchical/nested. Use iteration when your data is linear/flat.

In your case, there is a natural ordering you can impose on the combinations, so you can treat the data as linear, but if you view it as a tree you end up with the recursive approach.

If the structure of your algorithm reflects the structure of the underlying problem, you end up with simpler code that is easier to understand. Don't use recursion just because your CS201 professor thought it was So! Cool!

后eg是否自 2024-10-01 10:31:50

只需使用循环即可避免使用递归。通常要避免递归,因为它会降低代码的可读性并且更难以维护和调试。如果你的资源很少,正如 paxdiablo 所说,堆栈空间可能对你很有价值,所以你也应该避免使用它。

Just use a loop and you will avoid using recursion. Recursion is avoided generally because it makes the code less readable and harder to maintain and debug. If you have low resources as paxdiablo said stack space might be valuable for you so you should avoid using it then too.

耳钉梦 2024-10-01 10:31:50

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");

Algorithms and Data Structures by Niklaus Wirth have a section "When not to use recursion", but recursion is useful programmer`s tool. I think that understanding recursion is "must" for a programmer.

You have a clever approach to permutation problem. It can be solved recursively (pseudocode):

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");
任谁 2024-10-01 10:31:50

当有大量递归调用时,您的堆栈可能会爆炸,从而导致 StackOverflowError。一个很好的例子是使用基本的斐波那契数(或河内塔问题)计算
递归你将无法计算其中的许多数字。您可以通过使用非重复版本来实现。基本上,递归创建了漂亮的解决方案,这是一个优点。通过使用尾递归,您仍然可以拥有良好的递归解决方案

When there is plenty of invocations of recursion then your stack may explode leaving you with StackOverflowError. The good example is calculation of Fibonacci numbers (or Hanoi towers problem) with basic
recursion you will not be able to calculate many of those numbers. Which you will be able by using of non recurring version. Basically recursion creates nice looking solution and this is a virtue. You may still have good working recursion solution by using tail recursion

无人问我粥可暖 2024-10-01 10:31:50

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

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


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()

As the people above have written, recursion is not always the optimal solution (function calls may be expensive and they consume the stack unless the compiler can optimize tail recursion away). However, it's particularly suited to such problems as yours.

While theoretically it's possible to express each recursive algorithm in terms of iteration (ex. by manually simulating the call stack with an array), sometimes the equivalent iterative solution is less elegant. Here is a sample:


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()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文