递归的真实例子

red*_*ood 86 recursion

什么是现实世界的问题,其中一个递归的方法是除了深度优先搜索(DFS)的自然的解决方案?

(我不考虑河内塔,斐波纳契数或因子现实世界的问题.在我看来,它们有点做作.)

Han*_*son 105

一个真实的递归示例

一株向日葵

  • 由Matrix架构师用递归编码:) (9认同)
  • DNA或光线追踪.这是代码 (4认同)
  • 这递归怎么样?当然,它很漂亮.但是递归?分形卷心菜可以很好地工作,但我不认为这朵花有自相似之处. (2认同)
  • 好吧,这有点开玩笑,但它是叶序的一个例子,可以用斐波那契数列来描述,斐波那契数列通常通过递归实现。 (2认同)
  • “通常通过递归实现”并不一定意味着花会这样做。也许确实如此;作为分子生物学家,我还不够了解,但如果没有解释它是如何做到的,我认为这不是特别有用。投反对票。如果你想添加一个描述(无论它在生物学上是否准确,它可能会提供洞察力)伴随它,我很乐意重新考虑投票。 (2认同)

Mat*_*ard 64

如何涉及文件系统中的目录结构.递归查找文件,删除文件,创建目录等.

这是一个Java实现,以递归方式打印出目录及其子目录的内容.

import java.io.File;

public class DirectoryContentAnalyserOne implements DirectoryContentAnalyser {

    private static StringBuilder indentation = new StringBuilder();

    public static void main (String args [] ){
        // Here you pass the path to the directory to be scanned
        getDirectoryContent("C:\\DirOne\\DirTwo\\AndSoOn");
    }

