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

【数据结构】线性表--栈

【数据结构】线性表--栈

  • 一.什么是栈
  • 二.栈的实现
    • 1.栈结构定义:
    • 2.栈的初始化:
    • 3.栈的销毁:
    • 4.插入函数:
    • 5.删除函数:
    • 6.求栈顶元素:
    • 7.求数据个数:
    • 8.判空:
  • 三.总结

一.什么是栈

栈是一种重要的线性结构,从数据结构看,它也是一种线性表,其特殊性体现在它是操作受限的线性表:只允许在一端进行元素的插入和删除操作。我们将插入和删除元素的一端称为栈顶,另一端称为栈底。

因为只允许在一端进行插入删除操作,所以栈的数据元素遵循后进先出LIFO(last in first out)的原则。

大家可以将栈想象成一个书箱,数据元素就像一本本书一样,只能从顶部放书或取书,最后放进去的书,最先拿到。在这里插入图片描述
或者如视频演示:

栈后进先出演示

二.栈的实现

由干栈本身就是一个线性表,那么前几篇文章我们讨论的线性表的顺序存储和链式存储对于栈来说也是同样适用的。
顺序存储实现就相当于顺序表的尾插尾删,不需要移动元素并且结构简单。
链式存储实现如果是单向链表,用头做栈顶更好,如果是双向链表,用尾做栈顶更好。
本文讲述的是栈的顺序存储实现。

1.栈结构定义:

我们使用动态数组存储数据元素,这样空间不够时可以动态申请空间。
然后定义一个top变量来指示栈顶元素在数组中的位置,top就如同中学物理学过的游标卡尺的游标,如下图,它可以来回移动,意昧着栈顶的top可以根据数据元素入栈、出栈移动,但无论如何游标不能超出尺的长度。同理,若栈的长度为capacity,则栈顶位置top必须小于等于capacity,通常把空栈的判定条件定为top等于0。
在这里插入图片描述

typedef int STDataType;typedef struct Stack
{STDataType* _arr; //数组int top;          //栈顶下标int capacity;     //容量大小
}ST;

2.栈的初始化:

与顺序表类似,使用malloc函数为数组申请一块空间,将top置为0,表示初始时数组下标为0的位置是栈顶(也可以赋别的值),capacity的大小与malloc申请的空间大小一致。

//初始化函数
void StackInit(ST* ps)
{assert(ps);ps->_arr = (STDataType*)malloc(sizeof(STDataType) * 4);//初始给4个STDataType大小的空间//检查是否成功申请空间if (!ps->_arr){perror("malloc fail!");exit(1);}//走到这里说明申请成功ps->capacity = 4;ps->top = 0;
}

3.栈的销毁:

栈的销毁即将动态申请的空间释放掉,将指针置为空,其余都置为0即可。

//销毁函数
void StackDestory(ST* ps)
{assert(ps);free(ps->_arr);ps->_arr = NULL;ps->capacity = ps->top = 0;
}

4.插入函数:

因为栈这个结构规定只能在栈顶插入,所以不存在头插,尾插,任意位置插入这些函数。

插入元素的操作也被称为入栈。
入栈前先检查空间是否足够,不足的话一般二倍扩容。容量足够则直接在栈顶插入数据即可(注意插入完数据之后将栈顶位置++)。

//入栈(插入函数)
void StackPush(ST* ps, STDataType x)
{assert(ps);//入栈前先检查容量if (ps->capacity == ps->top){//一般二倍扩容STDataType* tmp = (STDataType*)realloc(ps->_arr, ps->capacity * 2 * sizeof(STDataType));//检查是否成功申请空间if (!tmp){perror("realloc fail!");exit(1);//直接退出程序}//走到这里说明成功扩容ps->_arr = tmp;ps->capacity *= 2;}ps->_arr[ps->top] = x;ps->top++;
}

5.删除函数:

因为栈这个结构规定只能在栈顶删除,所以不存在头删,尾删,任意位置删除这些函数。

删除元素的操作也被称为出栈。
注意栈为空时不能出栈,可以直接返回,也可以使用断言。

//出栈(删除函数)
void StackPop(ST* ps)
{assert(ps);//如果栈为空不能出栈if (ps->top == 0){return;}elseps->top--;
}

6.求栈顶元素:

求栈顶元素直接返回数组中栈顶位置的下标即可,栈为空无栈顶元素。

//求栈顶元素
STDataType StackTop(ST* ps)
{assert(ps);//栈为空不能求栈顶元素assert(ps->top > 0);return ps->_arr[ps->top - 1];
}

7.求数据个数:

求数据个数直接返回栈顶值即可。

//求数据个数
int StackSize(ST* ps)
{assert(ps);return ps->top;
}

8.判空:

直接根据栈顶位置是否为0判断是否为空。

//判空
bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;//栈为空时返回true,不为空时返回false
}

