递归是如何用栈来实现的?

前言

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

概念介绍

栈的基本概念和原理我们已在“文章链接”中做过具体说明,下面我们主要讲讲递归算法

  1. 什么是递归?
  • 百度百科上的解释如下:程序调用自身的编程技巧称为递归;
  • 一般来说,递归需要有边界条件、递归前进段和递归返回段。
  • 当边界条件满足时,递归返回;当递归条件不满足时,递归前进;
  • 递归的目的通常是把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
  1. 递归的通俗解释
  • 可能你看了递归的定义后还是不明白,那就举个例子说明下:孔夫子说“三十而立”,你看了可能就在想这个“立”是什么意思?那你就继续搜索“立”字的解释,你发现孔夫子又说过“立于礼”,“不知礼,无以立也”;那你又不知道“礼”是什么意思;那只好继续搜索“礼”字的含义,等你弄明白了什么是“礼”,那你就知道什么是“立”,自然而然你就知道什么是“三十而立”了
    在这里插入图片描述

原理讲解

讲解递归的原理那我们首先要搞明白递归和栈的关系。我们以如下代码为例:

int Factorial(int n)
{
    if (0 == n)
    {
        return 1;
    }

    int value = n * Factorial(n-1);

    qDebug() << "n:" << n << " value:" << value;
    return value;
}

Factorial(5);

递归和栈的关系

递归过程分为两步“递”和“归”,对应着栈的两种操作“进栈”和“出栈”。

  1. 当n=5时,满足递归条件,执行进栈操作,具体效果入下图
    在这里插入图片描述
  2. 当n=4时,满足递归条件,执行进栈操作,具体效果入下图
    在这里插入图片描述
  3. 当n=3时,满足递归条件,执行进栈操作,具体效果入下图
    在这里插入图片描述
  4. 当n=2时,满足递归条件,执行进栈操作,具体效果入下图
    在这里插入图片描述
  5. 当n=1时,满足递归条件,执行进栈操作,具体效果入下图
    在这里插入图片描述
  6. 当n=0时,不满足递归条件,开始执行第一次出栈操作,将Factorial(1)的结果1返回,具体效果入下图
    在这里插入图片描述
  7. 继续执行第二次出栈操作,将Factorial(2)的结果1*Factorial(1)=2返回,具体效果入下图
    在这里插入图片描述
  8. 继续执行第三次出栈操作,将Factorial(3)的结果3*Factorial(2)=6返回,具体效果入下图
    在这里插入图片描述
  9. 继续执行第四次出栈操作,将Factorial(4)的结果4*Factorial(3)=24返回,具体效果入下图
    在这里插入图片描述
  10. 继续执行第五次出栈操作,将Factorial(5)的结果5*Factorial(4)=120返回,具体效果入下图
    在这里插入图片描述

至此Factorial(5)递归结束

递归的优缺点

  • 优点
    • 代码简洁
    • 便于理解
  • 缺点
    • 时间和空间消耗大
    • 可能存在栈溢出
    • 可能存在重复计算

递归的应用场景

  • 问题的定义就是按照递归来定义的
    • 阶乘
    • Fibonacci函数
  • 问题的解决方法是递归的
    • 汉诺塔问题
  • 问题涉及的数据结构是递归的
    • 树的遍历
    • 树的深度

更多算法学习请关注我的公众号

在这里插入图片描述

说明

  • 在公众号中回复“算法源码”即可获取十大经典算法源码
  • 在公众号中回复“算法书籍”即可获取经典入门算法书籍
  • 在公众号中回复“数据结构”即可获取数据结构相关源码
  • 47
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
二叉树的非递归遍历一般使用栈实现。以下是 C 语言实现二叉树非递归遍历的示例代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }; // 定义结构 struct Stack { struct TreeNode *data[MAX_SIZE]; int top; }; // 初始化 void initStack(struct Stack *s) { s->top = -1; } // 判断是否为空 int isEmpty(struct Stack *s) { return s->top == -1; } // 判断是否已满 int isFull(struct Stack *s) { return s->top == MAX_SIZE - 1; } // 入 void push(struct Stack *s, struct TreeNode *node) { if (isFull(s)) { printf("Stack is full.\n"); return; } s->top++; s->data[s->top] = node; } // 出 struct TreeNode *pop(struct Stack *s) { if (isEmpty(s)) { printf("Stack is empty.\n"); return NULL; } struct TreeNode *node = s->data[s->top]; s->top--; return node; } // 二叉树非递归前序遍历 void preorderTraversal(struct TreeNode *root) { if (root == NULL) { return; } struct Stack s; initStack(&s); push(&s, root); while (!isEmpty(&s)) { struct TreeNode *node = pop(&s); printf("%d ", node->val); if (node->right != NULL) { push(&s, node->right); } if (node->left != NULL) { push(&s, node->left); } } } // 二叉树非递归中序遍历 void inorderTraversal(struct TreeNode *root) { if (root == NULL) { return; } struct Stack s; initStack(&s); struct TreeNode *node = root; while (node != NULL || !isEmpty(&s)) { while (node != NULL) { push(&s, node); node = node->left; } node = pop(&s); printf("%d ", node->val); node = node->right; } } // 二叉树非递归后序遍历 void postorderTraversal(struct TreeNode *root) { if (root == NULL) { return; } struct Stack s; initStack(&s); struct TreeNode *node = root; struct TreeNode *lastVisit = NULL; while (node != NULL || !isEmpty(&s)) { while (node != NULL) { push(&s, node); node = node->left; } node = s.data[s.top]; if (node->right == NULL || node->right == lastVisit) { printf("%d ", node->val); lastVisit = node; node = NULL; pop(&s); } else { node = node->right; } } } int main() { struct TreeNode *root = (struct TreeNode *) malloc(sizeof(struct TreeNode)); struct TreeNode *left = (struct TreeNode *) malloc(sizeof(struct TreeNode)); struct TreeNode *right = (struct TreeNode *) malloc(sizeof(struct TreeNode)); root->val = 1; root->left = left; root->right = right; left->val = 2; left->left = NULL; left->right = NULL; right->val = 3; right->left = NULL; right->right = NULL; printf("前序遍历结果:"); preorderTraversal(root); printf("\n中序遍历结果:"); inorderTraversal(root); printf("\n后序遍历结果:"); postorderTraversal(root); return 0; } ``` 这里实现了二叉树的非递归前序、中序和后序遍历。需要注意的是,后序遍历的实现比较复杂,需要设置一个 lastVisit 指针来记录上一个访问的结点,以保证不重复访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值