    private static void getDirectoryContent(String filePath) {

        File currentDirOrFile = new File(filePath);

        if ( !currentDirOrFile.exists() ){
            return;
        }
        else if ( currentDirOrFile.isFile() ){
            System.out.println(indentation + currentDirOrFile.getName());
            return;
        }
        else{
            System.out.println("\n" + indentation + "|_" +currentDirOrFile.getName());
            indentation.append("   ");

            for ( String currentFileOrDirName : currentDirOrFile.list()){
                getPrivateDirectoryContent(currentDirOrFile + "\\" + currentFileOrDirName);
            }

            if (indentation.length() - 3 > 3 ){
                indentation.delete(indentation.length() - 3, indentation.length());
            }
        }       
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 深度优先搜索:dfs(node){foreach child in node {visit(child); }} (4认同)
  • 我没有得到首字母缩略词"DFS" - 我坐在教室里已经有一段时间了. (3认同)
  • 文件系统提供了动力(这很好,谢谢)但这是 DFS 的一个具体示例。 (2认同)

BCS*_*BCS 45

Quicksort,合并排序和大多数其他N-log N种类.


Ken*_*ric 32

这里有许多蹩脚的例子,但你想要一个真实世界的例子,所以想一想,这可能是我能提供的最好的:

你发现一个人患有特定的感染性疾病,这是非致命性的,并迅速自我修复(A型),除了五分之一的人(我们称之为B型),他们永久感染了它并且没有症状,仅仅是一个吊具.

当类型B感染多种类型A时,这会产生非常恼人的破坏性波浪.

你的任务是追踪所有类型的Bs并免疫它们以阻止疾病的中坚力量.不幸的是,你不能在全国范围内治疗所有人,因为那些类型的人对于治疗B型的治疗方法也是致命的过敏.

这样做的方式是社交发现,给予感染者(A型),在上周选择所有联系人,在堆上标记每个联系人.当您测试某人受感染时,请将其添加到"跟进"队列中.当一个人是B型时,将它们添加到头部的"跟进"(因为你想要快速停止).

处理完一个人后,从队列前面选择一个人,并根据需要进行免疫.获取以前未访问的所有联系人,然后测试他们是否被感染.

重复,直到受感染的人的队列变为0,然后等待另一次爆发..

(好吧,这有点迭代,但它是一种解决递归问题的迭代方法,在这种情况下,尝试发现可能的问题路径的群体基础的广泛首次遍历,此外,迭代解决方案通常更快,更有效,我强迫性地去除各地的递归,这本身就变得本能了.......该死的!)

  • 这个现实世界的例子现在感觉很熟悉:( (22认同)
  • 谢谢 - 这仍然是图形遍历,但它很有动力,对非程序员来说很有意义. (2认同)
  • 在 2020 年读到它真是太可怕了。它看起来像是一个预测,而不是答案。肯特描述的方式与covid19完全吻合。我们可以说中国是从这里得到这个想法的吗:P (2认同)

Cod*_*ous 16

Matt Dillard的榜样很好.更一般地,树的任何行走通常可以非常容易地通过递归来处理.例如,编译解析树,遍历XML或HTML等.


小智 16

递归通常用于回溯算法的实现中.对于这个"真实世界"的应用,一个数独求解器怎么样?


Sam*_*Sam 13

只要通过将问题分成子问题就可以解决问题,递归是合适的,这可以使用相同的算法来解决它们.树和排序列表上的算法是很自然的.计算几何(和3D游戏)中的许多问题可以使用二进制空间分区(BSP)树,脂肪细分或将世界划分为子部分的其他方式递归地求解.

当您尝试保证算法的正确性时,递归也是合适的.给定一个接受不可变输入的函数并返回一个结果,该结果是对输入的递归和非递归调用的组合,通常很容易使用数学归纳来证明函数是正确的(或不正确).使用迭代函数或可能变异的输入来执行此操作通常是难以处理的.在处理财务计算和其他正确性非常重要的应用程序时,这非常有用.


Mar*_*ote 11

当然很多编译器都会大量使用递归.计算机语言本身就具有递归性(即,您可以在其他'if'语句中嵌入'if'语句等).

  • John,你可以嵌套if语句这一事实意味着语言定义(可能是语言解析器)是递归的. (2认同)

chi*_*tza 9

禁用/设置容器控件中所有子控件的只读.我需要这样做,因为一些儿童控件本身就是容器.

public static void SetReadOnly(Control ctrl, bool readOnly)
{
    //set the control read only
    SetControlReadOnly(ctrl, readOnly);

    if (ctrl.Controls != null && ctrl.Controls.Count > 0)
    {
        //recursively loop through all child controls
        foreach (Control c in ctrl.Controls)
            SetReadOnly(c, readOnly);
    }
}
Run Code Online (Sandbox Code Playgroud)


jfs*_*jfs 8

来自SICP的着名评估/应用周期

替代文字
(来源:mit.edu)

以下是eval的定义:

(define (eval exp env)
  (cond ((self-evaluating? exp) exp)
        ((variable? exp) (lookup-variable-value exp env))
        ((quoted? exp) (text-of-quotation exp))
        ((assignment? exp) (eval-assignment exp env))
        ((definition? exp) (eval-definition exp env))
        ((if? exp) (eval-if exp env))
        ((lambda? exp)
         (make-procedure (lambda-parameters exp)
                         (lambda-body exp)
                         env))
        ((begin? exp) 
         (eval-sequence (begin-actions exp) env))
        ((cond? exp) (eval (cond->if exp) env))
        ((application? exp)
         (apply (eval (operator exp) env)
                (list-of-values (operands exp) env)))
        (else
         (error "Unknown expression type - EVAL" exp))))
Run Code Online (Sandbox Code Playgroud)

以下是apply的定义:

(define (apply procedure arguments)
  (cond ((primitive-procedure? procedure)
         (apply-primitive-procedure procedure arguments))
        ((compound-procedure? procedure)
         (eval-sequence
           (procedure-body procedure)
           (extend-environment
             (procedure-parameters procedure)
             arguments
             (procedure-environment procedure))))
        (else
         (error
          "Unknown procedure type - APPLY" procedure))))
Run Code Online (Sandbox Code Playgroud)

这是eval-sequence的定义:

(define (eval-sequence exps env)
  (cond ((last-exp? exps) (eval (first-exp exps) env))
        (else (eval (first-exp exps) env)
              (eval-sequence (rest-exps exps) env))))
Run Code Online (Sandbox Code Playgroud)

eval- > apply- > eval-sequence- >eval


Mar*_*ark 7

递归用于诸如BSP树之类的用于游戏开发(和其他类似区域)中的碰撞检测.


小智 7

人们通常使用递归方法对堆栈文档进行排序.例如,假设您正在对包含名称的100个文档进行排序.首先将文件放入第一个字母的堆中,然后对每个堆进行排序.

在字典中查找单词通常通过类似二进制搜索的技术来执行,该技术是递归的.

在组织中,老板经常向部门负责人发出命令,而部门负责人又向管理人员发出命令,等等.


dra*_*gon 7

我最近得到的现实世界要求:

要求 A:在彻底理解要求 A 后实现此功能。


Ste*_*ung 5

递归适用于可以将其分解(减少)为更小的部分的问题(情况),并且每个部分看起来与原始问题相似。

包含与其自身相似的较小部分的事物的好例子是:

  • 树结构(分支就像一棵树)
  • 列表(列表的一部分仍然是列表)
  • 容器(俄罗斯娃娃)
  • 序列(序列的一部分看起来像下一个)
  • 对象组(子组仍然是一组对象)

递归是一种不断将问题分解为越来越小的部分的技术,直到其中一个部分变得小到小菜一碟。当然,在分解它们之后,您必须以正确的顺序将结果“缝合”在一起,以形成原始问题的完整解决方案。

一些递归排序算法、树遍历算法、映射/归约算法、分而治之都是这种技术的示例。

在计算机编程中,大多数基于堆栈的调用返回类型语言已经具有内置的递归功能:即

  • 将问题分解为更小的部分==>在原始数据的较小子集上调用自身),
  • 跟踪各个部分是如何划分的 ==> 调用堆栈,
  • 将结果缝合回来 ==> 基于堆栈的返回


小智 5

层级组织中的反馈循环。

高层老板告诉高层管理人员收集公司每个人的反馈。

每位高管都会收集他/她的直接下属,并告诉他们从直接下属那里收集反馈。

并继续下去。

没有直接报告的人(树中的叶节点)会给出反馈。

反馈会返回到树上,每个经理都会添加他/她自己的反馈。

最终所有的反馈都会反馈给最高老板。

这是自然的解决方案,因为递归方法允许在每个级别进行过滤 - 整理重复项并删除令人反感的反馈。最高老板可以发送一封全局电子邮件,并让每个员工将反馈直接反馈给他/她,但存在“你无法处理真相”和“你被解雇”的问题,因此递归在这里效果最好。