【数据结构&算法】08-栈概念&源码
前言
李柱明博客:https://www.cnblogs.com/lizhuming/p/15487342.html
栈的定义
定义
栈(stack)是限定仅在表尾进行插入和删除操作的线性表。
- 栈首先是一个线性表,栈元素具有线性关系。为特殊的线性表。
- 栈顶(top):允许插入和删除的一端称为栈顶。
- 栈底(bottom):另一端称为栈底。
- 表尾指的是栈顶,而不是栈底。
- 空栈:不含任何数据元素的栈称为空栈。
- LIFO:last in first out,栈又称为后进先出的线性表,简称 LIFO 结构。
- 栈的插入操作:进栈,也称压栈、入栈。
- 栈的删除操作:出栈,也称弹栈。
- 用数组实现的栈叫做:顺序栈
- 用链表实现的栈叫做:链式栈

小笔记:
内存中的堆栈和数据结构堆栈不是一个概念:
内存中的堆栈是真实存在的物理区。内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区。
- 代码区 :存储方法体的二进制代码。高级调度(作业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换。
- 静态数据区 :存储全局变量、静态变量、常量,常量包括 final 修饰的常量和 String 常量。系统自动分配和回收。
- 栈区 :存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。例如 int method(int a){int b;}栈中存储参数 a、局部变量 b、返回值 temp。
- 堆区 :new 一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。由程序员分配和回收。
数据结构中的堆栈是抽象的数据存储结构。
- 栈 :是一种连续存储的数据结构,特点是存储的数据先进后出。
- 堆 :是一棵完全二叉树结构,特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等。
常见应用
栈相对于数组和链表来说只有限制,是操作受限的线性表。从功能上,数组和链表也可以代替栈,但是数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,自然也就更容易出错。
栈的常见应用
- 软件中的撤销(undo)操作,浏览器历史纪录,Android 中的最近任务,Activity 的启动模式,CPU 中栈的实现,Word 自动保存,解析计算式,解析 xml/json。
进栈出栈变化形式
出栈序列个数公式:卡特兰公式:C(2n,n)/(n+1)
- n 为前几个数时的值:1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796 ...
栈的抽象数据类型
栈为线性表,具备线性表的操作特性。
对于栈来说,插入和删除改名为 push 和 pop。
- 压
- 弹
栈的顺序存储结构及实现
栈的顺序存储结构
顺序栈
- 栈的顺序存储也是线性表顺序存储的简化,简称为顺序栈。
- 在数组中,用下标为 0 的一段作为栈底。
- 栈顶 top:若存储栈长度为 stack_size,则 top 必须少于 stack_size。
- 空栈:栈中有一个元素时,top=0。空栈时,top = -1。
顺序栈的结构定义
- 指针式
// 指针式
typedef int se_type; /* 元素类型 */
typedef struct
{
se_type *top; /* 栈顶指针 */
se_type *bottom; /* 栈底指针 */
se_type stack_size; /* 栈的最大容量 */
}stack_t;
- 数组式
// 数组式
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
int top; /* 栈顶指针 */
se_type data[STACK_SIZE]; /* 栈空间 */
}stack_t;
两栈共享空间

