当前位置: 首页 > news >正文

数据结构——顺序栈

一、顺序栈的定义

栈是限定仅在表尾进行插入和删除操作的线性表,我们允许将插入和删除的一端叫做栈顶,另一端称为栈底,任何数据元素的栈称为空栈,栈又称为后进先出的线性表

栈顶指针:指向的是最后一个元素的下一个位置

注意:首先他是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系,只不过他是一种特殊的线性表而已。

(1)进栈(入栈,入栈):栈的插入。

(2)出栈(弹栈):栈的删除操作。

二、顺序栈的主要代码实现

1、顺序栈的结构体设计:

(1)与顺序表一样,我们需要一个数组,用来保存后续可能会保存的值,需一个可放入的最大空间,以及此时的数据元素个数

(2)顺序栈一样他也需要一个数组,用来保存后续可能会保存的值,需一个可放入数组元素的最大空间,以及数组的数据元素个数

注:我们不需要单独定义数组元素个数,因为此时栈顶指针做的事情就是指向现有元素的下一个元素的位置,因为数组是元素下标是以0开始所以此时栈顶指向的就是栈的元素的个数,可以把他想象成数组

#define STACK_INIT_SIZE 10//顺序表实现的栈 的初始大小 typedef int ElemType; //顺序栈的结构体设计 typedef struct SeqStack { ElemType* base;//1.指针类型,用来接收malloc的返回值 int top;//2.栈顶指针,用来指向栈顶元素的的下一个存储位置(也能表示当前有效元素个数 int stacksize;//3.当前总的空间大小(用来扩容 }SeqStack;

2、初始化栈

//1.初始化 void Init_SeqStack(SeqStack* psq) { assert(psq != NULL); psq->base = (ElemType*)malloc(STACK_INIT_SIZE * sizeof(ElemType)); if (psq->base == NULL) exit(EXIT_FAILURE); psq->top = 0; psq->stacksize = STACK_INIT_SIZE; }

3、入栈(雷同头插)

思路:

(1)顺序栈可以将其想象为数组,与链表不同他的内存是连续的,所以我们不需要有指针域来保存地址。

(2)判断传入的指针是否有效

(3)因为顺序栈相当于是数组,所以此时如果栈元素所占的字节数已经达到栈的最大内存,那么此时就没有空间可以插入元素,所以需要扩容

(4)因为栈顶指针指向的就是最后元素的下一个元素的位置,因为栈是一个特殊的线性表,他只可以在栈顶插入也只能在栈顶删除。此时栈顶指针指向的位置就是我们即将头插的位置。

(5)将要插入的值给到栈顶指针指向的位置并将栈顶指针+1;

//2.入栈 bool Push(SeqStack* psq, ElemType val) { //0.assert asser(psq!=NULL); //1.判满 (如果满了就扩容) if (Full(psq)) { Increase(psq); } //2.直接给top指向的下标格子进行插入值 val psq->base[psq->top] = val; //3.更新一下top栈顶指针的指向 psq->top++; return true; }

4、出栈(雷同头删)

思路:

(1)因为顺序栈是受到限制的线性表,他只能从栈顶插入栈顶删除。所以具有先进后出的特点。

(2)判断传入指针是否有效

(3)判断顺序表是否是空表如果是空表则删不了

(4)找到合适的删除位置也就是头删,利用栈顶指针(因为栈顶指针指向最后一个有效元素的下一个位置,此时直接让栈顶指针-1,就意味着将原本的栈的最后有效元素给抛弃掉,让原倒数第二个元素变成栈的新的最后一个有效元素)

