数据结构 栈与队列详解!!

一.栈

 关于内存中的栈和数据结构中的栈是不同的,本章着重讲的是数据结构的栈。

 这是一张关于栈的表达图。从图中可以看出栈很像是一副卡牌,发牌时只能从上取出,即出栈。

而入栈则是像你出牌后,要把你出的牌压在上一张出的牌上面。这是入栈。

栈可以用链表或者顺序表实现,这里采用的是顺序表的结构。

1.栈的头文件 

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int StackDatatype;
typedef struct Stack
{
	StackDatatype* data;
	int capacity;
	int Top;
}ST;
void STPush(ST* pst, StackDatatype x);
void StackInit(ST* pst);
void StackDestroy(ST* pst);
void Push(ST* pst, StackDatatype x);
void Pop(ST* pst);
StackDatatype StackTop(ST* pst);
int StackSize(ST* pst);
bool StackEmpty(ST* pst);

 2.栈的初始化

void StackInit(ST* pst)
{
	assert(pst);
	pst->capacity = 0;
	pst->data = NULL;
	pst->Top = -1;
}

这里的pst->Top可以用-1,或者0.用-1的话后续你的pst->Top 所代表的下标就是栈顶元素。

如果用0 那pst-Top 之后的下标就是栈顶元素的下一个位置。这里可以自己考虑,代码的多样性。 (本章采用的是-1 的写法)

3.栈的插入

void Push(ST* pst, StackDatatype x)
{
	assert(pst);
	pst->Top++;
	JudgeCapacity(pst);
	pst->data[pst->Top] = x;
}

栈的插入就是入栈,top++ 是pst->top 指向当前即将插入元素的位置(栈顶的位置)。

后面在判断pst中的容量,不够需要扩容。把x 插入栈顶位置。 

4.栈的取出

void Pop(ST* pst)
{
	assert(pst);
	assert(pst->Top > -1);
	pst->Top--;
}

和顺序表一样只要 top--即可,不用删除,因为top -- 以后,你下次在使用该位置的时候,其实就是把原来这个位置的元素更改就可以了,不需要删除。

5.栈的栈顶元素

StackDatatype StackTop(ST* pst)
{
	assert(pst);
	return pst->data[pst->Top];
}

 这个函数的存在意义就是取当前的栈顶元素的值。

6.栈的元素个数

int StackSize(ST* pst)
{
	assert(pst);
	return pst->Top+1;
}

因为我们的Top 用的是-1开头,所以,当它指向第一个元素的时候,这时候Top == 0, 所以加一。

7.栈的判空

bool StackEmpty(ST* pst)
{
	assert(pst);
	return pst->Top == -1;
}

判断栈此时是否为空,用pst- top == -1 的判断表达式返回即可。 

8.栈的销毁

void StackDestroy(ST* pst)
{
	assert(pst);
	free(pst->data);
	pst->data = NULL;
	pst->capacity = 0;
    pst->Top = -1;
}

因为栈是创建出来的一个空间。所以最后要将这段空间free,并将所有数据都置空 

栈的容量判断

void JudgeCapacity(ST* pst)
{
	assert(pst);
	if (pst->capacity == pst->Top)
	{
		int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;
		StackDatatype* tmp = (StackDatatype*)realloc(pst->data, sizeof(StackDatatype) * newcapacity);
		if (tmp == NULL)
		{
			perror("malloc failed!");
			return;
		}
		pst->data = tmp;
		pst->capacity = newcapacity;
	}
}

 和顺序表的容量判断一样,有兴趣的可以直接去看我的顺序表详解,这里给大家简单的说一下,用三目表达式判断并赋值newcapacity,然后扩容pst->data这一段空间。

最后把扩容好的空间地址给到tmp,newcapacity给到原来的capacity。

二.队列

 上图是队列的表达图,队列如字意就像是排队一样,先进入的人,就先获得服务。

所以 队列和 栈的不同点就是出栈和出队,队列出的是头元素,而栈出的是尾元素(栈顶)

对比入队和 入栈两者相似都是尾插。

,还有队列用的是链表,栈用的是顺序表。

1.队列的头文件

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

typedef int QeDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QeDataType data;
}Qnode;
typedef struct Queue
{
	Qnode* head;
	Qnode* back;
}Qe;
void QueueInit(Qe* q);
void QueueDestroy(Qe* q);
void Queuepush(Qe* q, QeDataType x);
void QueuePop(Qe* q);
QeDataType QueueFront(Qe* q);
QeDataType QueueBack(Qe* q);
int QueueSize(Qe* q);
bool QueueEmpty(Qe* q);

 相比栈 队列多用了一个typedef 原因是,队列要记录头元素和尾元素。因为入队入的在尾部,出队出的是头部

2.队列的初始化

