数据结构·栈和队列

1. 栈

1.1 栈的概念及结构

        栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶,另一端称为栈底。

        栈中的数据元素遵守 后进先出 LIFO(Last In First Out)的原则,后进来的数据先出去

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

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

                        

1.2  栈的实现

        我们先分析一下,栈我们应该用顺序表还是链表实现?

        栈中的数据的插入和删除都是在栈顶实现的,不需要随机位置的插入删除,此时链表的优势就不大了。相比之下顺序表还有内存命中率高的优点,所以最后我们选择用顺序表实现栈

                                

        头文件,源文件,测试文件这里我就不展示了,直接写栈中功能的实现

1.2.1 栈的初始化和销毁

        这个没什么好说的,直接上代码

1.2.2 判断栈是否真是空

        

1.2.3 压栈

        压栈涉及到扩容,如果栈内空间不够就要扩容,栈满的判断标准就是 栈顶top 和 总空间大小capacity 数值相同,然后压完之后不要忘记top++

1.2.4 出栈

        这个很简单,让栈顶回退一个位置就行了

                ​​​​​​​        

1.2.5 取栈顶元素

        这里要注意我们在取栈顶的时候要取 top-1 因为我们在初始化的时候设定的top为0,实际上此时的栈顶指向了一个空的位置,之后我们每压一次栈top都会向后移动一下,指向下一个空的位置,所以我们实际取栈顶的时候要 top-1 或者说,top是指向了栈顶的下一个元素

        ​​​​​​​​​​​​​​        ​​​​​​​        

1.2.6 返回栈的大小(多少有效数据)

        这没啥好说的,上代码

        

1.3 栈的完整代码

        Stack.h

#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* ps);
void STDestory(ST* ps);//压栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);//取栈顶元素
STDataType STTop(ST* ps);int STSize(ST* ps);bool STEmpty(ST* ps);

        Stack.c

#include"Stack.h"//初始化
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}//销毁
void STDestory(ST* ps)
{free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}//压栈
void STPush(ST* ps, STDataType x)
{assert(ps);//满了,要扩容if (ps->top == ps->capacity){//防止是第一次扩容,所以要判断一下int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;	STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");exit(-1);}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;
}//出栈
void STPop(ST* ps)
{assert(ps);//栈不为空才能删assert(!STEmpty(ps));ps->top--;
}//取栈顶元素
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top-1];
}//返回栈的大小(多少有效数据)
int STSize(ST* ps)
{assert(ps);return ps->top;
}//判断栈是否真是空
bool STEmpty(ST* ps)
{assert(ps);//如果真是空就返回真//如果不是空就返回假return ps->top == 0;
}

2. 队列

2.1 队列的概念及结构

        队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(first in first out)特点

        入队列:进行插入操作的一端为队尾

        出队列:进行删除操作的一端为队头

        ​​​​​​​        ​​​​​​​        

2.2 队列的实现

        首先我们分析一下应该怎么实现队列

        如果用顺序表的话,数据从前向后依次存放,此操作还比较方便,但是到删除时,从前向后删除,每删一个元素,就要将后面的元素向前挪一位,时间复杂度O(N)

        所以推荐使用链表解决问题,尾插数据,头删数据,就像上面画的那个类似管道的示意图一样,此时问题又来了,尾插数据需要遍历链表,这样时间复杂度的问题依旧没解决,怎么办?

        解决方案就是我们再引入一个新的结构体,专门用来维护这条链表,新的结构体中存放这个链表的头节点和尾节点的地址,还有这个链表的长度,这样只需将新节点尾插到ptail后面就好了,不用遍历链表了。

        创建链表节点:

        ​​​​​​​        ​​​​​​​        

        创建新结构体用于维护链表:

                        

        之后在主函数中用也这个新结构体来代替链表头节点进行传参,或者说这个新结构体代替的整条链表,而链表头节点只是一个节点,孰强孰弱,一目了然。

2.2.1 队列的初始化和销毁

        因为我们创建的链表是不带头的,所以初始化都是无脑置空就好

        

        

2.2.2 队列中剩余元素

        ​​​​​​​        ​​​​​​​ 

2.2.3 入队列

2.2.4 出队列

        出队列要注意链表的三种状态,分别是链表尾空、链表只有一个节点、链表有多个节点。为空的情况用断言处理,多个节点就正常删除头节点就行,但是要注意只有一个节点的时候要处理ptail 否则它将变成野指针

        ​​​​​​​        

2.2.5 取队头、取队尾

        ​​​​​​​        

        ​​​​​​​        

2.2.6 判断队列为空

                

2.3 队列的完整代码

        Queue.h

