数据结构篇其四---栈:后进先出的魔法世界

前言

栈的学习难度非常简单,前提是如果你学过顺序表和单链表的话,我直接说我的观点了,栈就是有限制的顺序表和单链表。

栈只允许一端进行插入删除。栈去除了各种情况复杂的插入删除,只允许一端插入删除的特性,这一种数据结构在实际应用场景非常有价值。

栈的概念

栈是一种线性表,其中只允许固定的一段进行插入删除元素操作。

其中进行数据插入和删除操作的一端称为栈顶;

另一端称为栈底。

栈中数据遵循一个元素LIFO(Last In Fast Out),后进先出原则。

栈有一句话概括了它的特点:先进后出,后进先出。

进栈与出栈一图流搞定。

栈的定义

栈分两种存储结构:

1.顺式存储结构,比如前面的顺序表。顺序表可以通过静态数组和动态数组实现。

那么栈的顺式存储结构也能通过静态数组和动态数组实现。这种栈称为数组栈。

2.链式存储结构,比如链表(这里指单链表)。栈也能像单链表那样的结构定义,这种栈称为链表栈。

数组栈(顺序栈)

数组有定长数组和动态数组。

选择数组下标为0为栈底,选择存储有效数据最远的为栈顶。

对于静态数组的栈,不妨我们称做静态(数组)栈。

要素

1.定长数组。

2.栈顶指针(用于记录当前位置)。

注意:栈顶指针不一定是真的指针,这里可以数数组下标,因为数组在内存中连续存储的特性,用下标也就是在用指针。

对于复杂数据类型,还是离不开结构体。如下:

#define NUM_MAX 100//看情况调整
typedef int STDataType;
typedef struct Stack
{
	STDataType arr[NUM_MAX];//定长数组
	int top;//栈顶指针
}ST;

tip:这里的top其实就是静态顺序表的size,只是换了一个变量名。

这里换成top其实是要养成良好的取名风格,方便后续的学习。 

 后面针对动态数组实现的栈,我们不妨称为动态(数组)栈

要素:

1.栈数据类型的一级指针;用于动态内存分配

2.栈顶指针;(前面解释过,不在解释)

3.容量大小;(动态数组不会记住当前已有的空间大小,需要额外引入变量记录)

总结:用结构体,和动态顺序表一模一样,除了size改了个名叫top。

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

链式栈  

首先选择什么类型链表结构,链表结构合计8种,由于进栈出栈限定在一端操作,单链表就适合。(栈不适合带头结点的单链表)

哪端作为栈顶,另一端作为栈底呢?

由于单链表的单向性且要符合栈的LIFO特性。

头指针指向处为栈顶,尾结点处为栈底。

typedef int STDataType;
typedef struct Stack
{
	struct Stack* next;
	STDataType data;
}ST;

您可能想问,这不就是单链表吗,跟链式栈有什么区别?

不不不,单链表还有一个关键的东西----头指针。

头指针和栈顶指针合二为一了。接下来只要用该结构体实现栈的相关函数,就可以明显区分单链表和链式栈的差别了。

ST* top = NULL;//创建一个链式栈

栈的实现(用动态数组栈实现)

数组栈比链式栈更简单,所以我们优先实现数组栈。

这里出栈进栈等价于顺序表的尾删和尾插,顺序表处理这方面效率是最高的。

显然用顺序栈(数组栈),前排提醒:实现顺序表可以说相当简单。

这里选择数组栈的动态数组的方式实现。



#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>


typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

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

//栈的销毁
void STDestroy(ST* pst);

//压栈/进栈/入栈
void STPush(ST* pst,STDataType x);

//出栈
void STPop(ST* pst);

//获取栈顶元素
STDataType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//栈上合计多少个元素个数
int STsize(ST* pst);

 

栈的初始化

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	//pst->top = -1;//top指向最新插入的数据

	//以这个为例
	pst->top = 0;//top指向当前有效数据的下一个位置。
	pst->capacity = 0;//容量大小

}

栈的销毁 

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);//释放动态开辟空间

	//以下同初始化
	pst->a = NULL;
	pst->top = pst->capacity = 0;//置空

}


压栈函数

void STPush(ST* pst,STDataType x)
{
	assert(pst);

	//动态增容
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));//给动态数组开辟空间
		if (tmp == NULL)//判断空间是否开辟失败
		{
			perror("realloc fail");
			return;
		}

		pst->a = tmp;//开辟成功赋值
		pst->capacity = newcapacity;
	}
	pst->a[pst->top++] = x;
}

出栈函数

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));//空栈不能删除
	pst->top--;//直接改变栈顶即可
}

栈顶元素函数

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));//空栈没有元素了
	return pst->a[pst->top-1];
}