三.总结

栈的引入简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决的问题核心。
在我们软件应用中,栈这种后进先出的数据结构的应用是非常普遍的。比如你用浏览器上网时,不管什么测览器都有一个‘‘后退’’键,你单击后可以按访问顺序的逆序加载浏览过的网页。很多类似软件,比如word、Photoshop等文档或图像编辑软件,都有撤销(undo)的操作,也是用栈这种方式来实现的,当然不同的软件具体实现代码会有很大差异,不过原理其实都是—样的。
以下是全部源码
Stack.h:

#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>typedef int STDataType;typedef struct Stack
{STDataType* _arr; //数组int top;          //栈顶下标int capacity;     //容量大小
}ST;//初始化函数
void StackInit(ST* ps);//销毁函数
void StackDestory(ST* ps);//入栈(插入函数)
void StackPush(ST* ps, STDataType x);//出栈(删除函数)
void StackPop(ST* ps);//求栈顶元素
STDataType StackTop(ST* ps);//求数据个数
int StackSize(ST* ps);//判空
bool StackEmpty(ST* ps);

Stack.c:

#include"Stack.h"//初始化函数
void StackInit(ST* ps)
{assert(ps);ps->_arr = (STDataType*)malloc(sizeof(STDataType) * 4);//初始给4个STDataType大小的空间//检查是否成功申请空间if (!ps->_arr){perror("malloc fail!");exit(1);}//走到这里说明申请成功ps->capacity = 4;ps->top = 0;
}//销毁函数
void StackDestory(ST* ps)
{assert(ps);free(ps->_arr);ps->_arr = NULL;ps->capacity = ps->top = 0;
}//入栈(插入函数)
void StackPush(ST* ps, STDataType x)
{assert(ps);//入栈前先检查容量if (ps->capacity == ps->top){//一般二倍扩容STDataType* tmp = (STDataType*)realloc(ps->_arr, ps->capacity * 2 * sizeof(STDataType));//检查是否成功申请空间if (!tmp){perror("realloc fail!");exit(1);//直接退出程序}//走到这里说明成功扩容ps->_arr = tmp;ps->capacity *= 2;}ps->_arr[ps->top] = x;ps->top++;
}//出栈(删除函数)
void StackPop(ST* ps)
{assert(ps);//如果栈为空不能出栈if (ps->top == 0){return;}elseps->top--;
}//求栈顶元素
STDataType StackTop(ST* ps)
{assert(ps);//栈为空不能求栈顶元素assert(ps->top > 0);return ps->_arr[ps->top - 1];
}//求数据个数
int StackSize(ST* ps)
{assert(ps);return ps->top;
}//判空
bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;//栈为空时返回true,不为空时返回false
}

test.c:

#include"Stack.h"//测试各个函数
void test01()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);StackPush(&st, 5);//入栈后依次取栈顶数据观察while (!StackEmpty(&st)){printf("%d ", StackTop(&st));//取完栈顶元素后出栈,这样下次才能取到后续的元素StackPop(&st);}StackDestory(&st);
}int main()
{test01();return 0;
}

感谢阅读!
在这里插入图片描述

相关文章:

  • 网络攻防模拟:城市安全 “数字预演”
  • 记录一个为打印高清而做投喂图像增强的例子
  • leetcode2749. 得到整数零需要执行的最少操作数-medium
  • 第二十六天打卡
  • python版本管理工具-pyenv轻松切换多个Python版本
  • 求职困境:开发、AI、运维、自动化
  • Java Set系列集合详解:HashSet、LinkedHashSet、TreeSet底层原理与使用场景
  • YOLO+UI(C#)开发
  • 基于MATLAB-GUI图形界面的数字图像处理
  • 服务培训QDA 的安装调试方法,硬件模块的讲解和软件控制台使用及系统测试
  • R1 快开门式压力容器操作证备考练习题及答案
  • java输入输出类
  • 如何排查阻塞语句
  • 【Linux】iptables 命令详解
  • dify知识库支持图文回复实践
  • STM32H743IIT6_ADC采集误差分析与ADC_DMA
  • Stainer Chain的镜像对称性的充分必要条件
  • 建筑设计单位的数据安全如何保护?天锐蓝盾针对性解决方案
  • 【AI模型部署】
  • Linux-进程概念(一)
  • 盐城经济技术开发区党工委书记王旭东接受纪律审查和监察调查
  • 61岁云浮市律师协会副会长谭炳光因突发疾病逝世
  • 美国新泽西客运公司遭遇罢工:40年来首次,35万人受影响
  • 贵州仁怀通报“正新鸡排鸡腿里全是蛆”:已对同类产品封存送检
  • 收到延期付款利息,该缴纳增值税吗?
  • 韧性十足的中国外贸企业:“不倒翁”被摁下去,还会再弹起来