数据结构漫游记:队列的动态模拟实现(C语言)

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记  闲言碎语小记坊 题山采玉

目录

队列的理解:

基础数据结构的选取:

队列的模拟实现

队列的结构的定义

队列的初始化

入队

判空

出队

获取队头元素

获取队尾元素

获取元素个数

销毁队列 

测试代码

总结:


 

队列的理解:

队列就跟排队吃饭一样,先排到的人先走,后来的人只能在队尾慢慢排。

我们类比于栈,发现我们的队列它只能从一端入数据,一端出数据。

它依然是一个顺序表,在逻辑结构上是顺序存储,而在物理结构就不一定了。

基础数据结构的选取:

还是和栈一样的问题,我们该使用数组还是链表来模拟实现这个数据结构呢?

先来看看数组:

如果我们在数组一端当作队尾一端当作队头。但是我们了解到数组在头部进行操作的时间复杂度都是O(n),不复合我们对时间复杂度的预期,那我们将队尾和队头互换呢,还不是要对数组的头部进行操作,这样看来数组用来实现队列不是一个好选择。

那我们来试试链表:

同样的我们将 头结点视作队头,尾结点视为队尾,发现无论我们以那个结点为头,那个结点为尾,我们始终逃不掉要对尾结点进行操作,要么尾插要么尾删。有没有什么办法能够让尾部进行操作的时间复杂度降到O(1)呢?

你别说还真有如果我们定义一个指针一直指向尾结点呢,之前我们实现链表时都有这个想法,但因为尾部进行删除时指向尾结点的指针不能找到他的前一个结点,但我们如果实现队列,根本不需要对尾部进行删除操作,所以我们定义一个始终指向尾结点的指针,然后进行尾插操作很显然时间复杂度就降到了O(1)了。

队列的模拟实现

队列的结构的定义

因为队列里面有两个指针,一个指向头结点,一个指向尾结点,我们得先定义结点的结构体,然后两个指针在队列的结构体之中。

typedef int QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode

这里定义了一个结点类型是重命名为QNode

然后定义队列的结构

// 队列的结构 
typedef struct Queue
{QNode* front;QNode* rear;
}Queue;

队列的初始化

我们得将队列里面的两个指针先置为空。还得判断不能传入空指针。

// 初始化队列 
void QueueInit(Queue* q)
{assert(q);q->rear = q->front = NULL;
}

入队

入队就是向尾结点加入数据,那如果链表为空呢,我们得特判,让首尾结点都指向新结点

void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* tmp = (QNode*)malloc(sizeof(QNode));if(tmp ==NULL) {	perror("malloc失败\n");exit(1);}tmp->data = data;tmp->next = NULL;if (q->front == NULL) q->front = q->rear = tmp;else{q->rear->next = tmp;q->rear = q->rear->next;}
}

最后要让尾结点等于新的尾结点,不然会死循环

判空

判空这个操作也很简单,当头结点或者是尾结点指向空的时候队列就是空的

bool QueueEmpty(Queue* q)
{assert(q);return q->front == NULL;
}

出队

出队就是删除头结点,如果只有一个结点的时候,就得让头指针和尾指针指向NULL,如果没有结点,就不能进行这个操作就assert一下就好了。

void QueuePop(Queue* q)
{assert(!QueueEmpty(q));if (q->front == q->rear){free(q->front);q->front = q->rear = NULL;}else {QNode* tmp = q->front;q->front = q->front->next;free(tmp);}}

注意删除的时候要用一个变量来暂时接收一下头结点的下一个结点的地址,不然释放了头结点就找不到下一个结点了,对释放了的指针解引用是野指针的行为。

获取队头元素

获取队头和队尾很简单,但要记得assert一下。

QDataType QueueFront(Queue* q)
{assert(!QueueEmpty(q));return q->front->data;
}

获取队尾元素

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{assert(!QueueEmpty(q));return q->rear->data;
}

获取元素个数

我们如果用遍历来实现获取元素个数,那么时间复杂度就又成了O(n)呢,如果这个操作执行的次数少到也无妨,但如果执行的次数多我还是建议定义结构的时候多定义一个变量size,然后初始化,入队,出队时多进行一下操作即可。

int QueueSize(Queue* q)
{return q->size;
}

销毁队列 

最后一个销毁队列,这个没办法,只能遍历链表呢

void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->front;while (cur){QNode* next = cur->next;free(cur);cur = next;}q->rear = q->front = NULL;q->size = 0;
}