两栈共享空间:
原理:两个栈底分别位于数组的始端(下标 0)和数组的末端(下标数组长度 n-1),增加元素即从两端点向中间延伸。
条件:两个具有相同数据类型的栈,生长方向相反。
满栈判断:
- 一般情况:两个栈见面之时,即两个指针相差 1,
top1+1 == top2时。 - 极端情况:stack_2 空时,top1=n-1,则 stack_1 满;stack_1 空,top2=0,则 stack_2 满。
- 一般情况:两个栈见面之时,即两个指针相差 1,
部分代码实现
// 数组式
/* 两栈共享空间结构 */
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
int top1; /* 栈顶指针 */
int top2; /* 栈顶指针 */
se_type data[STACK_SIZE]; /* 栈空间 */
}stack_double_t;
/**
* @name stack_double_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_double_t *stack_double_creat(void)
{
stack_t *stack_double_ptr = NULL;
stack_double_ptr = (stack_double_t *)malloc(sizeof(stack_double_t));
if(stack_double_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_double_t));
stack_double_ptr->top1 = -1;
stack_double_ptr->top2 = STACK_SIZE;
return stack_double_ptr;
}
/**
* @name stack_double_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_double_destroy(stack_double_t *stack)
{
if(stack != NULL)
{
free(stack);
return 0;
}
return -1;
}
栈的链式存储结构及实现
栈的链式存储结构
就是基于链表实现的栈。
栈的链式存储结构:
- 栈的链式存储结构,简称链栈。
- 栈顶放在单链表的头部,且不需要头结点。(自主决定)
- 空栈:链表原定义为头指针指向空,故链栈的空是 top = NULL。
- 结构:
/* 链式结构 */
typedef int se_type; /* 元素类型 */
typedef struct stack_node
{
se_type date;
struct stack_node *next;
}stack_node_t;
typedef struct
{
int count;
stack_node_t *top;
}stack_link_t;
栈的应用之递归
递归的定义:
- 把一个直接调用自己或者通过一系列的调用语句间接地调用自己的函数,称为递归函数。
- 每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出。(出口条件)
递归与栈结构:
- 递归进入时,压栈。
- 递归退出时,出栈。
代码实现
指针式顺序栈操作
/** @file stack.c
* @brief 简要说明
* @details 详细说明
* @author lzm
* @date 2021-09-06 09:42:22
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
**********************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 指针式
typedef int se_type; /* 元素类型 */
typedef struct
{
se_type *top; /* 栈顶指针 */
se_type *bottom; /* 栈底指针 */
se_type stack_size; /* 栈的最大容量,元素个数。 */
}stack_pointer_t;
/**
* @name stack_pointer_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_pointer_t *stack_pointer_creat(int size)
{
stack_pointer_t *stack_ptr = NULL;
stack_ptr = (stack_pointer_t *)malloc(sizeof(stack_pointer_t));
if(stack_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_pointer_t));
stack_ptr->bottom = (se_type *)malloc(size * sizeof(se_type));
if(stack_ptr->bottom == NULL)
{
free(stack_ptr);
return NULL;
}
memset(stack_ptr->bottom, 0x00, size * sizeof(se_type));
stack_ptr->top = stack_ptr->bottom;
stack_ptr->stack_size = size;
return stack_ptr;
}
/**
* @name stack_pointer_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_destroy(stack_pointer_t *stack)
{
if(stack != NULL)
{
if(stack->bottom != NULL)
free(stack->bottom);
free(stack);
return 0;
}
return -1;
}
/**
* @name stack_pointer_clear
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_clear(stack_pointer_t *stack)
{
if(stack == NULL)
return -1;
stack->top = stack->bottom;
return 0;
}
/**
* @name stack_pointer_empty
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_empty(stack_pointer_t *stack)
{
if(stack == NULL)
return -1;
if(stack->top == stack->bottom)
return 1;
return 0;
}
/**
* @name stack_pointer_full
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_full(stack_pointer_t *stack)
{
if(stack == NULL)
return -1;
if(stack->top == (stack->bottom + stack->stack_size * sizeof(se_type)))
return 1;
return 0;
}
/**
* @name stack_pointer_length
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_length(stack_pointer_t *stack)
{
if(stack == NULL)
return -1;
return (stack->top - stack->bottom)/sizeof(se_type);
}
/**
* @name stack_pointer_push
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_push(stack_pointer_t *stack, se_type elem)
{
if(stack_pointer_full(stack) != 0)
return -1;
*stack->top = elem;
stack->top += sizeof(se_type);
return 0;
}
/**
* @name stack_pointer_pop
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_pop(stack_pointer_t *stack, se_type *elem)
{
if(stack_pointer_empty(stack) != 0)
{
elem = NULL;
return -1;
}
stack->top -= sizeof(se_type);
elem = stack->top;
return 0;
}
int main(void)
{
;
}
数组式顺序栈操作
/** @file stack.c
* @brief 简要说明
* @details 详细说明
* @author lzm
* @date 2021-09-06 09:42:22
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
**********************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 数组式
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
int top; /* 栈顶指针 */
se_type data[STACK_SIZE]; /* 栈空间 */
}stack_t;
/**
* @name stack_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_t *stack_array_creat(void)
{
stack_t *stack_ptr = NULL;
stack_ptr = (stack_t *)malloc(sizeof(stack_t));
if(stack_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_t));
stack_ptr->top = -1;
return stack_ptr;
}
/**
* @name stack_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_destroy(stack_t *stack)
{
if(stack != NULL)
{
free(stack);
return 0;
}
return -1;
}
/**
* @name stack_clear
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_clear(stack_t *stack)
{
if(stack == NULL)
return -1;
stack->top = -1;
return 0;
}
/**
* @name stack_empty
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_empty(stack_t *stack)
{
if(stack == NULL)
return -1;
if(stack->top == -1)
return 1;
return 0;
}
/**
* @name stack_full
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_full(stack_t *stack)
{
if(stack == NULL)
return -1;
if(stack->top == STACK_SIZE-1)
return 1;
return 0;
}
/**
* @name stack_length
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_length(stack_t *stack)
{
if(stack == NULL)
return -1;
return stack->top + 1;
}
/**
* @name stack_push
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_push(stack_t *stack, se_type elem)
{
if(stack_array_full(stack) != 0)
return -1;
stack->top++;
stack->data[stack->top] = elem;
return 0;
}
/**
* @name stack_pop
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_pop(stack_t *stack, se_type *elem)
{
if(stack_array_empty(stack) != 0 || elem == NULL)
{
return -1;
}
*elem = stack->data[stack->top];
stack->top--;
return 0;
}
/**
* @name stack_get_top
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_get_top(stack_t *stack, se_type *elem)
{
if(stack_array_empty(stack) != 0 || elem == NULL || stack->top >= STACK_SIZE)
{
return -1;
}
*elem = stack->data[stack->top];
return 0;
}
链式栈
/** @file stack.c
* @brief 简要说明
* @details 详细说明
* @author lzm
* @date 2021-09-06 22:52:12
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
**********************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 链式结构 */
typedef int se_type; /* 元素类型 */
typedef struct stack_node
{
se_type date;
struct stack_node *next;
}stack_node_t;
typedef struct
{
int count;
stack_node_t *top;
}stack_link_t;
/**
* @name stack_link_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_link_t *stack_creat(int size)
{
stack_link_t *stack_ptr = NULL;
stack_ptr = (stack_link_t *)malloc(sizeof(stack_link_t));
if(stack_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_link_t));
stack_ptr->count = 0;
stack_ptr->top = NULL;
return stack_ptr;
}
/**
* @name stack_link_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_destroy(stack_link_t *stack)
{
stack_node_t *stack_cur = NULL;
stack_node_t *stack_last = NULL;
if(stack == NULL)
return -1;
stack_cur = stack->top;
while(stack_cur)
{
stack_last = stack_cur;
stack_cur = stack_cur->next;
free(stack_last);
}
free(stack);
return 0;
}
/**
* @name stack_link_clear
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_clear(stack_link_t *stack)
{
stack_node_t *stack_cur = NULL;
stack_node_t *stack_last = NULL;
if(stack == NULL)
return -1;
stack_cur = stack->top;
while(stack_cur)
{
stack_last = stack_cur;
stack_cur = stack_cur->next;
free(stack_last);
}
return 0;
}
/**
* @name stack_link_empty
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_empty(stack_link_t *stack)
{
if(stack == NULL)
return -1;
if(stack->count == 0)
return 1;
return 0;
}
/**
* @name stack_link_length
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_length(stack_link_t *stack)
{
if(stack == NULL)
return -1;
return (stack->count);
}
/**
* @name stack_link_push
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_push(stack_link_t *stack, se_type elem)
{
stack_node_t *stack_node_ptr = NULL;
stack_node_ptr = (stack_node_t *)malloc(sizeof(stack_node_t));
if(stack_node_ptr == NULL)
return -1;
memset(stack_node_ptr, 0x00, sizeof(stack_node_t));
stack_node_ptr->date = elem;
stack_node_ptr->next = stack->top;
stack->top = stack_node_ptr->next;
stack->count++;
return 0;
}
/**
* @name stack_link_pop
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_pop(stack_link_t *stack, se_type *elem)
{
stack_node_t *node = NULL;
if(stack_link_empty(stack) != 0 || elem == NULL)
{
return -1;
}
*elem = stack->top->date;
node = stack->top;
stack->top = stack->top->next;
free(node);
stack->count--;
return 0;
}
/**
* @name stack_link_get_top
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_get_top(stack_link_t *stack, se_type *elem)
{
if(stack_link_empty(stack) != 0 || elem == NULL)
{
return -1;
}
*elem = stack->top->date;
return 0;
}
【数据结构&算法】08-栈概念&源码的更多相关文章
- C语言- 基础数据结构和算法 - 08 栈的应用_就近匹配20220611
听黑马程序员教程<基础数据结构和算法 (C版本)>, 照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友 ...
- 中国象棋程序的设计与实现(六)--N皇后问题的算法设计与实现(源码+注释+截图)
八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题. 该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列 ...
- <Linux内核源码>文件系统VFS内核4.0.4版本基本概念源码
题外话:Linux内核从2.x和3.x到现在最新的4.x变化非常大,最直观的表现就是很多书上的内核代码已经无法直接继续使用,所以看看新的源码是非常有意义的! (下文中的内核源码都来自于 kernel ...
- 数据挖掘:关联规则的apriori算法在weka的源码分析
相对于机器学习,关联规则的apriori算法更偏向于数据挖掘. 1) 测试文档中调用weka的关联规则apriori算法,如下 try { File file = new File("F:\ ...
- 数据挖掘 FP-tree算法C++实现及源码
FP-growth挖掘算法 步骤一 扫描数据库,扫描数据库一次,得到频繁1-项集,把项按支持度递减排序,再一次扫描数据库,建立FP-tree 步骤二 对每个项,生成它的 条件模式库 步骤三 用条件模式 ...
- 常用限流算法与Guava RateLimiter源码解析
在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...
- 常见算法合集[java源码+持续更新中...]
一.引子 本文搜集从各种资源上搜集高频面试算法,慢慢填充...每个算法都亲测可运行,原理有注释.Talk is cheap,show me the code! 走你~ 二.常见算法 2.1 判断单向链 ...
- 最快速的“高斯”模糊算法(附Android源码)
这是一个外国人的算法,本人是搬运工.参考:http://blog.ivank.net/fastest-gaussian-blur.html 1:高斯模糊算法(参考:http://www.rua ...
- A*算法(附c源码)
关于A*算法网上介绍的有很多,我只是看了之后对这个算法用c写了一下,并测试无误后上传以分享一下,欢迎指正!下面是我找的一个介绍,并主要根据这个实现的. 寻路算法不止 A* 这一种, 还有递归, 非递归 ...
随机推荐
- echsop设置伪静态
1.后台商店设置-基本设置-URL重写开启 2.修改httpd.conf文件 AllowOverride None 改为 AllowOverride AllLoadModule rewrite_mod ...
- Java基础系列(20)- while循环
循环结构 while循环 do-循环 for循环 在java5中引入了一种主要用于数组的增强型for循环 while循环 while是最基本的循环,它的结构为 while(布尔表达式){ //循环内容 ...
- Shell系列(1)- Shell概述
Shell是什么 Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动.挂起.停止甚至时编写一些程序 Shell还是一个功能 ...
- Shell系列(35)- for循环语法一简介及批量解压缩脚本
for循环语法一 for 变量 in 值1 值2 值3 - do 程序 done 例子 需求:批量解压缩 脚本: #!/bin/bash cd /root/publicls *.tar.gz > ...
- P7046-「MCOI-03」诗韵【SAM,倍增,树状数组】
正题 题目链接:https://www.luogu.com.cn/problem/P7046 题目大意 给出一个长度为 \(n\) 的字符串,然后 \(m\) 次把它的一个子串加入集合.如果一个字符串 ...
- 几分钟就能学会的Python虚拟环境教程
什么是虚拟环境 我们在使用Python的时候,通常用pip来进行包管理.比如我们要安装一个叫requests的库,那么我们就会采用以下命令去安装: pip install requests 那你知道, ...
- Kubernetes-Service介绍(一)-基本概念
前言 本篇是Kubernetes第八篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战.Pod篇暂时应该还缺少两篇,等Service和存储相关内容介绍以后,补充剩下的两篇,有状态的Pod会涉及 ...
- 【vue】使用 Video.js 播放视频
目录 安装 引入 使用 参考文档 环境: vue 2.0+ element ui (这里的代码用了elmentui的按钮样式,可以不用elment ui的样式) 安装 在项目中安装 video.js. ...
- 左手IRR,右手NPV,掌握发家致富道路密码
智能手机的普及让世界成为了我们指尖下的方寸之地. 在各种信息爆炸出现的同时,五花八门的理财信息与我们的生活越贴越近.投资不再仅仅是企业行为,对于个人而言,也是很值得关注的内容. 但是落脚到很小的例子之 ...
- 开发函数计算的正确姿势——OCR 服务
作者 | 杜万(倚贤) 阿里云技术专家 简介 首先介绍下在本文出现的几个比较重要的概念: OCR(光学字符识别):光学字符识别(Optical Character Recognition, OCR)是 ...