精华内容
下载资源
问答
  • 栈与递归

    2019-10-06 08:31:43
    今天说的是栈与递归的关系,函数的递归调用和普通函数调用是一样的。当程序执行到某个函数时,将这个函数进行入栈操作,在入栈之前,通常需要完成三件事。  1、将所有的实参、返回地址等信息传递给被调函数保存。 ...

      今天说的是栈与递归的关系,函数的递归调用和普通函数调用是一样的。当程序执行到某个函数时,将这个函数进行入栈操作,在入栈之前,通常需要完成三件事。

      1、将所有的实参、返回地址等信息传递给被调函数保存。

      2、为被调函数的局部变量分配存储区。

      3、将控制转移到北调函数入口。

    当一个函数完成之后会进行出栈操作,出栈之前同样要完成三件事。

      1、保存被调函数的计算结果。

      2、释放被调函数的数据区。

      3、依照被调函数保存的返回地址将控制转移到调用函数。

    上述操作必须通过栈来实现,即将整个程序的运行空间安排在一个栈中。每当运行一个函数时,就在栈顶分配空间,函数退出后,释放这块空间。所以当前运行的函数一定在栈顶。

    (注:摘自严蔚敏等人的数据结构c语言版)

     

    接下来我们来观察一个简单的递归。

    #include <stdio.h>
    
    void recurrence(int num)
    {
        if ( num < 0 )
            return;
        printf("%d\n", num);
        recurrence(num - 1); 
       printf("%d\n", num);
    } int main(void) { recurrence(5); return 0; }

    程序每次运行到recurrence()函数时都会进入这个这个函数,直到num为0时返回,返回之后会接着运行recurrence()后面的代码,箭头代表函数控制权转移,请看图示。

    转载于:https://www.cnblogs.com/ITgaozy/p/5162889.html

    展开全文
  • java递归的关系

    2019-09-26 04:38:30
    最近看了Mark.Allen.Weiss算法数据结构,看到了里面讲述表、和和队列,结合最近工程用比较多的递归运算。所以这里讲一下递归  因为在年初时候看了《大话数据结构》(推荐看一下),这里先讲一下概念:...

      最近看了Mark.Allen.Weiss的算法与数据结构,看到了里面讲述的表、栈和和队列,结合最近工程用的比较多的递归运算。所以这里讲一下递归

      因为在年初的时候看了《大话数据结构》(推荐看一下),这里先讲一下概念:函数的递归调用和普通函数调用是一样的,当程序执行到某个函数时,将这个函数进行入栈操作,入栈之前主要做三件事

      1.把入参,返回地址等返回给被调用函数保存

      2.分配栈空间

      3.准备被调用

      出栈也一样:

      1.保存运算结果

      2.消除栈空间

      3.把运算结果放到栈空间出口

      所以递归这种存储某些数据,并在后面又以存储的逆序恢复这些数据,以提供之后使用的需求,显然很符合栈这样的数据结构,因此,编译器使用栈实现递归就没什么好惊讶的了。

      example:

      

      这种程序称为尾递归使用不当的例子。尾递归设计在最后一行的递归调用。尾递归可以通过讲代码放到一个while循环中并用每个方法参数的一次赋值代替递归调用而被手工删除。下面是去除递归之后的写法

     

      其实在代码运算的过程中,递归总总能够被彻底去除(编译器是在转变成汇编语言时完成递归去除的);但是这么做是相当冗长乏味的。一般方法要求使用一个栈,而且仅当你能够把最低限度的最小值放到栈上时这个方法才值得一用。

    转载于:https://www.cnblogs.com/stop-Word/p/7351621.html

    展开全文
  • 栈与递归的关系 一.递归 1.概念 什么是递归,就是高中数学上我们学的那个,递推式。当然,如果把一个递推公式用函数来表示,那么我们可以叫这个函数递归函数。递归函数是一个直接调用自己或通过一系列的语句简介地...

    一.递归

    1.概念

    什么是递归,就是高中数学上我们学的那个,递推式。当然,如果把一个递推公式用函数来表示,那么我们可以叫这个函数递归函数递归函数是一个直接调用自己或通过一系列的语句简介地调用自己的函数,称作递归函数。

    比如我们的阶乘函数:
    Fact(n)={1,n=0nFact(n1),n>0 Fact(n)=\left\{ \begin{aligned} 1,n=0\\ n\cdot Fact(n-1),n>0\\ \end{aligned} \right.
    亦或者我们比较熟悉的斐波那契数列:
    Fib(n)={0,n=01,n=1Fib(n1)Fib(n2),n>1 Fib(n)=\left\{ \begin{aligned} 0,n=0\\ 1,n=1\\ Fib(n-1)\cdot Fib(n-2),n>1\\ \end{aligned} \right.

    2.实现

    我们可以把那些常数项,叫做递归边界,比如阶乘的f(n)=1,n=0或者斐波那契数列的f(n)=0,n=0 ,f(n)=1,n=1

    那我们写段实现斐波那契数列的递归代码:

    int Fib(int n)
    {
        if (n == 0) return 0;
        else if (n == 1) return 1;
        else
        {
            return Fib(n-1) + Fib(n-2);
        }
    }
    
    int main()
    {
        printf("%d", Fib(10));
        return 0;
    }
    

    只要我们能写出递归的函数表达式,就可以写出它的递归函数。个人认为:递归边界是最重要的。如果递归边界没有处理好,那么递归的可能永远持续下去,然后爆栈而死。

    3.较难的递归分析——汉诺塔

    在这里插入图片描述

    汉诺塔的游戏规则就是:把A中的盘子移动到C盘子上,大盘子不能放在小盘子上。

    对于这个我们多试几次:

    1. n=1

      第1次 1号盘 A---->C

    2. n=2

      第1次 1号盘 A---->B

      第2次 2号盘 A---->C

      第3次 1号盘 B---->C

    3. n=3

      第1次 1号盘 A---->C

      第2次 2号盘 A---->B

      第3次 1号盘 C---->B

      第4次 3号盘 A---->C

      第5次 1号盘 B---->A

      第6次 2号盘 B---->C

      第7次 1号盘 A---->C

    如果我们用整体法的思想来看,如果把一堆盘子从A移动到C,那么我们可以把A柱子上的盘子看成两个整体,最下面的盘子和它上面的所有盘子。那么我们的过程就是:

    1. 上面所有的盘子从A到B
    2. 最下面的盘子从A到C
    3. 上面所有的盘子从B到C

    那么我们如何把最上面的盘子移动到B和C呢?那就把这部分盘子看成两部分,最下面一张盘子和上面所有的盘子。

    如果移动到B,那么C就是我们的辅助塔(因为游戏是从A移动到C,所以B是辅助塔),所以我们就对这上面的部分执行“A到B的汉诺塔操作”。

    反之,从B移动到C的话,A就是辅助塔,所以我们执行的是"B到C的焊诺特操作"

    开始套娃。直到最后我们只有一个盘子,那么狠显然,它执行“A到C的汉诺塔操作”且只有一块盘子,那就把它移动到C。

    那么我们的递归表达式就出来了:

    递归边界: n=1时 把1号盘子 A→C

    递归内容:①把n-1号盘子 A→B把n号盘子 A→C把n-1号盘子 B→C

    好了,代码实现一下:

    void hano(int n, char a, char b, char c)    // hano(n=有几个碟子,a=主塔,b=辅助塔,c=目标塔) 
    {
        if (n == 1) printf("No.%d  %c -> %c\n", 1, a, c);
        else
        {
            hano(n - 1, a, c, b);   // 这里是A to B的操作,C是辅助塔
            printf("No.%d  %c -> %c\n", n, a, c);
            hano(n - 1, b, a, c); // 这里是B to C的操作,A是辅助塔
        }
        
    }
    
    int main()
    {
        hano(3, 'A', 'B', 'C'); // 这里是A to C的操作
        return 0;
    }
    

    二.栈与递归的关系

    在高级语言中,如果需要调用(这是动词)函数,那么调用(名词)函数被调用函数之间的链接与信息交换需要通过内部的栈进行。

    在运行被调用函数之前,系统会完成三件事:

    1. 把所有的实参、返回地址等信息传递给被调用函数保存。
    2. 为被调用函数的局部变量分配储存区
    3. 将控制转移到被调用函数的入口。

    然后在被调用函数返回调用函数之前,我们也要完成三件事:

    1. 保存被调函数的计算结果
    2. 释放被调用函数的数据区
    3. 依照被调用函数保存的返回地址将控制转移到调用函数。

    假设我们像递归这样成嵌套的调用时,那么先调用的函数肯定要最后返回,所以在编译器的内部,是通过栈的方式为我们保存这些关系与信息。

    所以我们的递归之间的信息传递需要使用到栈,幸好编译器会帮我们管理递归工作栈,所以我们只需要好好考虑递归边界和递归的内容就可以啦!

    展开全文
  • 递归 不得不说“故事”

    千次阅读 2020-01-19 10:26:45
    文章目录基本思想广义递归狭义递归递归与栈的紧密关系从基本思想来说从函数栈的使用角度说栈与递归的实际功用 基本思想 把规模较大的一个问题,分解成规模较小的多个子问题去解决,而每一个子问题又可以继续拆分成...

    基本思想

    • 把规模较大的一个问题,分解成规模较小的多个子问题去解决,而每一个子问题又可以继续拆分成多个更小的子问题。
    • 递归解决的是有依赖关系的多个问题:必须先解决最小子问题,在层层递进的方式解决当前问题

    广义递归

    void main(){
        A();
    }
    
    func_A()
    {
    func_B();
    }
    
    func_B()
    {
    func_C();
    }
    
    func_C()
    {
     .....//代码块儿
    }
    

    具体过程:

    • 调用函数A;
    • 调用函数B;
    • 调用函数C;
    • 函数C返回;
    • 函数B返回;
    • 函数A返回;

    狭义递归

    void main(){
        A();
    }
    
    func_A(int i)
    {
     if(i == 1) return 1;
     return A(i-1)+1;
    }
    
    

    具体过程:
    当 i = 3 时,函数 A 被调用了三次,与广义递归中的调用,从某种形式上看一致。
    我们把函数内调用函数自身的形式,称为狭义递归

    递归与栈的紧密关系

    从基本思想来说

    • 从递归的基本思想及对问题的处理顺序来看,是遵循着 “先开始的问题,最后结束” 的规律
    • 栈对数据的操作,即是 “先进后出”,两者不谋而合了

    从函数栈的使用角度说

        void dfs(int a0, int a1, ....){
            {
                //代码块儿 0;
            }
            
            dfs(a00, a11, ...);
    
            {
                //代码块儿 1;
            }
        }
    

    执行过程如下:
    在这里插入图片描述

    整体的递归过程
    (以代码被执行的第一视角来看:)
    1、执行代码块儿0
    2、保存当前情景进入下一层
    3、接受下层返回的数据
    4、恢复情景
    5、继续执行代码块儿1

    栈的实际使用
    第 2,4 步骤,都是编译器在完成,及在前行阶段,对于每一层递归,函数的局部变量、参数值以及返回地址都被压入栈中。在回退阶段,位于栈顶的局部变量、参数值和返回地址被弹出,用于返回调用层次中执行代码的其余部分(恢复了调用的状态)。

    栈与递归的实际功用

    (1)浏览器的撤回功能
    不管什么浏览器都有一个“后退”键,你点击后可以按访问顺序的逆序加载浏览过的网页。即使你从第一个网页开始,连续点了几十个链接跳转,你点“后退”时,还是可以像历史倒退一样,回到之前浏览过的某个页面

    (2)函数的调用

    int main() {
      a();
      return 0;
    }
    
    void a() {
      b();
    }
    
    void b() {
      c();
    }
    
    void c() {
    }
    
    main()  a()  b()  c()
       -                         main()
       |
       +>     -                    a()
       .      |
       .      +>   -                 b()
       .      .    |
       .      .    +>   -              c()
       .      .    .    |
       .      .    +   <-              return from c()
       .      .    |
       .      +   <-                 return from b()
       .      |
       +     <-                    return from a()
       |
       -                         return from main()
    

    函数的调用有完美的嵌套关系——调用者的生命期总是长于被调用者的生命期,并且后者在前者的之内。这样,被调用者的局部信息所占空间的分配总是后于调用者的(后入),而其释放则总是先于调用者的(先出),所以正好可以满足栈的LIFO顺序,选用栈这种数据结构来实现调用栈是一种很自然的选择。
    参考:-- https://www.zhihu.com/question/34499262

    (3)递归转成非递归调用
    举例:二叉树的非递归遍历
    在这里插入图片描述

    待完成:…

    展开全文
  • 递归与栈的关系

    2019-05-20 10:58:00
    递归与栈的关系: 可是为何执行了900多次就出错了呢?还说超过了最大递归深度现在,为什么要限制呢? 通俗来讲,是因为每个函数在调自己的时候还没有退出,占内存,多了肯定会导致内存崩溃。 本质上讲呢,在...
  • 专题四-栈与递归

    2017-02-06 09:50:52
    栈与递归 C语言中疑惑 小A:C语言常说局部变量在栈上分配空间,那么这个地方栈和我们之前学习栈数据结构有关系吗? 小B:我觉得应该没有关系吧,只是名称碰巧一致而已吧。 函数调用栈 (1)程序中“函数...
  • 数据-第18课-栈与递归

    2019-09-29 15:37:32
    第18课-栈与递归 C语言中疑惑 讨论中…… 小A:C语言中常说“局部变量在栈上分配空间”,那么这个地方“栈”和我们之前学习栈数据结构有关系吗? 小B:我觉得应该没关系吧 :我觉得应该没关系吧,只是...
  • 数据结构—栈与递归

    2019-07-03 09:20:54
    1.递归的基本思想 所谓递归,就是有去有回。 递归的基本思想,是把规模较大的一个问题,分解成规模较小的多个子问题去解决,而每一个子问题又可以继续拆分成多个更小的子问题。 最重要的一点就是假设子问题已经...
  • 本节主要说程序中的函数栈的关系以及递归算法的关系。 一、函数调用时的 1.程序调用时的是也就是平时所说的函数是数据结构的一种应用,函数调用一般是从搞地质向低地址增长的,栈顶为内存的低地址,...
  • 函数递归与栈的关系

    2015-09-14 00:58:00
    首先通过反汇编语言,我们来了解一下最简单的递归函数与栈之间的关系。 如何获得反汇编语言,在visual studio 2008中,在debug环境下,在debug/windows/disassembly中可以查看反汇编之后的语言。现在我们看一下阶乘...
  • 今天博主复习了一下栈与递归的知识,做了计蒜客平台的一章习题。下面贴出来和大家交流分享。如有不正之处,请求指教。 蒜头君吃桃 题目描述 思路分析 设第i天还剩下g(n)个桃子 那么第i-1天还剩下g(n-1)个桃子。 根据...
  • 【九】栈与递归--程序栈空间

    千次阅读 2015-05-27 20:54:26
    1、C语言中疑惑C语言中常说“局部变量在上分配空间”,那么这个地方”和我们之前学习的栈数据结构有关系吗?解答: 保存局部变量的栈是函数调用时的栈; 程序中“函数调用”是数据结构一种应用; ...
  • 先遍历后输出,与栈的先进后出特性一样,所以考虑用压栈出栈来解决。 先用非递归算法,比较简单,代码如下;public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { // 方法一:非递归,利用...
  • 递归每执行一次都会释放一次函数 setjmp 记录函数栈的栈顶 longjmp 寻找函数栈的栈顶 如果longjmp找到了他要寻找函数栈顶 调用setjmp函数不会被释放 所以setjmp 和 longjmp 也会形成死循环,所以要严格控制...
  • 理解递归的本质:递归与栈

    万次阅读 多人点赞 2018-04-11 09:34:08
    递归的基本思想所谓递归,就是有去有回。递归的基本思想,是把规模较大的一个问题,分解成规模较小的多个子问题去解决,而每一个子问题又可以继续拆分成多个更小的子问题。最重要的一点就是假设子问题已经解决了,...
  • 递归与栈

    2015-05-04 08:16:11
    函数递归与栈的关系 2011-11-12 21:07 922人阅读 评论(0) 收藏 举报 汇编语言db2stringblogc 首先通过反汇编语言,我们来了解一下最简单的递归函数与栈之间的关系。 如何获得反汇编语言,在visual...
  • DFS,回溯与递归的关系

    2019-12-19 11:23:54
    首先DFS叫做深度优先搜索,...那么DFS过程中,你要退一步,就必然需要保存你走过每个点所有信息,而且是又先后顺序,符合后进先出规则,那么就需要用一个,而递归过程中函数调用会自动产生栈帧,当你的栈...
  • 递归与循环、

    2019-10-03 14:16:26
    递归循环的共同点:同一计算...递归与栈的关系 因为程序中的结构是顺序,因此,如果递归的次数过多,程序中的数据过大,在不断的压栈过程中造成空间耗尽而产生溢出。 递归可以使用转化为循环。 ...
  • 递归将大型复杂问题转化为原问题相同但规模较小问题进行处理。(找递推关系式 )递归需要有边界条件: 当不满足边界条件时,递归继续进行 当满足边界条件时,递归停止 递归函数要一直走到一个临界...
  • public class 递归与栈 { public static void Recursion(int num) { if(num<1) return; System.out.println(num); //递 Recursion(num-1); System.out.println(num); //归 return; } p

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 369
精华内容 147
关键字:

栈与递归的关系