测试代码

#include"queue.h"void test01()
{Queue pq;QueueInit(&pq);for (int i = 1; i <= 10; i++){QueuePush(&pq, i);}while (QueueSize(&pq))//!QueueEmpty(&pq){printf("队头:%d   队尾:%d\n", QueueFront(&pq), QueueBack(&pq));QueuePop(&pq);}QueueDestroy(&pq);
}
int main()
{test01();return 0;
}

结果

总结:

我们实现的队列,除了销毁时的时间复杂度是O(n),其他都是常数级别的,实现的队列采用的是链表。

完结撒花谢谢大家!

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

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

相关文章

Ubuntu22.04安装paddle GPU版本

文章目录 确立版本安装CUDA与CUDNN安装paddle 确立版本 查看官网信息&#xff0c;确立服务版本&#xff1a;https://www.paddlepaddle.org.cn/documentation/docs/zh/2.6/install/pip/linux-pip.html 安装CUDA与CUDNN 通过nvidia-smi查看当前显卡驱动版本&#xff1a; 通过…

2024年度总结:从后端Java到全栈成长的蜕变

目录 前言1. 用数据与实践书写成长篇章2. 技术与生活的双重蜕变3. 技术的进阶与生活的绽放 前言 今年是我入行的第十年&#xff0c;也是记录在CSDN平台上的第五年。这五年来&#xff0c;我始终坚持记录成长的点滴&#xff0c;将个人事业与博客创作紧密相连。一路走来&#xff0…

麦田物语学习笔记:创建TransitionManager控制人物场景切换

基本流程 制作场景之间的切换 1.代码思路 (1)为了实现不同场景切换,并且保持当前的persistentScene一直存在,则需要一个Manager去控制场景的加载和卸载,并且在加载每一个场景之后,都要将当前的场景Set Active Scene,保证其为激活的场景,在卸载的时候也可以方便调用当前激活的场…

无人机高速无刷动力电机核心设计技术

一、技术概述 无刷电机优势&#xff1a; 高效率&#xff1a;无刷电机由于去除了电刷和换向器&#xff0c;减少了能量损失&#xff0c;因此具有更高的效率。 长寿命&#xff1a;电刷和换向器的磨损是导致传统有刷电机寿命较短的主要原因&#xff0c;而无刷电机则避免了这一问…

Linux C\C++方式下的文件I/O编程

【图书推荐】《Linux C与C一线开发实践&#xff08;第2版&#xff09;》_linux c与c一线开发实践pdf-CSDN博客 《Linux C与C一线开发实践&#xff08;第2版&#xff09;&#xff08;Linux技术丛书&#xff09;》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 Lin…

python编程-OpenCV(图像读写-图像处理-图像滤波-角点检测-边缘检测)角点检测

角点检测&#xff08;Corner Detection&#xff09;是计算机视觉和图像处理中重要的步骤&#xff0c;主要用于提取图像中的关键特征&#xff0c;以便进行后续的任务&#xff0c;比如图像匹配、物体识别、运动跟踪等。下面介绍几种常用的角点检测方法及其应用。 1. Harris角点检…

QT开发-T113 Linux 主板QC配置套件

此篇文章用于记录在Linux主板上使用QT开发项目的套件配置步骤 进入QC软件&#xff0c;点击 Manage Kits… 选择项目对应的QT Version : 一般有一个项目对应的qmake 文件&#xff0c;选择导入即可 如果首次导入提示 qmake could not be added 需要先对项目进行命令行编译(具体命…

【云岚到家】-day03-门户缓存实现实战

【云岚到家】-day03-门户缓存实现实战 1.定时任务更新缓存 1.1 搭建XXL-JOB环境 1.1.1 分布式调度平台XXL-JOB介绍 对于开通区域列表的缓存数据需要由定时任务每天凌晨更新缓存&#xff0c;如何实现定时任务呢&#xff1f; 1.使用jdk提供的Timer定时器 示例代码如下&#xf…

SuperdEye:一款基于纯Go实现的间接系统调用执行工具

关于SuperdEye SuperdEye是一款基于纯Go实现的间接系统调用执行工具&#xff0c;该工具是TartarusGate 的修订版&#xff0c;可以利用Go来实现TartarusGate 方法进行间接系统调用。 该工具的目标是为了扫描挂钩的NTDLL并检索Syscall编号&#xff0c;然后使用它来执行间接系统调…

