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

【数据结构】栈的概念、结构和实现详解

本文来介绍一下数据结构中的栈,以及如何用C语言去实现。

 1. 栈的概念及结构

栈:一种特殊的线性表,它只允许在固定的一端进行插入和删除元素的操作。

       进行数据插入和删除操作的一端称为栈顶,另一端称为栈底

       栈中元素遵循后进先出LIFO(Last In First Out)的原则

压栈:栈的插入操作叫做进栈/入栈/压栈,入数据在栈顶

出栈:栈的删除操作叫做出栈,出数据也在栈顶

2. 实现栈的底层方法选择

没有规定栈的哪端是栈顶,只说了数据插入和删除的一端是栈顶,所以我们栈的底层实现可以用链表或者数组 。

 虽然数组和单链表都可以实现栈,但是单链表能很好入数据不好删除数据,这里单链表要删除数据就是尾删,尾删需要找到前一个结点,不是很方便。

非要用链表的话有两个解决方法,1.可以用双向链表 2.我们把单链表的头节点当作栈顶,也就是把左边当栈顶,右边当栈底,对单链表进行头插和头删的操作。

 现在有3种方法实现栈,数组,单链表,双链表,我们应该如何选?

首先排除双链表,用双链表不如用单链表,双链表因为一个节点存两个指针,比单链表的一个节点多了4个字节或者8个字节。数组实现栈和单链表实现栈有什么区别?基本没区别,都可以,非要说选一个,我们还是更倾向于数组,因为数组的唯一缺点就是内存不足时需要扩容,扩容的影响也不是特别大,最重要的是数组的缓存效率更高。所以我们就用数组实现栈。

3. 栈的实现

提前说明,如果本篇看不太懂可以先看看【数据结构】顺序表-CSDN博客,我们栈的实现和顺序表的实现差不多。

还是一样,新建一个头文件和两个源文件

 点开Stack.h文件,在这个文件里面我们要定义栈的结构,以及给类型和栈的结构取别名。

typedef int STDateType;
typedef struct Stack
{STDateType* a;//动态申请空间 调大小int top;      //用栈顶记录元素个数int capacity; //数组实现要扩容,记录空间大小
}ST;

栈一共要实现下面这7个接口,我们将一个一个来看.

void STInit(ST* pst);//栈初始化
void STDistroy(ST* pst);//栈的销毁
void STPush(ST* pst, STDateType x);//压栈
void STPop(ST* pst);//出栈
STDateType STTopDate(ST* pst);//获取栈顶元素
bool STEmpty(ST* pst);//判断栈是否为空
int STSize(ST* pst);//获取栈元素个数

这里是会用到的头文件,且标注了是什么会用到,被包含的头文件全放在Stack.h

#include <stdio.h>
#include <stdlib.h>   //空间申请
#include <stdbool.h>  //布尔类型
#include <assert.h>   //断言

Stack.c中只需要包含Stack.h

#include "Stack.h"

 准别工作做好后我们开始实现栈。

3.1 栈的初始化和销毁

Stack.h中进行函数的声明。这里的参数需要传指针。

void STInit(ST* pst);//栈初始化
void STDistroy(ST* pst);//栈的销毁

SeqList.c中进行函数的实现

void STInit(ST* pst)//栈初始化
{assert(pst); //判断pst是否为空pst->capacity = 0;pst->top = 0;pst->a = NULL;
}
void STDistroy(ST* pst)//栈的销毁
{assert(pst);free(pst->a);pst->a = NULL;pst->capacity = pst->top = 0;
}

 这里和顺序表差不多,很简单就不多说了。

3.2 压栈和出栈

Stack.h中进行函数的声明。

void STPush(ST* pst, STDateType x);//压栈
void STPop(ST* pst);//出栈

这里的参数需要传指针,压栈的函数参数还有要插入的数据。因为栈插入数据就是从栈顶插入,这里就没有什么头插尾插的概念,直接就是Push,删除数据也是,直接栈顶删除Pop。

