• 栈与栈区
    • 数组栈
    • **Stack.h中的代码:**
    • **Stack.c中的内容**
    • Test.c
      • 链式栈
  • **Stack.h**
  • **Stack.c**
  • **Test.c**
  • 习题:

栈与栈区

在C/C++中有两种栈。
1,一种是数据结构中的栈,和之前的链表一样,只是一种特殊的线性表,但不同的是,他只允许在在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶

如图所示,只能从一端入栈和出栈,类似于弹夹一样,先装进去的子弹最后才能打出来,这一特性在某些问题很适合
2,另外一个栈是操作系统中的栈,用来函数调用时建立栈帧,然后就是某些局部变量的创建,在栈区,然后动态开辟的空间实在堆区,目前我对操作系统了解的不是很多,有兴趣的可以看看***《深入理解计算机系统》***
好啦,下面我开始介绍一下我们数据结构中的栈
栈一般可以用数组或者链表实现,我在下面两种都写一遍,但是还是比较推荐数组的写法,因为数组在尾上插入数据的代价较小。
注:我写的都是支持动态增长的栈,不是静态栈

数组栈

Stack.h中的代码:


#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;//栈顶的位置int capacity;//容量
}ST;
void StackInit(ST* ps);//栈的初始化
void StackDestory(ST* ps);//栈的销毁
void StackPush(ST* ps,STDataType x);//压栈
void StackPop(ST* ps);//出栈
bool StackEmpty(ST* ps);//检测栈是否为空
int StackSize(ST* ps);//返回栈中元素的个数
STDataType StackTop(ST* ps);//返回栈顶的元素

Stack.c中的内容


