栈和队列【详解】

目录

一、栈

1.栈的定义 

2.栈的初始化 

3.入栈 

4.出栈

 5.获取栈顶元素

6.获取栈元素的个数

 7.判断栈是否为空

8.销毁栈

二、队列

1.队列的定义

2.入队

 3.出队

4.获取队头元素

5.获取队尾元素

6.判断队列是否为空

 7.获取队列的元素个数

8.销毁队列


前言:

栈和队列也是一种常见的线性表

一、栈

1.栈的定义 

 栈:仅限在一端进行插入和删除元素操作。数据插入删除的一端称为栈顶,而另一端称为栈底

压栈:数据的插入操作。出栈:数据的删除操作。

栈中的数据遵循后进先出(Last In First Out,简称LIFO)的原则。

如图:

栈的存储定义 :

这里采用的是顺序栈,以动态数组的形式进行存放栈的元素,当栈满时,可以动态的增加栈的容量。

定义一个指针负责指向动态数组,用top来表示栈底,还有就是栈的容量capacity。

代码:

typedef int STDataType;

typedef struct StackNode 
{
	STDataType* a;
	int top; //栈底
	int capacity;  //栈的容量
}Stack;

2.栈的初始化 

当栈的存储定义完成后,就开始对栈进行初始化。

代码:

//初始化栈
/*这里采用动态数组来进行模拟栈*/
void InitStack(Stack* ps) 
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;  //指向栈顶的下一个元素
}

注意:这里定义的top 是指当top == 0 时 指向栈顶的下一个元素,当然top也可以是-1。这里采用的是top = 0。

3.入栈 

当元素入栈时,我们需要先考虑一下栈的容量的问题,例如:栈满或者初次使用栈的情况。

代码: 

//入栈
void PushStack(Stack* ps, STDataType x) 
{
	assert(ps);
	//入栈前先检查一下栈的容量
	if (ps->capacity == ps->top)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		//使用realloc直接为动态数组分配空间
		STDataType* tmp = (STDataType*)realloc(ps->a,newcapacity*sizeof(STDataType));
		if (tmp == NULL) 
		{
			perror("PushStack->realloc");//出错时提示
			return;
		}
		else 
		{
			ps->a = tmp;
			ps->capacity = newcapacity;
		}
	}

	//数据压栈
	ps->a[ps->top] = x;
	ps->top++;	//同时指向下个一个栈顶元素
}
  • 这里当初次入栈时,使用realloc进行动态分配空间,初次使用realloc 时,说明ps->a == NULL,那么这里就相当于malloc进行分配空间。
  • 栈满时,不是初次入栈就让原来的栈的容量增加二倍 (2 * ps->capacity)。
  • 栈没有满时,就直接入栈,同时top指向下一个栈顶元素。

 这里多说一下,如果对于realloc不是很理解,可以转到  realloc详细解析

注意:还有就是作者刚学realloc时,总是忘记对realloc使用sizeof(),直接给出元素个数,却忘记给出其元素的大小了。 所以不要忘记sizeof()

4.出栈

出栈需要注意的就是:当栈空了,就不能进行出栈了,这里采用断言assert来避免

代码:

//出栈
void PopStack(Stack* ps) 
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;    //栈顶减一即可
}

 5.获取栈顶元素

这里也要注意栈为空的情况

 代码:

//获取栈顶元素
STDataType TopStack(Stack* ps) 
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}

如图:

6.获取栈元素的个数

因为top是从0开始的,下标:0 到 top-1,就相当于有top个元素。

 代码:

//获取栈元素的个数
int SizeStack(Stack* ps) 
{
	assert(ps);
	return ps->top;
}

 7.判断栈是否为空

这里采用bool 返回类型,如果为空就返回的是true ,不为空就返回false。

//判断栈是否为空,空返回true,非空返回false
bool EmptyStack(Stack* ps) 
{
	assert(ps);
	return ps->top == 0;
}

8.销毁栈

为避免内存泄漏,我们应该养成及时释放内存的好习惯。

  代码:

//销毁栈
void DestroyStack(Stack* ps) 
{
	assert(ps);
	free(ps->a);   //释放指向的动态数组
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

二、队列

1.队列的定义

队列:只允许一端进行插入元素(队尾),另一端机进行删除元素(队头)的线性表。 

进队:数据的插入操作  出队:数据的删除操作

队列中的数据遵循先进先出(First In First Out,简称FIFO)的原则。

如图:

队列的存储定义: 这里是通过单链表的形式来进行模拟队列。同时定义两个指针来进行控制,一个指向队头,另一个指向队尾。这样就可以避免再从头开始遍历链表来找尾了。

代码:

typedef int QDataType;

//通过单链表来模拟队列
typedef struct QueueNode 
{
	QDataType val;
	struct QueueNode* next; //记录下一个结点的地址
}QueueNode;

typedef struct Queue 
{
	QueueNode* phead;	//指向队头的指针
	QueueNode* tail;	//指向队尾的指针
	int size;	//同时记录栈元素的个数
}Queue;

2.入队

元素入队,通过单链表进行尾插来模拟队列的入队。

在入队的操作中,采取使用malloc动态内存函数来开辟内存空间存放元素。因为是尾插,所以这里我们就要提前判断一下是否为第一次入队(尾插),当然这里也可以不用判断(前提就是要有头结点)。 因为这里没有用头结点,所以需要判断一下。

代码:

//入队
void PushQueue(Queue* pq, QDataType x) 
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL )
	{
		perror("PushQueue->malloc");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;
	//判断是否为第一次进行入队
	if (pq->phead == NULL) 
	{
		//第一次入队
		pq->phead = pq->tail = newnode;
	}
	else 
	{
		//不是第一次入队直接进行尾插
		pq->tail->next = newnode;
	}
	pq->size++;//队列元素加一
}

 3.出队

元素出队,这里通过单链表的头删进行模拟出队。出队需要注意的是队列不能为空那个,所以这里使用assert来断言进行避免

代码:

//出队
void PopQueue(Queue* pq) 
{
	assert(pq);
	assert(pq->phead);
	QueueNode* next = pq->phead->next;
	free(pq->phead);
	pq->phead = next;
	//当出队最后一个元素时
	//出完队后,headz指向空,而tail却变成了访问野指了
	//所以这里要对删的是最后一个元素进行单独处理
	if (pq->phead == NULL)
	{
		pq->tail = NULL;
	}
	pq->size--;
}

4.获取队头元素

需要注意的是:队为空的情况。使用assert断言来避免

代码:

//获取队头元素
QDataType TopQueue(Queue* pq) 
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

5.获取队尾元素

当然这里也要避免队尾为空的情况

代码:

//获取队尾元素
QDataType TailQueue(Queue* pq) 
{
	assert(pq);
	assert(pq->tail);
	return pq->tail->val;
}

6.判断队列是否为空

队列为空就返回true,否则返回false

代码:

//判断队列是否为空
bool EmptyQueue(Queue* pq) 
{
	assert(pq);
	return pq->phead == NULL;
}

 7.获取队列的元素个数

返回size

 代码:

//获取队列元素的个数
int SizeQueue(Queue* pq)
{
	assert(pq);
	return pq->size;
}

8.销毁队列

  代码:

//销毁队列
void DestroyQueue(Queue* pq) 
{
	assert(pq);
	QueueNode* cur = pq->phead;
	while (cur)
	{
		QueueNode* next = cur->next; //记录下一个结点
		free(cur);
		cur = next;
	}
	pq->phead = pq->tail = 0;
	pq->size = 0;
}

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

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

相关文章

el-input限制输入整数等分析

文章目录 前言1、在 Vue 中,可以使用以下几种方式来限制 el-input 只能输入整数1.1 设置input 的 type为number1.2 使用inputmode1.3 使用自定义指令1.4 使用计算属性1.5 使用 onafterpaste ,onkeyup1.6 el-input-number 的precision属性 总结 前言 input 限制输入…

python命令行交互 引导用户输入一个数字

代码 以下代码将在命令行中,引导用户选择一个数字,并反馈用户输入的值 # -*- coding:UTF-8 -*- """ author: dyy contact: douyaoyuan126.com time: 2023/11/22 15:51 file: 引导用户输入一个数字.py desc: xxxxxx """#…

D. Absolute Beauty - 思维

题面 分析 补题。配上题解的图,理解了很长时间,思维还需要提高。 对于每一对 a i a_i ai​和 b i b_i bi​,可以看作一个线段的左右端点,这是关键的一步,那么他们的绝对值就是线段的长度,对于线段相对位…

C++ MiniZip实现目录压缩与解压

Zlib是一个开源的数据压缩库,提供了一种通用的数据压缩和解压缩算法。它最初由Jean-Loup Gailly和Mark Adler开发,旨在成为一个高效、轻量级的压缩库,其被广泛应用于许多领域,包括网络通信、文件压缩、数据库系统等。其压缩算法是…

Doris数据模型的选择建议(十三)

Doris 的数据模型主要分为 3 类:Aggregate、Uniq、Duplicate Aggregate: Doris 数据模型-Aggregate 模型 Uniq:Doris 数据模型-Uniq 模型 Duplicate:Doris 数据模型-Duplicate 模型 因为数据模型在建表时就已经确定,且无法修改…

