数据结构·栈和队列

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修改为你需要打包的程序名字 …

验证C++中 cout 输出情况的小程序

//这个小程序验证了C中cout输出char数组、char*指针变量、string对象、int数组、double类型的情况&#xff0c;并做了简单说明。具体代码及注释 #include<iostream> using namespace std; #include<string> #include<fstream> #include <iomanip> int…

ElasticSearch架构介绍及原理解析

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

系统运维-Linux配置C、C++、Go语言编译环境

C yum install gcc -y #安装gcc编译器 gcc --version #验证环境gcc (GCC) 11.3.1 20221121 (Red Hat 11.3.1-4) Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even f…

简述操作系统内存管理

这篇可是真枯涩啊&#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…

【Elasticsearch专栏 14】深入探索:Elasticsearch使用Logstash的日期过滤器删除旧数据

导言 随着企业业务的不断增长和数字化转型的加速&#xff0c;日志和事件数据在Elasticsearch中迅速积累。这些数据中&#xff0c;有很大一部分是旧数据&#xff0c;它们可能不再需要或者不再相关。长时间保留这些数据不仅占用大量存储空间&#xff0c;还会降低Elasticsearch集…

c++ vector简介

1.vector定义&#xff1a; 改变数组大小的序列容器 2.如何创建vector&#xff1a; vector<数据类型> 容器名称&#xff08;容器大小&#xff0c;容器内每个位置的初始值&#xff09; vector num; vector num(5); vector num(5,2); vector num {1,2,3,4} ; //直接生成一个…

【uni-app】自定义组件和通信

&#xff08;1&#xff09;自定义组件概念 组件是 vue 技术中非常重要的部分&#xff0c;组件使得与ui相关的轮子可以方便的制造和共享&#xff0c;进而使得vue使用者的开发效率大幅提升&#xff0c;在项目的component目录下存放组件&#xff0c;uni-app 只支持 vue 单文件组件…

【外设篇】——显示器

显示屏是一种电光转换工具&#xff0c;现在市面上的显示器都是LCD&#xff08;Liquid Crystal Display&#xff0c;液晶显示器&#xff09; 显示器参数介绍 对比度 是指画面黑与白的比值&#xff0c;对比度越高能使色彩表现越丰富&#xff0c;对比度越高&#xff0c;显示器的…

c++之浅拷贝和深拷贝

目录 一、浅拷贝&#xff1a;浅拷贝就是对象的数据成员之间的简单赋值 二、深拷贝&#xff1a;源对象与拷贝对象互相独立 三、总结&#xff1a; 1、什么时候必须定义自己的拷贝构造函数呢&#xff1f; 2、出现段错误的原因&#xff1a; 3、浅拷贝和深拷贝的写法 注意浅拷贝…

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消息发送与接收&#…