#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int QDataType;
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;//初始化
void QueueInit(Queue* pq);//销毁
void QueueDestory(Queue* pq);//入队列
void QueuePush(Queue* pq, QDataType x);//出队列
void QueuePop(Queue* pq);//取队头
QDataType QueueFront(Queue* pq);//取队尾
QDataType QueueBack(Queue* pq);//判断队列为空
bool QueueEmpty(Queue* pq);//队列中剩余元素
int QueueSize(Queue* pq);

        Queue.c

#include"Queue.h"//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}//销毁
void QueueDestory(Queue* pq)
{assert(pq);QNode* cur = pq->phead;QNode* next = NULL;while (cur){next = cur->next;free(cur);cur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}//入队列
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode=(QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}//出队列
void QueuePop(Queue* pq)
{assert(pq);//保正头部有的删assert(pq->phead);QNode* next = pq->phead->next;//当只有一个节点时,要处理ptailif (pq->phead == pq->ptail){pq->ptail = NULL;}free(pq->phead);pq->phead = next;pq->size--;
}//取队头
QDataType QueueFront(Queue* pq)
{assert(pq);//取队头前提是有队头assert(pq->phead);return pq->phead->val;
}//取队尾
QDataType QueueBack(Queue* pq)
{assert(pq);//取队尾前提是有队尾assert(pq->ptail);return pq->ptail->val;
}//判断队列为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}//队列中剩余元素
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8 DeepSORT实现智能交通监控-改进yolo单目测距及速度测量-流量计数

YOLOv8 DeepSORT是一种基于目标检测和跟踪技术的智能交通监控系统。它基于YOLOv8&#xff0c;通过加入DeepSORT算法实现目标跟踪&#xff0c;同时还改进了YOLOv8的单目测距及速度测量技术和流量计数功能。 该系统可以通过摄像头或视频源实时捕获图像&#xff0c;并自动检测和跟…

web安全学习笔记【20】——信息打点(10)

信息打点-公众号服务&Github监控&供应链&网盘泄漏&证书图标邮箱资产 #知识点&#xff1a; 1、业务资产-应用类型分类 2、Web单域名获取-接口查询 3、Web子域名获取-解析枚举 4、Web架构资产-平台指纹识别 ------------------------------------ 1、开源-CMS指纹…

【刷题】 Leetcode 1022.从根到叶的二进制数之和

刷题 1022.从根到叶的二进制数之和题目描述&#xff1a;思路一&#xff08;dfs深搜万能版&#xff09;思路二 &#xff08;栈迭代巧解版&#xff09;总结 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&#xff…

SpringBoot 自定义注解实现操作日志记录

文章目录 前言正文一、项目结构介绍二、核心类2.1 核心注解2.1.1 CLog 日志注解2.1.2 ProcessorBean 处理器bean 2.2 切面类2.3 自定义线程池2.4 工具类2.4.1 管理者工具类 2.5 测试2.5.1 订单创建处理器2.5.2 订单管理者2.5.3 订单控制器2.5.4 测试报文2.5.5 测试结果 附录1、…

【Java题】调整奇数位于偶数之前(超简单版)

题目&#xff1a; 调整数组顺序使得奇数位于偶数之前。调整之后&#xff0c;不关心大小顺序。 如数组&#xff1a;[1,2,3,4,5,6,7,8,9] 调整后可能是&#xff1a;[1, 9,3,7,5, 6, 4, 8, 2] 代码&#xff1a; import java.util.Arrays;public class Main {public static voi…

将python程序打包为exe格式

1. 安装pyinstaller winr打开命令窗口 输入&#xff1a; pip install pyinstaller输入命令后会自动安装pyinstaller 2. 打包 进入你的代码所在位置&#xff0c;输入cmd 在弹出的窗口中输入 pyinstaller --onefile your_script.pyyour_script.py修改为你需要打包的程序名字 …

ElasticSearch架构介绍及原理解析

ElasticSearch架构介绍及原理解析文章目录 一、Elasticsearch是什么&#xff1f;1.简介2.历史与发展3.有关概念1.cluster2.shards3.replicas4.recovery5.river6.gateway7.discovery.zen8.Transport 4.安装 二、ElasticSearch架构介绍及原理解析1.基本架构1.1 进程节点1.2 负载均…

简述操作系统内存管理

这篇可是真枯涩啊&#xff0c;哈哈&#xff0c;老早在学操作系统的时候整理的文章&#xff0c;没加润色&#xff0c;单纯从个人网站迁移过来。 操作系统内存管理的目的是将线性物理地址用抽象的逻辑地址空间&#xff0c;从而保护物理地址。此外&#xff0c;可以独立地址空间&am…

07-Linux部署Nginx

Linux部署Nginx 简介 NGINX是一款高性能的HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP代理服务器。它的特点包括占用内存少、并发能力强&#xff0c;因此在处理高负载和高并发的场景时表现优秀。NGINX由俄罗斯的程序设计师Igor Sysoev开发&#xff0c;最初是为俄…

Windows Docker 部署 SQL Server

部署 SQL Server 打开 Docker Desktop&#xff0c;切换到 Linux 内核。然后在 PowerShell 执行下面命令&#xff0c;即可启动一个 SQL Server 服务&#xff0c;这里安装的是 2022 年版本 docker run -e "ACCEPT_EULAY" -e "MSSQL_SA_PASSWORDSQL123abcABC!&qu…

Spring 事务传播机制

事务传播机制&#xff1a;多个事务⽅法存在调⽤关系时, 事务是如何在这些⽅法间进⾏传播的。 ⽐如&#xff1a;有两个⽅法A&#xff0c;B都被 Transactional 修饰,&#xff0c;A⽅法调⽤B⽅法 A⽅法运⾏时, 会开启⼀个事务。当A调⽤B时&#xff0c; B⽅法本⾝也有事务&#xf…

59.仿简道云公式函数实战-文本函数-RMBCAP

1. RMBCAP函数 RMBCAP 函数可以将金额小写转换为人民币大写金额形式。 2. 函数用法 RMBCAP(数字) 3. 函数示例 如&#xff0c;在财务结算、报销管理、对公付款等场景中&#xff0c;可以利用 RMBCAP 函数将金额转换为大写&#xff0c;避免被篡改产生的负面影响 4. 代码实战…

Socket网络编程(一)——网络通信入门基本概念

目录 网络通信基本概念什么是网络&#xff1f;网络通信的基本架构什么是网络编程?7层网络模型-OSI模型什么是Socket&#xff1f;Socket的作用和组成Socket传输原理Socket与TCP、UDP的关系CS模型(Client-Server Application)报文段牛刀小试&#xff08;TCP消息发送与接收&#…

江科大stm32学习笔记——【5-2】对射式红外传感器计次旋转编码计次

一.对射式红外传感器计次 1.原理 2.硬件连接 3.程序 CountSensor.c: #include "stm32f10x.h" // Device header #include "Delay.h"uint16_t CountSensor_Count;void CountSensor_Init(void) {//配置RCC时钟&#xff1a;RCC_APB2Perip…

前端架构: 脚手架之包管理工具的案例对比及workspaces特性的使用与发布过程

npm的workspaces 特性 1 &#xff09;使用或不使用包管理工具的对比 vue-cli 这个脚手架使用 Lerna 管理&#xff0c;它的项目显得非常清晰在 vue-cli 中包含很多 package 点开进去&#xff0c;每一个包都有package.json它里面有很多项目&#xff0c;再没有 Lerna 之前去维护和…

SpringCloudNacos注册中心服务分级存储模型

文章目录 服务分级存储模型概述配置集群同集群优先的负载均衡 权重配置总结 之前对 Nacos注册中心入门 已经做了演示. 这篇文章对 Nacos 的服务分级存储模型做理论与实践. 服务分级存储模型概述 一个服务可以有多个实例&#xff0c;例如我们的 user-server&#xff0c;可以有:…

C#使用iText7给PDF文档添加书签

上一篇文章将SqlSugar官网文档中每个链接对应的网页生成独立PDF文档再合并为单个PDF文档&#xff0c;但是没有书签&#xff0c;八百多页的内容查找和跳转都不方便&#xff0c;本文学习和使用iText7给PDF文档添加多级书签。   添加多级书签分为两大步骤&#xff1a;1&#xff…

VR全景HDR拍摄教程

什么是HDR&#xff1f; HDR可以用在哪里&#xff1f; 书面解释&#xff1a;HDR&#xff08;高动态范围 High Dynamic Range&#xff09;摄影&#xff0c;是摄影领域广泛使用的一种技术。 是不是有点懵&#xff1f; 我们来看一个实际的拍摄现场环境&#xff0c;你就懂了 我们…

使用 Gradle 版本目录进行依赖管理 - Android

/ 前言 / 在软件开发中&#xff0c;依赖管理是一个至关重要的方面。合理的依赖版本控制有助于确保项目的稳定性、安全性和可维护性。 Gradle版本目录&#xff08;Version Catalogs&#xff09;是 Gradle 构建工具的一个强大功能&#xff0c;它为项目提供了一种集中管理依赖…

定时任务框架

定时任务的框架有哪些 ● Timer&#xff0c;JDK自带的&#xff0c;比较简单&#xff0c;使用的时候&#xff0c;定义一个TimerTask&#xff0c;实现run方法&#xff0c;然后定义一个Timer类&#xff0c;调用timer.schedule(timerTask,1000,3000); ○ 缺点&#xff1a;单线程、…