焦炉加热系统简述

烟道吸力 焦炉负压烘炉分烟道的吸力会影响立火道温度,具体影响因素如下: 烟道吸力过大会导致热量被抽走,使立火道温度降低。烟道吸力不足会导致烟气在烘炉内停留时间过长,使热量无法充分利用,也会导致立火道温度降低…

安防监控视频融合平台EasyCVR定制化页面开发

安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。安防视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、云存储、回放与检索…

元素的点击操作

元素的点击操作 .click 语法 // 单击某个元素 .click()// 带参数的单击 .click(options)// 在某个位置点击 .click(position)// 在某个位置点击,且带参数 .click(position, options)// 根据页面坐标点击 .click(x, y)// 根据页面坐标点击,且带参数 .c…

冷链运输车辆GPS定位及温湿度管理案例

1.项目背景 项目名称:山西冷链运输车辆GPS定位及温湿度管理案例 项目需求:随着经济发展带动物流行业快速发展,运输规模逐步扩大,集团为了适应高速发展的行业现象,物流管理系统的完善成了现阶段发展的重中之重。因此&…

Elasticsearch:FMA 风格的向量相似度计算

作者:Chris Hegarty 在 Lucene 9.7.0 中,我们添加了利用 SIMD 指令执行向量相似性计算的数据并行化的支持。 现在,我们通过使用融合乘加 (Fused Mulitply-Add - FMA) 进一步推动这一点。 什么是 FMA 乘法和加法是一种常见的运算,…

echarts实现如下图功能代码

这里写自定义目录标题 const option {tooltip: {trigger: axis},legend: {left: "-1px",top:15px,type: "scroll",icon:rect,data: [{name:1, textStyle:{color: theme?"#E5EAF3":#303133,fontSize:14}}, {name: 2, textStyle:{color: theme…

超详细 | 实验室linux服务器非root账号 | 安装pip | 安装conda

登录实验室公用服务器,个人账号下(非root)是空的,啥也没有,想安装下pip和conda。 转了一圈,好像没太有针对这个需求写具体博客的,但有挺多讲直接在root下安的(用的应该是个人虚拟机&…

【面试HOT300】滑动窗口篇

系列综述: 💞目的:本系列是个人整理为了秋招面试的,整理期间苛求每个知识点,平衡理解简易度与深入程度。 🥰来源:材料主要源于【CodeTopHot300】进行的,每个知识点的修正和深入主要参…

【Vue】生命周期一文详解

目录 前言 生命周期 钩子函数使用方法 ​编辑 周期-----创建阶段 创建阶段做了些什么事 该阶段可以干什么 周期----挂载阶段 挂载阶段做了什么事 该阶段适合干什么 周期----更新阶段 更新阶段做了什么事 该阶段适合做什么 周期----销毁阶段 销毁阶段做了什么事 …

图解系列--密钥,随机数,应用技术

密钥 1.生成密钥 1.1.用随机数生成密钥 密码学用途的伪随机数生成器必须是专门针对密码学用途而设计的。 1.2.用口令生成密钥 一般都是将口令输入单向散列函数,然后将得到的散列值作为密钥使用。 在使用口令生成密钥时,为了防止字典攻击,需要…

【追求卓越13】算法--深度和广度优先算法

引导 前面的几个章节,我们介绍了树这种数据结构,二叉搜索树在进行查找方面比较高效;有二叉树演变来的堆数据结构在处理优先级队列,top K,中位数等问题比较优秀;今天我们继续介绍新的数据结构——图。它在解…

【20年扬大真题】编写程序,功能是给a数组输入30个数据,并以每行5个数据的形式输出

【20年扬大真题】编写程序&#xff0c;功能是给a数组输入30个数据&#xff0c;并以每行5个数据的形式输出 #include<stdio.h> int main() {int arr[30] { 0 };int i 0;printf("请输入30个数据&#xff1a;");for (i 0;i < 30;i){scanf("%d", …

C语言—指针入门

内存存放数据 如果发送指令&#xff0c;读取f变量的内容&#xff0c;则先找f - >10005这个字节&#xff0c;然后再找到123。 指针和指针变量 通常说的指针就是地址的意思&#xff0c;C中有专门的指针变量存放指针。一个指针占4个字节。 定义指针变量 类型名 *指针变量名…

童装店铺如何通过软文增加客流量

在信息超负载、媒介粉尘化、产品同质化多重因素下&#xff0c;传统营销疲态尽显、日渐式微&#xff0c;很难支撑新环境下品牌和企业的持续增长。聚焦童装行业更是如此&#xff0c;一方面用户迭代速度快&#xff0c;另一方面&#xff0c;新时代父母的育儿观念更加精细化&#xf…