【问题标题】:Relevance of recursion递归的相关性
【发布时间】:2011-08-17 02:30:20
【问题描述】:

所以我目前正在尝试掌握递归的概念,并且我了解我遇到的大部分问题,但我觉得它的使用似乎不适用于太多的计算问题。这只是一个新手的假设,所以我问,作为程序员,递归有很多实际用途吗?还有,它可以解决哪些典型问题?我见过的唯一问题是堆排序和脑筋急转弯类型的问题,例如“河内塔似乎非常具体且缺乏广泛用途。

谢谢

【问题讨论】:

  • 其实,正确理解的“河内塔”并不特别,但用途非常广泛。解决问题的一个技巧是让一个问题看起来像另一个问题——尤其是你知道如何解决的问题。导航树结构(如在数据库中,或者可能是编译器可能构建的词汇树)很像导航河内塔,解决方案与它有很多相似之处。
  • stackoverflow.com/questions/5859571/relevance-of-recursion 的可能重复项(抱歉,开玩笑)

标签: language-agnostic recursion


【解决方案1】:

有几种语言不支持循环(即for和while),因此当您需要重复行为时,您需要使用递归(我相信J没有循环)。在许多示例中,递归需要 少的代码。比如我写了一个isPrime方法,只用了两行代码。

public static boolean isPrime(int n) { return n!=1&&isPrime(n,2); }

public static boolean isPrime(int n,int c) { return c==n||n%c!=0&&isPrime(n,c+1); }

迭代解决方案需要更多代码:

public static boolean isPrime(int n)
{
    if(n==1) return false;
    int c=2;
    while(c!=n)
    {
        if(n%c==0) return false;
    }
    return true;
}

另一个很好的例子是当您使用 ListNodes 时,例如,如果您想检查 ListNode 中的所有元素是否相同,递归解决方案会容易得多。

public static <E> boolean allSame(ListNode<E> list)
    {
        return list.getNext()==null||list.getValue().equals(list.getNext().getValue())&&allSame(list.getNext());
    }

迭代解决方案如下所示:

public static <E> boolean allSame(ListNode<E> list)
{
    while(list.getNext()!=null)
    {
        if(!list.getValue().equals(list)) return false;
        list=list.getNext();
    }
    return true;
}

如您所见,在大多数情况下,递归解决方案比迭代解决方案要短。

【讨论】:

    【解决方案2】:

    以下是一些没有递归几乎不可能的字段:

    • XML、HTML 或任何其他树状文档结构
    • 编译和解析
    • 自然语言处理
    • Divide and conquer algorithms
    • 许多数学概念,例如阶乘

    递归可以为原本复杂的问题带来非常优雅的解决方案。如果您对将编程作为一门艺术感兴趣,那么您真的应该更深入地研究。

    哦,如果您不确定,这里是递归的可靠定义:

    递归(名词):参见“递归”

    【讨论】:

      【解决方案3】:

      调用递归,作为一种程序结构,几乎不应该使用,除非在您期望编译器将其优化为不同结构的极高级语言中。调用递归的使用,除非您可以在深度上建立较小的界限,否则会导致 堆栈溢出,而不是为您回答问题的那种好的堆栈溢出。 :-)

      另一方面,递归作为算法概念非常有用。它是处理任何递归定义的数据格式(如 HTML 或 XML,或分层文件系统)以及在搜索、排序和(每个人都喜欢的)图形渲染等无数其他领域中实现重要算法的关键。

      【讨论】:

        【解决方案4】:

        如果您检查列出的与此问题“相关”的问题,您会发现“过多”的关于递归的内容可以帮助您更好地理解它。

        递归并不是什么新鲜事物,它也不仅仅是一个玩具概念。递归算法早在计算机出现之前就已经存在了。

        “阶乘”的经典定义就是一个很好的例子:

        fact(x) =
        if x < 0 then fact(x) is undefined
        if x = 0 then fact(0) = 1
        if x > 0 then fact(x) = x * fact(x-1)
        

        这不是计算机极客创造的东西,他们认为递归是一个很酷的玩具。这是标准的数学定义。

        【讨论】:

          【解决方案5】:

          我想这取决于你要做什么。作为一名从事企业网络工作的 C#/ASP.NET 开发人员,我每年可能编写不到一个递归函数。当我在搞乱我的爱好代码(主要是统计研究)时,我发现了更多应用递归的机会。部分原因是主题,部分原因是我更依赖于客户在进行公司工作时已经决定的 3rd 方库(实现需要递归的算法)。

          【讨论】:

          • 嗯,是的,谢谢。其实我对递归有非常扎实的理解,我的说法是站得住脚的。
          • 你处理XML之类的东西吗?你处理数据库吗? XML 有一个非常递归的定义,而数据库,尤其是那些具有自身链接的表的数据库,是递归解决方案的主要问题。
          • 为负面的言论道歉。我只是在很长一段时间内一直在计算,并且我将大部分时间都花在教育新手上,让他们了解学校不再很好教的东西。
          【解决方案6】:

          这不是你每天都在使用的东西。但是许多关于搜索和排序数据的算法都可以利用它。一般来说,大多数递归算法也可以使用迭代来编写;递归版本通常更简单。

          【讨论】:

          • 尝试编写一个非递归的“河内塔”解决方案,这将向您展示递归是多么简单。
          • @Zeke:如果我没记错的话,实际上有一个非常简单和优雅的非递归算法。我认为有人在试图理解它时在 SO 上发布了一个关于它的问题。
          • 是的,看这里:stackoverflow.com/questions/2209860/… 比递归简单得多。
          【解决方案7】:

          递归在编程中有很多用途 - 一个典型的例子是导航树结构,您可以在发现每个子元素的情况下调用导航函数,等等。

          【讨论】:

            猜你喜欢
            • 2020-11-08
            • 2015-01-29
            • 1970-01-01
            • 2019-12-11
            • 1970-01-01
            • 2012-03-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多