判断空栈函数

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


计算栈的长度

int STsize(ST* pst)
{
	assert(pst);
	return pst->top;//返回当前栈上的元素个数。
}

总源代码

请自行迁移用静态数组和单链表表示栈。

#include<stdio.h>
#include<stdbool.h>//bool类型
#include<stdlib.h>//realloc动态内存函数
#include<assert.h>//assert断言

//结构体声明定义
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

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

//栈的销毁
void STDestroy(ST* pst);

//压栈/进栈/入栈
void STPush(ST* pst, STDataType x);

//出栈
void STPop(ST* pst);

//获取栈顶元素
STDataType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//栈上合计多少个元素个数
int STsize(ST* pst);


void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	//pst->top = -1;//top指向最新插入的数据

	//以这个为例
	pst->top = 0;//top指向当前有效数据的下一个位置。
	pst->capacity = 0;//容量大小

}

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);//释放动态开辟空间

	//以下同初始化
	pst->a = NULL;
	pst->top = pst->capacity = 0;//置空

}
void STPush(ST* pst,STDataType x)
{
	assert(pst);

	//动态增容
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));//给动态数组开辟空间
		if (tmp == NULL)//判断空间是否开辟失败
		{
			perror("realloc fail");
			return;
		}

		pst->a = tmp;//开辟成功赋值
		pst->capacity = newcapacity;
	}
	pst->a[pst->top++] = x;
}

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));//空栈不能删除
	pst->top--;//直接改变栈顶即可
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));//空栈没有元素了
	return pst->a[pst->top-1];
}

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


int STsize(ST* pst)
{
	assert(pst);
	return pst->top;//返回当前栈上的元素个数。
}