bool Pop(SeqStack* psq) { //0.assert //1.判空 if (Empty(psq)) { return false; } //2.直接将top指针往后走一下,认为刚才的最后一个元素(刚才的栈顶元素)是无效值即可 psq->top--; return true; }

5、获取栈顶有效元素值(只有读的权限没有改的权限)

思路:

(1)因为顺序栈是受到限制的线性表,他只能从栈顶进行插入,栈顶进行删除,具有先进后出的特点

(2)利用栈顶指针,栈顶指针指向的前一个有效元素给获取出来

(3)如果是空栈就获取不了,直接退出

//4.获取栈顶元素值(只看栈顶元素的值 没有修改权限) ElemType Top(SeqStack* psq) { assert(psq != NULL); if (Empty(psq)) { return; } return psq->base[psq->top--]; }

6、扩容

思路:

(1)因为扩容具有可能会在原始的基础上进行申请空间,也可能新的一片空间,也可能扩容失败,所以需要另外申请一个指针来申请内存

//5.扩容 *2 void Increase(SeqStack* psq) { ElemType*tmp = (ElemType*)realloc(psq->base, psq->stacksize * sizeof(ElemType) * 2); if (tmp != NULL) psq->base = tmp; psq->stacksize *= 2; }

7、判空

思路:

(1)当栈顶指针指向栈底时,也就是0时此时说明没有有效元素

(2)直接return psq->top==0;当满足时就是true 当不满足时就是false

//6.判空 bool Empty(SeqStack* psq) { return psq->top == 0; }

8.判满

思路:

(1)判断栈顶指针指向的是否已经是栈的最大字节格子

//7.判满 bool Full(SeqStack* psq) { return psq->top == psq->stacksize; }

9、打印

//8.打印(用来测试的) void Show(SeqStack* psq) { for (int i = 0; i < psq->top; i++) printf("%d ", psq->base[i]); printf("\n"); }

10、清空

思路:

(1)直接抛弃栈里所有元素,将栈顶指针直接指向0

void Clear(SeqStack* psq) { psq->top = 0; }

11、销毁

思路:

(1)将申请的空间全部释放掉

void Destroy(SeqStack* psq) { free(psq->base); psq->base = NULL; psq->stacksize = 0; psq->top = 0; }

12、主函数测试

int main() { SeqStack st; Init_SeqStack(&st); Push(&st, 12); Push(&st, 23); Push(&st, 34); Show(&st); Pop(&st); Show(&st); printf("TOP=%d\n", Top(&st)); Push(&st, 12); Push(&st, 23); Push(&st, 34); Push(&st, 12); Push(&st, 23); Push(&st, 34); Push(&st, 12); Push(&st, 23); printf("TOP:%d, StackSize:%d\n", st.top, st.stacksize); Push(&st, 34); Show(&st); printf("TOP:%d, StackSize:%d\n", st.top, st.stacksize); Clear(&st); Show(&st); printf("TOP:%d, StackSize:%d\n", st.top, st.stacksize); Destroy(&st); printf("TOP:%d, StackSize:%d\n", st.top, st.stacksize); return 0; }
http://www.jsqmd.com/news/641130/

相关文章:

  • Topit:重新定义Mac多任务效率的智能窗口置顶革命
  • 第二届“Parloo”CTF应急响应挑战赛实战复盘:从Webshell追踪到内网渗透
  • Git Submodule 深度避坑指南:从“能用”到“好用”的协作进阶
  • 基于Ubuntu 24.04与MariaDB构建Zabbix 7.0云服务器监控体系
  • 成都地区宝钢产无缝钢管(8163-20#;外径42-630mm)现货报价 - 四川盛世钢联营销中心
  • claude4
  • 别再乱选二极管了!BUCK/BOOST电路续流与整流二极管实战避坑指南
  • 3分钟上手Keyviz:让你的键盘操作像电影特效一样炫酷
  • Windows防火墙如何放行WSL2?手把手教你设置入站规则(含常见错误排查)
  • Cesium中高效集成天地图WMTS服务的实战指南
  • Axure中文界面安装指南:3步告别英文困扰,让原型设计更高效
  • 鲲鹏麒麟环境下MySQL5.7离线部署全流程解析
  • AIMP:轻量级音乐播放器解决音频播放与管理的常见问题
  • 告别网盘限速困扰:八大网盘直链下载助手完全指南
  • 告别复制粘贴!深入理解GD32F407的GPIO配置:推挽、开漏、复用AF到底怎么选?
  • AutoCAD字体管理终极指南:FontCenter免费插件完整解决方案
  • 为什么 Multi-Agent 是技术创业者的最大机会
  • STL体积计算器:3D打印模型体积与重量估算完整指南
  • Java SPI实战:从零实现一个可插拔的日志框架(附完整代码)
  • Noto字体:告别豆腐块困扰,打造完美多语言显示体验
  • 告别需求文档焦虑:用Spec-Kit + Claude Code,5分钟搞定你的C++五子棋项目规划
  • 当网盘限速成为日常,这款工具如何让我重获下载自由?
  • 从零到部署:为你的UG/NX二次开发插件制作专业级菜单界面(MenuScript实战指南)
  • 如何在OBS中实现免费本地AI语音识别:LocalVocal完全指南
  • 保姆级教程:在Linux下排查PCIe RootPort Completion Timeout错误(附抓包与日志分析)
  • MogFace人脸检测模型-WebUI实操手册:Linux服务器部署、日志排查、性能调优
  • 揭秘LLaVA-ViL-Flamingo三大主流多模态模型的“黑箱决策路径”:如何用Grad-CAM++与Concept Activation Vector精准定位图文推理漏洞?
  • 【Scala PyTorch深度学习】PyTorch On Scala 系列课程 第五章 10 :数据集【AI Infra 3.0】[PyTorch Scala 硕士研一课程]
  • 告别环境配置焦虑:在Ubuntu 22.04上5分钟搞定ESP-IDF v5.4.2(含永久串口权限设置)
  • 本地化基因ID转换工具开发指南:从NCBI数据到高效pipeline集成