文章目录
一. 思维导图
二. 栈的概念
1. 定义
- 栈(stack)只允许在一端进行插入和删除操作的线性表
- 或者说是一种可以实现“先进后出”的存储结构
- 栈是一种操作受限的线性表
2. 栈的内存分配
内存分配方式理解:栈和堆不同
#include <stdio.h>
#include <malloc.h>
{
void f(int k){
int m;
double * p = (double *)malloc (200);
}
int main(void){
int i = 10;
int * p = (int *)malloc(100);
return 0;
}
}
-
m,q,i,p变量是栈分配
静态分配(由OS分配)压栈出栈 或局部变量分配
-
200,100存储是堆分配
动态分配(程序员手动分配) 堆排序方式分配内存
3. 栈的分类
(1). 顺序栈(静态栈)
-
类似数组
(2). 链栈(动态栈)
- 类似链表
三. 栈的存储结构
1. 顺序栈
(1). 定义
- 采用顺序存储结构(用一组地址连续的存储单元存放栈底到栈顶的元素)
(2). 顺序栈的数据结构表示
(3). 顺序栈的基本操作
(4). 顺序栈的特例(共享栈)
定义
- 两个栈的栈底分别设置在共享空间的两端,栈顶向共享空间的中间延伸,共享一个一维数组空间
共享栈的算法基本操作
放代码
2. 链栈
(1). 定义
- 采用链式存储的栈,一般采用单链表实现
优点:
- 便于多个栈共享存储空间和提高效率,不存在栈满上溢
(2). 链栈数据结构表示
(3). 链栈算法的操作
https://gitee.com/zhiqiang99/data-structure/blob/master/Stack/stack.cpp
-
栈的基本操作
2. 初始化一个栈
3. 压栈
4. 遍历栈
四. 栈的应用
1. 函数调用
2. 中断
3. 表达式求值
4. 缓冲处理
5. 走迷宫
6. 括号匹配
7. 递归中的应用
7.1 概述
递归定义:
- 一个函数自己直接或间接调用自己
不同函数之间的相互调用
一个函数自己调用自己
7.2 递归的本质
递归满足三个条件:
- 递归必须得有一个明确的中止条件
- 该函数所处理的数据规模必须在递减(值可以增加)
- 这个转换必须是可解的
循环和递归的关系
- 理论上所有的循环都可转换成递归(方法很多:基本上是一个数学问题)
- 但用递归解决的问题用循环不一定能解决
递归的特点:
- 优点:易于理解
- 缺点:速度慢,存储空间大
循环的特点:
- 缺点:不易理解
- 优点:速度快,存储空间小
7.3 常用递归算法
-
阶乘的循环实现
https://gitee.com/zhiqiang99/data-structure/blob/master/Stack/Recursion/Factorial_circle.cpp -
递归实现求阶乘功能
https://gitee.com/zhiqiang99/data-structure/blob/master/Stack/Recursion/Factorial_recursion.cpp -
计算1-100的和,使用递归来实现
https://gitee.com/zhiqiang99/data-structure/blob/master/Stack/Recursion/1_100_sum.cpp -
汉诺塔实现
https://gitee.com/zhiqiang99/data-structure/blob/master/Stack/Recursion/Hanoi.cpp
7.4 递归的应用
计算机特别适合用递归的思想解决问题,但是我们人类用递归思想来考虑问题就会感到十分困难,对计算机而言,一个函数调用别的函数与调用它自己是没有区别的。对机器而言,递归和普通函数的调用没有区别,都是借用堆栈把函数的返回地址,函数的局部变量,调用函数的实参压栈。但对人而言,自己调用自己,觉得不可思议,应该陷入死循环才对嘛
递归思想是软件思想的最基本思想之一,在树和图论上面,几乎全是用递归来实现的。最简单的,大家用的资源管理器,我要求无之尽的创建用户目录。这实际上就是动态构造树的问题,要用到递归的知识来解决。
- 树和森林就是以递归的方式定义的(易理解,若不用递归将非常难实现)
- 树和图的很多算法都是以递归来实现的
- 很多数学公式就是以递归的方式定义的(斐波那契数列)
未完待续…