int main()
{
	ST st;
	STInit(&st);
	STPush(&st, 1);
	STPush(&st, 2);
	STPush(&st, 3);
	STPush(&st, 4);
	STPush(&st, 5);
	STPush(&st, 6);
	while (!STEmpty(&st))
	{
		printf("%d", STTop(&st));
		STPop(&st);
	}

	STDestroy(&st);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/592129.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5月4(信息差)

&#x1f384; HDMI ARC国产双精度浮点dsp杜比数码7.1声道解码AC3/dts/AAC环绕声光纤、同轴、USB输入解码板KC33C &#x1f30d; 国铁集团回应高铁票价将上涨 https://finance.eastmoney.com/a/202405043066422773.html ✨ 源代码管理平台GitLab发布人工智能编程助手DuoCha…

【数据结构】您有一份KMP算法教学已到账,请注意查收!!!

KMP算法 导读一、KMP算法1.1 重要术语1.2 部分匹配值1.3 部分匹配值的作用 二、KMP算法原理2.1 从指针的角度理解KMP算法2.2 从匹配的角度理解KMP算法2.3 小结 三、KMP算法的实现3.1 next数组3.2 next数组的计算3.2.1 通过PM值计算next数组3.2.2 通过移位模拟计算next数组3.2.3…

Web Storage 笔记11 网页数据存储

相关内容&#xff1a;Web Storage基本概念、localStorage、sessionStorage、登录注销实例、…… 在制作网页时会希望记录一些信息&#xff0c;例如用户登录状态、计数器或者小游戏等&#xff0c;但是又不希望用到数据库&#xff0c;就可以利用WebStorage技术将数据存储在用户浏…

Kubelet containerd 管理命令 ctr常用操作

镜像常用操作 1. 拉取镜像 ctr images pull docker.io/library/nginx:alpine 指定平台 --all-platforms&#xff1a;所有平台&#xff08;amd64 、arm、386 、ppc64le 等&#xff09;&#xff0c;不加的话下载当前平台架构 --platform&#xff1a;指定linux/amd64平台 ctr …

鸿蒙开发仿咸鱼TabBar

鸿蒙开发自定义TabBar&#xff0c;实现tabBar 上中间按钮凸起效果 第一步、定义数据模型 export default class TabItemData{defaultIcon: ResourceselectedIcon: Resourcetitle: stringisMiddle: booleanconstructor(defaultIcon:Resource, selectedIcon:Resource, title:st…

并发-启动线程的正确姿势

目录 启动线程的正确姿势 Start方法原理解读 Run方法原理解读 常见问题 启动线程的正确姿势 start()与run()方法的比较测试结果可以看出&#xff0c;runnable.run()方法是由main线程执行的&#xff0c;而要子线程执行就一定要先调用start()启动新线程去执行run方法并不能成…

【数据结构】第四讲:双向链表

目录 一、链表的分类 二、双向链表的结构及实现 1.带头双向链表的结构 2.创建节点 3.初始化 4.尾插 5.打印 6.头插 7.尾删 8.头删 9.在pos位置之后插入数据 10.删除pos节点 11.查找 12.销毁 个人主页&#xff1a;深情秋刀鱼-CSDN博客 数据结构专栏&#xff1a;数…

Mac M2 本地下载 Xinference

想要在Mac M2 上部署一个本地的模型。看到了Xinference 这个工具 一、Xorbits Inference 是什么 Xorbits Inference&#xff08;Xinference&#xff09;是一个性能强大且功能全面的分布式推理框架。可用于大语言模型&#xff08;LLM&#xff09;&#xff0c;语音识别模型&…

激动,五四青年节,拿下YashanDB认证YCP

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验&#xff0c; Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、My…

中间件之搜索和数据分析组件Elasticsearch

一、概述 1.1介绍 The Elastic Stack, 包括 Elasticsearch、Kibana、Beats 和 Logstash&#xff08;也称为 ELK Stack&#xff09;。 能够安全可靠地获取任何来源、任何格式的数据&#xff0c;然后实时地对数据进行搜索、分析和可视 化。Elaticsearch&#xff0c;简称为 ES&a…

CUDA和显卡驱动

1.安装显卡驱动 https://www.nvidia.com/download/index.aspx?langen-us 由于我的显卡是RTX4060&#xff0c;因此先选择RTX40系列&#xff0c;然后选择RTX4060&#xff0c;进行安装 2.查看显卡对应的CUDA CUDA安装地址&#xff1a;https://developer.nvidia.com/cuda-toolk…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-12-蜂鸣器

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

复旦微JFM7VX690计算后IO接口模块,用于雷达信号处理、数据处理等需要高速密集计算的应用场景

计算后IO接口模块 1 介绍 1.1 产品概述 计算后IO接口模块主要由复旦微JFM7VX690型FPGA、国产以太网收发器YT8521、国产BMC芯片GD32F450、国产CPLD芯片EF2L45BG256B、国产内存颗粒等主要芯片组成&#xff0c;采用标准6U VPX尺寸设计。 本计算后IO接口模块主要用于雷达信号处…

QT+串口调试助手+基本版

一、创建串口调试助手UI界面 1、首先生成串口连接必要参数界面&#xff0c;删除关闭串口控件 2、给参数下拉框添加常见的选项&#xff0c;删除关闭串口控件 3、将串口调试助手参数界面布局整齐&#xff0c;删除关闭串口控件 4、更改控件名字&#xff0c;方便后续编程&#xff…

第五篇:通信脉络:探索计算机外设与总线体系的精髓

通信脉络&#xff1a;探索计算机外设与总线体系的精髓 1 引言 在这个技术日新月异的时代&#xff0c;理解计算机系统的基本构成要素 —— 总线和外设 —— 对于每个从事技术工作的人来说都是至关重要的。这些组件不仅是计算机通信的基石&#xff0c;也直接影响着系统的性能、效…

Universal Thresholdizer:将多种密码学原语门限化

参考文献&#xff1a; [LS90] Lapidot D, Shamir A. Publicly verifiable non-interactive zero-knowledge proofs[C]//Advances in Cryptology-CRYPTO’90: Proceedings 10. Springer Berlin Heidelberg, 1991: 353-365.[Shoup00] Shoup V. Practical threshold signatures[C…

关于MS-DOS时代的回忆

目录 一、MS-DOS是什么&#xff1f; 二、MS-DOS的主要功能有哪些&#xff1f; 三、MS-DOS的怎么运行的&#xff1f; 四、微软开源MS-DOS源代码 五、高手与漂亮女同学 一、MS-DOS是什么&#xff1f; MS-DOS&#xff08;Microsoft Disk Operating System&#xff09;是微软公…

多线程与信号量简介

信号量与 PV 操作 计算机中信号量的本质是整数&#xff0c;数值表示可用的资源数量 P 操作 (Passeren > 通过, 原子操作) 若信号量 0&#xff0c;当前任务阻塞 (进入信号量等待队列)若信号量 > 0&#xff0c;则&#xff1a;将信号量数值减一&#xff0c;当前任务继续执…

USP技术提升大语言模型的零样本学习能力

大语言模型&#xff08;LLMs&#xff09;在零样本和少样本学习能力上取得了显著进展&#xff0c;这通常通过上下文学习&#xff08;in-context learning, ICL&#xff09;和提示&#xff08;prompting&#xff09;来实现。然而&#xff0c;零样本性能通常较弱&#xff0c;因为缺…

KMP算法--C语言实现

#include <stdio.h> #include <assert.h> #include <string.h> #include <stdlib.h>void GetNext(char* sub, int next[]) {int lenSub strlen(sub);next[0] -1; // 初始第一个为 -1 第二个为 0next[1] 0;int i 2;int k 0;while (i < lenSub){…