void QueueInit(Qe* q)
{
	assert(q);
	Qnode* newnode = CreateNode(-1);
	q->head = newnode;
	q->back = newnode;
}

 这里采用的是有头结点的队列,当然没有头结点(哨兵位)也是可以的,根据个人喜好选择。

初始化创立一个头结点(哨兵位)后,头指针和尾指针都指向头结点(哨兵位)

3.队列的插入

void Queuepush(Qe* q, QeDataType x)
{
	assert(q);
	Qnode* newnode = CreateNode(x);
	q->back->next = newnode;
	q->back = newnode;
}

 关于队列的插入,就是链表的尾插,如果链表还没明白的朋友,可以去看我之前关于单链表的博客。

4.队列的取出

void QueuePop(Qe* q)
{
	assert(q);
	assert(q->head->next);

	Qnode* next = q->head->next;
	q->head->next = next->next;
	free(next);
	next = NULL;
	if (q->head->next == NULL)
	{
		q->back = q->head;
		q->back->next = NULL;
	}
}

关于队列的取出,实质上就是链表的头删。 

5.队列的头元素

QeDataType QueueFront(Qe* q)
{
	assert(q);
	assert(q->head->next);
	return q->head->next->data;
}

 队列的头元素返回就是返回哨兵位后的第一个节点的数据。因为要返回数值,所以这个第一个节点不能为空,用assert断言。

6.队列的尾元素

QeDataType QueueBack(Qe* q)
{
	assert(q);
	assert(q->head->next);
	return q->back->data;
}

 既然要返回尾元素的数据,那就是用到尾指针,当然链表第一个节点不能为空。

7.队列的元素个数

int QueueSize(Qe* q)
{
	Qnode* size = q->head->next;
	int num = 0;
	while (size)
	{
		size = size->next;
		num++;
	}
	return num;
}

队列的元素个数,就把链表遍历一遍,用num记录遍历次数,就是元素个数。 

8.队列的判空

bool QueueEmpty(Qe* q)
{
	return q->head->next == NULL;
}

 队列的判空就是判断第一个节点是否为空,return 一个 表达式即可,也可以用if else 语句。因人而异。

创造一个节点