#include"Stack.h"
void StackInit(ST* ps)//栈的初始化
{ assert(ps);//栈可以为空,但是储存栈的结构体不可能是空的ps->a = NULL;ps->capacity = 0;ps->top = 0;
}void StackDestory(ST* ps)//栈的销毁
{assert(ps);free(ps->a);ps->a = NULL;ps->top = 0;ps->capacity = 0;}void StackPush(ST* ps, STDataType x)//压栈
{assert(ps);//压栈之前要检查一下栈是否满 因为我们的top始终是位于栈顶的下一个位置//所以当top的值等于capacity的时候栈就满了或者是一开始栈空的情况if (ps->top == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;ps->a = (ST*)realloc(ps->a, sizeof(ST) * newCapacity);//在原来的基础上扩容,所以用reallocif (ps->a == NULL){printf("malloc fail\n");exit(-1);}ps->capacity = newCapacity;}//压栈ps->a[ps->top] = x;ps->top++;
}void StackPop(ST* ps)//出栈
{assert(ps);//出栈之前要考虑一下栈是否为空,空的话就不用出栈了 所以还需要一个断言assert(ps->top > 0);ps->top--;//因为我们打印的时候是从头开始遍历的,只会遍历到top所以只需要top--}bool StackEmpty(ST* ps)//检测栈是否为空
{assert(ps);//如果top = 0的时候就是栈空 所以return ps->top == 0;
}int StackSize(ST* ps)//返回栈中元素的个数
{assert(ps);return ps->top;
}STDataType StackTop(ST* ps)//返回栈顶的元素
{assert(ps);//同时这里要确保栈中不为空assert(ps->top > 0);return ps->a[ps->top - 1];
}

Test.c


#include"Stack.h"
int main()
{ST xk;StackInit(&xk);StackPush(&xk, 1);StackPush(&xk, 3);StackPush(&xk, 2);StackPush(&xk, 5);StackPush(&xk, 6);//打印栈while (!StackEmpty(&xk))//当栈非空的时候打印{printf("%d  ", StackTop(&xk));StackPop(&xk);//一定要记得出栈 不然会无限循环}return 0;
}

链式栈


Stack.h

 #define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack//注意:我写的这个是不带哨兵位的单链表
{STDataType data;struct Stack* next;
}ST;
//注意:因为链式栈的初始化一开始就是就是一个空指针
//而后续函数基本都要改动头结点,所以函数应该传入的是二级指针
void StackInit(ST** ps);//栈的初始化
void StackDestory(ST** ps);//栈的销毁
void StackPush(ST** ps, STDataType x);//压栈
void StackPop(ST** ps);//出栈
bool StackEmpty(ST** ps);//检测栈是否为空
int StackSize(ST** ps);//返回栈中元素的个数
STDataType StackTop(ST** ps);//返回栈顶的元素

Stack.c

 #define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"void StackDestory(ST** ps)//栈的销毁
{assert(ps);//这的*ps表示的是头结点 当栈空的时候头结点是有可能为NULL的//但是指针的地址是不可能空的,所以我们断言的是指针的地址ST* cur = *ps;while (cur){ST* ret = cur->next;free(cur);cur = ret;}*ps = NULL;//和单链表的销毁是一样的}void StackPush(ST** ps, STDataType x)//压栈{//压栈其实相当于单链表的头插assert(ps);ST* cur = (ST*)malloc(sizeof(ST));//先申请一个空间来储存x的值if (cur == NULL){printf("malloc fail\n");exit(-1);}cur->data = x;cur->next = NULL;//当栈为空的时候if (*ps == NULL){*ps = cur;}else{ST* ret = (*ps);*ps = cur;(*ps)->next = ret;}}void StackPop(ST** ps)//出栈
{assert(ps);//出栈就是单链表中删除第一个元素 //所以我们应该要断言一下栈不为空的时候才可以出栈assert(*ps);//当只有一个元素时ST* cur = *ps;*ps = (*ps)->next;free(cur);}bool StackEmpty(ST** ps)//检测栈是否为空
{assert(ps);return (*ps) == NULL;
}int StackSize(ST** ps)//返回栈中元素的个数
{assert(ps);ST* cur = *ps;int sum = 0;while (cur){sum++;cur = cur->next;}return sum;
}STDataType StackTop(ST** ps)//返回栈顶的元素
{assert(ps && *ps);//断言栈不为空return (*ps)->data;}

Test.c

 #define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
int main()
{ST* xk = NULL;StackPush(&xk, 223);StackPush(&xk, 453);StackPush(&xk, 43534);StackPush(&xk, 3454);StackPush(&xk, 3665);StackPush(&xk, 7876);while (!StackEmpty(&xk)){printf("%-7d   ", StackTop(&xk));printf("%d\n", StackSize(&xk));StackPop(&xk);}return 0;
}

习题:

括号匹配问题
我这边解题用的是C语言 可能显得有点鸡肋,用c++要方便好多,但这也可以说是学以致用了哈哈哈
我用的是数组栈去解题的,有兴趣的可以试试链式栈,由于C语言的局限性,我们必须把栈的模拟全部 ctrl+c+v上去

思路:依次遍历字符串中每一个字符,遇到左边括号就入栈,遇到右边的括号就出栈,并且出栈的时候拿栈顶的字符和字符串此时的字符比较,如果符合的话我们此时就比较下一个字符,知道字符串全部遍历完,如果有一个不匹配的话,直接return false
需要注意的代码我在下面已经标记出来了


typedef char STDataType;//赋值粘贴的时候别忘记改成char
typedef struct Stack
{STDataType* a;int top;//栈顶的位置int capacity;//容量
}ST;
void StackInit(ST* ps)//栈的初始化
{ assert(ps);//栈可以为空,但是储存栈的结构体不可能是空的ps->a = NULL;ps->capacity = 0;ps->top = 0;
}void StackDestory(ST* ps)//栈的销毁
{assert(ps);free(ps->a);ps->a = NULL;ps->top = 0;ps->capacity = 0;}void StackPush(ST* ps, STDataType x)//压栈
{assert(ps);//压栈之前要检查一下栈是否满 因为我们的top始终是位于栈顶的下一个位置//所以当top的值等于capacity的时候栈就满了或者是一开始栈空的情况if (ps->top == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;ps->a = (ST*)realloc(ps->a, sizeof(ST) * newCapacity);//在原来的基础上扩容,所以用reallocif (ps->a == NULL){printf("malloc fail\n");exit(-1);}ps->capacity = newCapacity;}//压栈ps->a[ps->top] = x;ps->top++;
}void StackPop(ST* ps)//出栈
{assert(ps);//出栈之前要考虑一下栈是否为空,空的话就不用出栈了 所以还需要一个断言assert(ps->top > 0);ps->top--;//因为我们打印的时候是从头开始遍历的,只会遍历到top所以只需要top--}bool StackEmpty(ST* ps)//检测栈是否为空
{assert(ps);//如果top = 0的时候就是栈空 所以return ps->top == 0;
}int StackSize(ST* ps)//返回栈中元素的个数
{assert(ps);return ps->top;
}STDataType StackTop(ST* ps)//返回栈顶的元素
{assert(ps);//同时这里要确保栈中不为空assert(ps->top > 0);return ps->a[ps->top - 1];
}
bool isValid(char * s)
{  ST pos;//创建一个栈StackInit(&pos);while(*s){if(*s=='('||*s=='{'||*s=='['){StackPush(&pos,*s);s++;}else{if(StackEmpty(&pos)) //这一步一定不能忘记了,因为当栈为空的时候,下面的返回栈顶会报错的return false;if((*s==')'&&StackTop(&pos)!='(')||(*s=='}'&&StackTop(&pos)!='{')||(*s==']'&&StackTop(&pos)!='['))return  false;else{StackPop(&pos);s++;}}}if(!StackEmpty(&pos)) return false;//如果最后栈区不是空的话,那么也是不符合要求的return true;}

栈(数据结构)超详解(最后面还有一道经典习题哦)相关推荐

  1. C/C++堆、栈及静态数据区详解

    五大内存分区 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区.下面分别来介绍: 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面 ...

  2. 堆、栈及静态数据区详解

    堆.栈及静态数据区详解 五大内存分区 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储 ...

  3. java数据结构-链表详解

    文章目录 1.数据结构-链表详解 1.1单链表 1.1.1单链表节点的尾部添加 1.1.2单链表节点的自动排序添加 1.1.3单链表节点的修改 1.1.4单链表节点的删除 1.2单链表面试题 1.2. ...

  4. JAVA 多线程并发超详解

    JAVA 多线程并发超详解(未完,下一篇文章还有) 1. JAVA 多线程并发 1.1.1. JAVA 并发知识库 1.1.2. JAVA 线程实现/创建方式 1.1.2.1. 继承 Thread 类 ...

  5. Android vector标签 PathData 画图超详解

    此文章来源于https://www.cnblogs.com/yuhanghzsd/p/5466846.html点击打开链接 Android vector标签 PathData 画图超详解 SVG是一种 ...

  6. Mybatis案例超详解

    Mybatis案例超详解 前言: 本来是想像之前一样继续跟新Mybatis,但由于种种原因,迟迟没有更新,快开学了,学了一个暑假,博客也更新了不少,我觉得我得缓缓,先整合一些案例练练,等我再成熟点理解 ...

  7. python控制手机模拟器_Appium+python自动化之连接模拟器并启动淘宝APP(超详解)...

    简介 上一篇讲解完模拟器的安装.配置好以后,就好比我们手机已经买好,并且系统已经做好了,就差我们用数据线和电脑连接开始实战了,这篇宏哥就带着小伙伴们和童鞋们趁热打铁,讲解和分享一下如何连接模拟器(电脑 ...

  8. js打印三角形超详解

    js打印三角形超详解 j控制星星的总行数,i控制每行星星的打印个数 打印图形如下: (1) (2) //str=""用来存储星星// 理解步骤1:在一行输出6个星星如何操作,在循环 ...

  9. 线性规划之单纯形法【超详解+图解】-转载

    线性规划之单纯形法[超详解+图解] 目录 1.作用 2.线性规划的一般形式 5.1几何意义 5.2如何判断最优 5.3如何选择新的基变量 5.4如何选择被替换的基变量 5.5终止条件 标准型: 转化为 ...

最新文章

  1. PCL-1.8.1从源码搭建开发环境二(FLANN库的编译)
  2. IDEA多行缩进快捷键
  3. JavaScript存在的原因
  4. 面试宝典系列-PHP变量在内存中的存储方式
  5. 杨攀:融云专注极致技术 不忘初心打造极简体验
  6. DB Intro - MongoDB User
  7. php asp.net core,asp.net core实例教程之配置
  8. 算法设计与分析——递归与分治策略——线性时间选择
  9. This subject is anonymous - it does not have any identifying principals and authorization operations
  10. cgdb 调试_在MacOS上使用gdb(cgdb)调试Golang程序
  11. Hystrix面试 - 基于 Hystrix 信号量机制实现资源隔离
  12. Python Tree库绘制多叉树的用法介绍
  13. mysql mgr监控_说MGR - MGR的监控
  14. R语言计算相关矩阵然后将计算结果输出到CSV文件
  15. pop和push等使用方法,every和some、join
  16. 氪金玩家逸仙电商的高端困境
  17. ckeditor使用----跳坑之旅
  18. [TcaplusDB] 行业新闻汇编(6月29日)
  19. java switch的意思_java switch
  20. 关于Linux的介绍与安装

热门文章

  1. 十一郎专栏 | java面试八股文-基础篇
  2. java 后台源码_课程管理系统后台JAVA代码
  3. 《好学的C++ 第2版》 第3章 一专多能的for语句
  4. 全球及中国橡胶防粘剂行业研究及十四五规划分析报告(2022)
  5. 如何在GIS中转出并显示CAD的DWG中的文字(注记)数据
  6. mysql实验总结,数据库实验总结
  7. php制作cms视频教程下载,PHPCMS V9 实战模板制作视频教程+仿站超级工具
  8. 2022-2028年中国新型农业机械行业市场前瞻与投资战略规划分析报告
  9. [RK3399][Android8.1/9]双屏异显
  10. 服务器 用一个独立的硬盘存储文件夹,一、块存储、文件存储、对象存储,三者的本质差别是什么?...