SeqList.c中进行函数的实现

先说压栈

先分析空间足够的情况,初始化我们把top置为0,放进一个元素,top就是1,但是这个元素在数组中的下标为0,所以栈顶元素数组下标是top-1,而top指向的是栈顶元素的下一个位置,而不是栈顶元素。

所以我们放数据就是直接放下标为top的位置。

void STPush(ST* pst, STDateType x)//压栈
{assert(pst);pst->a[pst->top] = x; //先放数据pst->top++;   //然后top++}

然后考虑扩容。capacity是数组大小,分析一下数组满了的情况

 

应该是top和capacity相等,此时就要扩容。

void STPush(ST* pst, STDateType x)//压栈
{assert(pst);if (pst->top == pst->capacity){int newcapacity = pst->capacity * 2;//原来空间2倍的扩容//扩容STDateType* tmp = (STDateType*)realloc(pst->a, newcapacity * sizeof(STDateType));if (tmp == NULL) //扩容失败{perror("realloc fail");return;}//扩容成功pst->a = tmp;pst->capacity = newcapacity;}pst->a[pst->top] = x;pst->top++;
}

但是我们要注意这句代码 int newcapacity = pst->capacity * 2;  我们一开始capacity初始化为0,0乘任何数都是0,所以这句换我们要改一下,用一个三目操作符就能解决。

int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;

 再说出栈

出栈和顺序表是一样的,直接top--就行了,不理解的可以看看顺序表中数据的尾删

void STPop(ST* pst)//出栈
{assert(pst);assert(pst->top > 0);pst->top--;
}

test.c中测试一下栈的初始化,压栈,出栈,栈的销毁。

#include "Stack.h"
int main()
{ST s;STInit(&s);   //初始化STPush(&s, 1);//压栈STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);for (int i = 0; i < s.top; i++){printf("%d ", s.a[i]);}printf("\n");STPop(&s);//出栈for (int i = 0; i < s.top; i++){printf("%d ", s.a[i] );}printf("\n");STPop(&s);//出栈for (int i = 0; i < s.top; i++){printf("%d ", s.a[i]);}STDistroy(&s);//销毁return 0;
}

 遵循后进先出

3.3 获取栈顶元素

Stack.h中进行函数的声明。

STDateType STTopDate(ST* pst);//获取栈顶元素

SeqList.c中进行函数的实现

STDateType STTopDate(ST* pst)//获取栈顶元素
{assert(pst);assert(pst->top > 0);return pst->a[pst->top - 1];
}

test.c中测试一下

#include "Stack.h"
int main()
{ST s;STInit(&s);   //初始化STPush(&s, 1);//压栈STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);for (int i = 0; i < s.top; i++){printf("%d ", s.a[i]);}printf("\n");printf("栈顶元素:%d\n", STTopDate(&s));STPop(&s);//出栈STPop(&s);for (int i = 0; i < s.top; i++){printf("%d ", s.a[i] );}printf("\n");printf("栈顶元素:%d\n", STTopDate(&s));STDistroy(&s);//销毁return 0;
}

3.4 判断栈是否为空

Stack.h中进行函数的声明。

bool STEmpty(ST* pst);//判断栈是否为空

这里用了bool类型,需要包含头文件stdbool.h

SeqList.c中进行函数的实现

bool STEmpty(ST* pst)//判断栈是否为空
{assert(pst);if (pst->top == 0) //为空,返回真return true;else               //不为空,返回假return false;
}

还有一个更简单的写法,如下

 bool STEmpty(ST* pst)//判断栈是否为空
{assert(pst);return pst->top == 0;
}

 为空,返回真,不为空返回假。

test.c中测试一下,用栈的后进先出的特点访问

#include "Stack.h"
int main()
{ST s;STInit(&s);   //初始化STPush(&s, 1);//压栈STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);//栈标准的后进先出访问方式while (!STEmpty(&s)){printf("%d ", STTopDate(&s));//先访问栈顶元素STPop(&s); //然后把栈顶元素删除}STDistroy(&s);//销毁return 0;
}

3.5 获取栈元素个数

Stack.h中进行函数的声明。

int STSize(ST* pst);//获取栈元素个数

SeqList.c中进行函数的实现

因为我们前面的top初始化为0,所以top就是栈的元素个数,直接返回top就行了。

int STSize(ST* pst)//获取栈元素个数
{assert(pst);return pst->top;
}

test.c中自己测试一下,这里就不测试了

到这里这个栈就实现好了,本篇也就结束啦,拜拜~

相关文章:

【数据结构】栈的概念、结构和实现详解

本文来介绍一下数据结构中的栈&#xff0c;以及如何用C语言去实现。 1. 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;它只允许在固定的一端进行插入和删除元素的操作。 进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。 栈中元素遵循后进先出…...

LeetCode 每日一题 2024/7/29-2024/8/4

记录了初步解题思路 以及本地实现代码&#xff1b;并不一定为最优 也希望大家能一起探讨 一起进步 目录 7/29 682. 棒球比赛7/30 2961. 双模幂运算7/31 3111. 覆盖所有点的最少矩形数目8/1 LCP 40. 心算挑战8/2 3128. 直角三角形8/3 3143. 正方形中的最多点数8/4 572. 另一棵树…...

Golang死锁vs操作系统死锁

目录 一、死锁 二、Golang死锁场景 2.1 重复上锁 2.2 不会减少的 WaitGroup 2.3 空select 2.4 channel 一、死锁 1.golang中死锁的触发条件&#xff1a; 死锁是当 Goroutine 被阻塞而无法解除阻塞时产生的一种状态。 2.操作系统死锁&#xff1a; 发生死锁时&#xff0c;线…...

c/c++中π怎么定义

c/c中都没有π的专属变量&#xff0c;一般都是自定义。 方法1&#xff1a;#define pi 3.1415926 方法2&#xff1a;使用反三角函数const double pi acos(-1.0);...

基于whisper流式语音识别

为了实现持续监听麦克风并在检测到声音时进行转录&#xff0c;我们可以将流的监听时间设置为无限长。通过使用一个音量门限来检测是否有声音&#xff0c;然后进行转录。 安装依赖 确保安装必要的库&#xff1a; pip install torch torchaudio openai-whisper sounddevice nu…...

Web3 市场暴跌的时候,哪些token跌的少,哪些还涨了? binance 数据爬取及分析

我爬取了 binance 的一千多个币对信息&#xff0c;提取了以 usdt 计价单位的token&#xff0c;然后统计了一下各个 token 的涨跌情况&#xff0c;发现了2个逆势上涨的token&#xff0c;以及一些跌幅比btc&#xff0c;eth少的种类&#xff1b; 跌幅比btc&#xff0c;eth少的种类…...

ffmpeg获得视频的音频文件

要从视频文件中提取音频文件&#xff0c;你可以使用 FFmpeg&#xff0c;这是一个强大的多媒体框架&#xff0c;用于转换、流化以及处理多媒体数据。下面是如何使用 FFmpeg 从视频文件中提取音频的步骤&#xff1a; 1. 确定视频文件的位置&#xff1a; 确保你知道视频文件的完整…...

Robot Operating System——深度解析单线程执行器(SingleThreadedExecutor)执行逻辑

大纲 创建SingleThreadedExecutor新增Nodeadd_nodetrigger_entity_recollectcollect_entities 自旋等待get_next_executablewait_for_workget_next_ready_executableTimerSubscriptionServiceClientWaitableAnyExecutable execute_any_executable 参考资料 在ROS2中&#xff0c…...

【TS】使用npm全局安装typescript

查看npm安装 npm -v 安装typescript npm i -g typescript 查看安装 tsc 这就是标致着安装完成。...

安全用户角色权限

$PATH 搞系统设置设置⾥头path ⽬标包含mysql 可执⾏⽂件&#xff0c;那么就是由使⽤ 在终端使⽤ ./bin/mysql -h192.168.71.164 -P3306 -uroot -proot 1.远程登录前提条件是mysql.user表中的host属性为%&#xff0c;如果是 localhost就不允许远程登录&#xff0c;update…...

代理模式学习

代理模式 代理模式是常用的java设计模式&#xff0c;他的特征是代理类与委托类有同样的接口&#xff0c;代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类&#xff0c;以及事后处理消息等。代理类与委托类之间通常会存在关联关系&#xff0c;一个代理类的对象…...

深入理解Go 语言信号量 Semaphore

1. 什么是信号量 信号量的概念是荷兰计算机科学家 1.1 P/V 操作 Dijkstra 在他的论文中为信号量定义了两个操作 : P 和 V 。 1.2 信号量和互斥锁的区别与联系 信号量有两种类型&#xff1a;二元信号量和计数信号量。 2. 信号量的 channel 实现 程序在运行时&#xff0c;…...

VisualStudio2019下载与安装

1.下载 通过百度网盘分享的文件&#xff1a;VisualStudio2019 链接&#xff1a;https://pan.baidu.com/s/16tqm0ZsOkmXTfGmi4LnGbA 提取码&#xff1a;wx60 --来自百度网盘超级会员V3的分享 2.安装...

李宏毅老师机器学习常见英语词汇

目录 1.Regression &#xff1a;回归2.Classification&#xff1a;分类3.local minima:局部最小值4.saddle point:鞍点5.ground truth:它是机器学习算法的参考标准&#xff0c;用于衡量模型的性的和判断模型的准确性6.optimization:优化 1.Regression &#xff1a;回归 2.Clas…...

人工智能时代,程序员如何保持核心竞争力?

人工智能时代&#xff0c;程序员如何保持核心竞争力&#xff1f; 随着AIGC&#xff08;如chatgpt、midjourney、claude等&#xff09;大语言模型接二连三的涌现&#xff0c;AI辅助编程工具日益普及&#xff0c;程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工…...

WiFi to Ethernet: 树莓派共享无线连接至有线网口,自动通过Captive Poartal网页登录认证

物联网开发系列&#xff1a;物联网开发之旅① WiFi to Ethernet: 树莓派共享无线连接至有线网口&#xff0c;自动通过Captive Poartal验证物联网开发番外篇之 Captive Portal验证原理 文章目录 背景实现工具实现细节一、将无线连接共享到以太网1. 配置静态IP地址2. 启用IP转发3…...

【神软大数据治理平台-高级动态SQL(接口开发)】

1、背景 业务部门需大数据平台按照所提需求提供企业数据接口&#xff0c;基于神软大数据治理平台-高级动态SQL功能&#xff0c;满足业务需求&#xff0c;如下&#xff1a; &#xff08;1&#xff09;业务系统需求&#xff1a; 输入&#xff1a; enterpriseName&#xff1a;…...

【Java数据结构】Map和Set超详细两万字讲解(内含搜索树+哈希表)

&#x1f512;文章目录&#xff1a; 1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; 2. Map和Set的基础概念 3.Map的基础使用 4.Set的基础使用 5. TreeMap的本质——红黑树 5.1二叉搜索树的概念 5.2二叉搜索树的模拟实现 二叉搜索树——查找 二…...

中国制造2025,会抛弃精益生产吗?

时至今日&#xff0c;“精益生产”模式依旧大行其道&#xff0c;它始终支持着中国制造业以最低的成本做出优质产品。我们认为&#xff0c;纵然是中国制造2025成为现实&#xff0c;精益生产模式也仍然是整个制造业的精髓之一。 首先&#xff0c;精益生产模式最重要的一根脊梁就是…...

Rust 循环

Rust 循环 在编程语言中&#xff0c;循环是一种重要的控制结构&#xff0c;它允许我们重复执行一段代码直到满足特定的条件。Rust 语言提供了多种循环方式&#xff0c;每种方式都有其特定的用途和语法。本文将详细介绍 Rust 中的循环&#xff0c;包括 loop、while、while let、…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...