Qnode* CreateNode(QeDataType x)
{
	Qnode* newnode = (Qnode*)malloc(sizeof(Qnode));
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

 创造一个节点在链表的初始化和插入都会用到,在之前链表的那篇博客有讲到,偏简单。

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

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

相关文章

从C语言的面向过程编程过渡理解面向对象编程风格中的封装

黑发不知勤学早&#xff0c;白首方悔读书迟 专栏推荐Easyx学习实践 在C语言中&#xff0c;我们解决一个问题通常是采用在了解了问题如何解决后&#xff0c;设置一个一个的函数&#xff0c;依次调用实现不同的功能的函数从而解决问题&#xff0c;这种编程风格就叫做面向过程。  …

Trapezoidal Rule Integral

See https://byjus.com/maths/trapezoidal-rule/

如何用html css js 画出曲线 或者斜线;

效果图 解题思路 将图片全部定位至中心点&#xff0c;然后x轴就变动translateX &#xff0c;y轴同理&#xff1b; 这里有两个问题 浏览器&#xff1a; 以左上角为原点0&#xff0c;0 越往下y越大 数学坐标系&#xff1a;以中心点为原点0&#xff0c;0 越往下y越小&#xff1…

pyinstaller 打包pyqt6等ui文件为exe可执行程序的方法

刚开始使用auto-py-to-exe打包pyqt6的程序&#xff0c;折腾好半天都会出错&#xff0c;关键打包出来的exe单文件有快100兆了&#xff0c;真大啊&#xff01; auto-py-to-exe有图形界面&#xff0c;看起来比较直观。 还有中文语言&#xff0c;对使用者比较友善&#xff0c;可以…

【技术追踪】SAM(Segment Anything Model)代码解析与结构绘制之Mask Decoder

论文&#xff1a;Segment Anything   代码&#xff1a;https://github.com/facebookresearch/segment-anything 系列篇&#xff1a;   &#xff08;1&#xff09;【技术追踪】SAM&#xff08;Segment Anything Model&#xff09;代码解析与结构绘制之Image Encoder   &am…

LaTeX 数学公式常见问题及解决方案

本文汇总了博主在使用 LaTeX 写文档过程中遇到的所有数学公式常见问题及对应的 LaTeX 解决方案 持续更新... 目录 1. 连等式2. 公式重新开始编号2.1 图片/表格重新编号 1. 连等式 在数学公式推导过程中常常会遇到如 Figure 1 所示的连等式&#xff0c;一般需要保证等号或者不等…

消息积压了如何处理?

欢迎大家到我的博客阅读这篇文章。消息积压了如何处理&#xff1f; - 胤凯 (oyto.github.io)在系统中使用消息队列的时候&#xff0c;消息积压这个问题也经常遇到&#xff0c;并且这个问题还不太好解决。 消息积压的直接原因通常是&#xff0c;系统中的某个部分出现了性能问题…

经典ctf ping题目详解 青少年CTF-WEB-PingMe02

题目环境&#xff1a; 根据题目名称可知 这是一道CTF-WEB方向常考的知识点&#xff1a;ping地址 随便ping一个地址查看接受的数据包?ip0.0.0.0 有回显数据&#xff0c;尝试列出目录文件 堆叠命令使用’;作为命令之间的连接符&#xff0c;当上一个命令完成后&#xff0c;继续执…

Flink1.17 DataStream API

目录 一.执行环境&#xff08;Execution Environment&#xff09; 1.1 创建执行环境 1.2 执行模式 1.3 触发程序执行 二.源算子&#xff08;Source&#xff09; 2.1 从集合中读取数据 2.2 从文件读取数据 2.3 从 RabbitMQ 中读取数据 2.4 从数据生成器读取数据 2.5 …

【产品应用】一体化伺服电机在系留无人机中的应用

一体化伺服电机是一种将电机、驱动器、编码器结合在一起的伺服系统&#xff0c;具有高精度控制、快速响应和高效运行等优点。系留无人机则是一种通过绳索或链条与地面设施连接的无人机&#xff0c;能够实现长时间的稳定悬停和空中作业。 01.设备简介 电源线牵引装置&#xff1…

MATLAB Simulink和S7-1200PLC MOBUSTCP通信

MATLAB Simulink和SMART PLC OPC通信详细配置请查看下面文章链接: MATLAB和西门子SMART PLC OPC通信-CSDN博客文章浏览阅读749次,点赞26次,收藏2次。西门子S7-200SMART PLC OPC软件的下载和使用,请查看下面文章Smart 200PLC PC Access SMART OPC通信_基于pc access smart的…

人工智能-循环神经网络通过时间反向传播

到目前为止&#xff0c;我们已经反复提到像梯度爆炸或梯度消失&#xff0c; 以及需要对循环神经网络分离梯度。 例如&#xff0c;我们在序列上调用了detach函数。 为了能够快速构建模型并了解其工作原理&#xff0c; 上面所说的这些概念都没有得到充分的解释。 本节将更深入地探…

YOLO目标检测——烟雾检测数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;烟雾检测数据集可用于监控烟雾情况&#xff0c;实现火灾的早期预警。数据集说明&#xff1a;烟雾检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;含烟雾1个类别标签说明&#xff1a;使用lableimg标注软件标注&am…

Ant Design for Figma设计系统组件库 支持变量 非社区版

Ant Design for Figma 是基于 Ant Design 设计系统的 Figma 组件库&#xff0c;提供丰富的 UI 组件和交互功能&#xff0c;帮助设计师快速构建高质量的 Figma 设计稿。 Ant Design for Figma 继承了 Ant Design 的设计理念和风格&#xff0c;提供丰富的 UI 组件和交互功能&…

如何在el-tree懒加载并且包含下级的情况下进行数据回显-01

在项目中做需求&#xff0c;遇到一个比较棘手的问题&#xff0c;el-tree懒加载在包含下级的时候&#xff0c;需要做回显&#xff0c;将选中的数据再次勾选上&#xff0c;在处理这个需求的时候有两点是比较困难的&#xff1a; el-tree是懒加载的&#xff0c;包含下级需要一层一…

【10套模拟】【6】

关键字&#xff1a; 有向图入度、无向图度、一次深度优先、快速排序平均性能、折半查找、判断是否是二叉排序树、链式直接入插入排序

腾讯云服务器怎么买便宜?腾讯云服务器新人专享限时特惠购买链接

腾讯云作为国内领先的云计算服务提供商之一&#xff0c;为个人用户和企业用户提供了多种优惠活动。这些活动不仅能帮助用户节省成本&#xff0c;还能提升企业的效益。本文将介绍腾讯云的多重优惠活动&#xff0c;让用户能够以更优惠的价格购买和续费云服务器。 腾讯云双十一领…

HarmonyOS真机调试报错:INSTALL_PARSE_FAILED_USESDK_ERROR处理

1、 新建应用时选择与自己真机匹配的sdk版本 查看自己设备sdk版本 创建时先择匹配版本&#xff1a; 2、 根据报错提示连接打开处理方案 3、查询真机版本对应的compileSdkVersion 和 compatibleSdkVersion 提示3.1版本之后和3.1版本之前的不同命令&#xff08;此处为3.0版…

数学建模 | 灰色预测原理及python实现

目录 一、灰色预测的原理 二、灰色预测的应用及python实现 一、灰色预测的原理 灰色预测是以灰色模型为基础&#xff0c;灰色模型GM(n,h)是微分方程模型&#xff0c;可用于描述对象做长期、连续、动态的反应。其中&#xff0c;n代表微分方程式的阶数&#xff0c;h代表微分方…