Python+ tkinter实现小学整数乘法和除法竖式演算式

Python tkinter实现小学整数乘法和除法竖式演算式 整数的乘法与除法是小学数学中的重要内容&#xff0c;它们是数学运算中的基础部分。 本文将使用python 和Python 的标准 GUI&#xff08;图形用户界面&#xff09;包tkinter&#xff0c;实现整数乘法与除法的竖式演示。供有兴趣…

线程池遇到未处理的异常会崩溃吗?

线程池中的 execute 和 submit 方法详解 目录 引言execute 方法 使用示例代码 submit 方法 2.1 提交 Callable 任务2.2 提交 Runnable 任务 遇到未处理异常 3.1 execute 方法遇到未处理异常3.2 submit 方法遇到未处理异常 小结 引言 在多线程编程中&#xff0c;线程池是提高性…

MongoDB基本操作

一、实验目的 1. 熟悉MongoDB的基本操作&#xff0c;包括CRUD&#xff08;增加、读取、更新、删除&#xff09;。 2. 理解MongoDB的文档型数据库特性和Shell的使用。 3. 培养学生通过命令行操作数据库的能力。 4. 强化数据库操作的实际应用能力。 二、实验环境准备 1.…

【银河麒麟高级服务器操作系统】业务访问慢网卡丢包现象分析及处理过程

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;product.kylinos.cn 开发者专区&#xff1a;developer.kylinos.cn 文档中心&#xff1a;document.kylinos.cn 交流论坛&#xff1a;forum.kylinos.cn 服务器环境以及配置 【内核版本…

Kotlin Bytedeco OpenCV 图像图像54 透视变换 图像矫正

Kotlin Bytedeco OpenCV 图像图像54 透视变换 图像矫正 1 添加依赖2 测试代码3 测试结果 在OpenCV中&#xff0c;仿射变换&#xff08;Affine Transformation&#xff09;和透视变换&#xff08;Perspective Transformation&#xff09;是两种常用的图像几何变换方法。 变换方…

【LeetCode100】--- 寻找重复数

题目传送门 方法一&#xff1a;暴力解法&#xff08;超时&#xff09; 算法原理 双重循环&#xff0c;每次固定一个数&#xff0c;再遍历别的数。比较这两个数是否相等&#xff0c; 若相等则返回这个数。就是重复数。 复杂度分析 时间复杂度&#xff1a;O&#xff08;N方&…

RabbitMQ---TTL与死信

&#xff08;一&#xff09;TTL 1.TTL概念 TTL又叫过期时间 RabbitMQ可以对队列和消息设置TTL&#xff0c;当消息到达过期时间还没有被消费时就会自动删除 注&#xff1a;这里我们说的对队列设置TTL,是对队列上的消息设置TTL并不是对队列本身&#xff0c;不是说队列过期时间…

mysql查看binlog日志

mysql 配置、查看binlog日志&#xff1a; 示例为MySQL8.0 1、 检查binlog开启状态 SHOW VARIABLES LIKE ‘log_bin’; 如果未开启&#xff0c;修改配置my.ini 开启日志 安装目录配置my.ini(mysql8在data目录) log-binmysql-bin&#xff08;开启日志并指定日志前缀&#xff…

【QT】 控件 -- 按钮类(Button)

&#x1f525; 目录 1. 前言 2. Push Button 按钮 1、带有图标的按钮 -- 纯代码实现2、带有快捷键的按钮 -- 图形化&代码实现 3、按钮的重复触发 3. Radio Button 按钮 **1. click、press、release、toggled 的区别** **2. 单选框分组** 4. Check Box 复选 5. Tool Butto…

postman请求参数化

postman界面介绍 一、使用环境变量(Environment Variables)进行参数化 1、在请求中使用环境变量 在请求的url、请求头(Headers)、请求体(Body)等部分都可以使用环境变量。 URL 部分示例 点击 Postman 界面右上角的 “眼睛” 图标(Environment Quick Look)打开环境管理…

在 Babylon.js 中使用 Gizmo:交互式 3D 操作工具

在 3D 应用程序中&#xff0c;交互式操作对象&#xff08;如平移、旋转、缩放&#xff09;是一个常见的需求。Babylon.js 提供了一个强大的工具——Gizmo&#xff0c;用于在 3D 场景中实现这些功能。本文将介绍如何在 Babylon.js 中使用 Gizmo&#xff0c;并展示如何通过代码实…