数据结构之队列的实现(附源码)
目录
一、队列的概念及结构
二、队列的实现
拓展:循环队列
三、初学的队列以及栈和队列结合的练习题
一、队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
二、队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
具体代码如下(C语言实现):
#pragma once//Queue.h
// 链式结构:表示队列#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int QDateType;typedef struct QListNode
{struct QListNode* _next;QDateType _data;
}QNode;// 队列的结构
typedef struct Queue
{QNode* _front;//队头QNode* _rear;//队尾int size;
}Queue;// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDateType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDateType QueueFront(Queue* q);
// 获取队列队尾元素
QDateType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
//Queue.c
#include "Queue.h"void QueueInit(Queue* q)
{assert(q);q->_front = NULL;q->_rear = NULL;q->size = 0;
}void QueuePush(Queue* q, QDateType data)
{assert(q);QNode* tmp = (QNode*)malloc(sizeof(QNode));if (tmp == NULL){perror("tmp malloc");exit(-1);}tmp->_data = data;tmp->_next = NULL;if (q->_rear == NULL){q->_front = q->_rear = tmp;}else{q->_rear->_next = tmp;q->_rear = tmp;}q->size++;
}void QueuePop(Queue* q)
{assert(q);assert(QueueEmpty(q));if (q->_front->_next == NULL){free(q->_front);q->_front = q->_rear = NULL;}else{QNode* next = q->_front->_next;free(q->_front);q->_front = next;}q->size--;
}QDateType QueueFront(Queue* q)
{assert(q);assert(QueueEmpty(q));return q->_front->_data;
}QDateType QueueBack(Queue* q)
{assert(q);assert(QueueEmpty(q));return q->_rear->_data;
}int QueueSize(Queue* q)
{assert(q);return q->size;
}int QueueEmpty(Queue* q)
{assert(q);return q->size;
}void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->_front;while (cur){Queue* next = cur->_next;free(cur);cur = next;}q->_front = q->_rear = NULL;q->size = 0;
}
//test.c
#include "Queue.h"void test02()
{Queue q1;QueueInit(&q1);QueuePush(&q1, 1);QueuePush(&q1, 2);QueuePush(&q1, 3);QueuePush(&q1, 4);QueuePush(&q1, 5);QueuePop(&q1);while (QueueEmpty(&q1)){printf("%d ", QueueFront(&q1));QueuePop(&q1);}printf("\n");QueueDestroy(&q1);
}int main()
{test02();return 0;
}
拓展:循环队列
如上图所示:循环队列的节点数一般会比要求的节点数多一个,以便区分空的循环队列和满的循环队列。空的循环队列front和rear指向同一个节点,满的循环队列可以理解为rear = front + 1。
三、初学的队列以及栈和队列结合的练习题
题目一:设计循环队列
MyCircularQueue(k)
: 构造器,设置队列长度为 k 。Front
: 从队首获取元素。如果队列为空,返回 -1 。Rear
: 获取队尾元素。如果队列为空,返回 -1 。enQueue(value)
: 向循环队列插入一个元素。如果成功插入则返回真。deQueue()
: 从循环队列中删除一个元素。如果成功删除则返回真。isEmpty()
: 检查循环队列是否为空。isFull()
: 检查循环队列是否已满。
typedef struct
{int* a;int front;int rear;int k;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k)
{MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->a = (int*)malloc(sizeof(int)*(k+1));obj->front = obj->rear = 0;obj->k = k;return obj;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{//front和rear相等即为空return obj->front == obj->rear;
}bool myCircularQueueIsFull(MyCircularQueue* obj)
{//数学方法判满return (obj->rear + 1) % (obj->k + 1) == obj->front;
}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{if(myCircularQueueIsFull(obj))return false;obj->a[obj->rear] = value;++obj->rear;//不然rear可能越界obj->rear %= (obj->k+1);return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj)
{if(myCircularQueueIsEmpty(obj))return false;obj->front++;obj->front %= (obj->k+1);return true;
}int myCircularQueueFront(MyCircularQueue* obj)
{if(myCircularQueueIsEmpty(obj))return -1;elsereturn obj->a[obj->front];
}int myCircularQueueRear(MyCircularQueue* obj)
{if(myCircularQueueIsEmpty(obj))return -1;else//数学方法return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}void myCircularQueueFree(MyCircularQueue* obj)
{free(obj->a);free(obj);
}
题目二:用队列实现栈
思路:用两个队列,保持一个队列为空一个不为空,当要出栈的时候就将不为空的队列中除了队尾的元素全都入到为空的队列中,然后将唯一的那个元素出栈。
typedef int QDateType;typedef struct QListNode
{struct QListNode* _next;QDateType _data;
}QNode;// 队列的结构
typedef struct Queue
{QNode* _front;QNode* _rear;int size;
}Queue;void QueueInit(Queue* q)
{assert(q);q->_front = NULL;q->_rear = NULL;q->size = 0;
}void QueuePush(Queue* q, QDateType data)
{assert(q);QNode* tmp = (QNode*)malloc(sizeof(QNode));if (tmp == NULL){perror("tmp malloc");exit(-1);}tmp->_data = data;tmp->_next = NULL;if (q->_rear == NULL){q->_front = q->_rear = tmp;}else{q->_rear->_next = tmp;q->_rear = tmp;}q->size++;
}void QueuePop(Queue* q)
{assert(q);assert(QueueEmpty(q));if (q->_front->_next == NULL){free(q->_front);q->_front = q->_rear = NULL;}else{QNode* next = q->_front->_next;free(q->_front);q->_front = next;}q->size--;
}QDateType QueueFront(Queue* q)
{assert(q);assert(QueueEmpty(q));return q->_front->_data;
}QDateType QueueBack(Queue* q)
{assert(q);assert(QueueEmpty(q));return q->_rear->_data;
}int QueueSize(Queue* q)
{assert(q);return q->size;
}int QueueEmpty(Queue* q)
{assert(q);return q->size;
}void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->_front;while (cur){Queue* next = cur->_next;free(cur);cur = next;}q->_front = q->_rear = NULL;q->size = 0;
}typedef struct
{Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate()
{MyStack* tmp = (MyStack*)malloc(sizeof(MyStack));QueueInit(&tmp->q1);QueueInit(&tmp->q2);return tmp;
}void myStackPush(MyStack* obj, int x)
{if(QueueEmpty(&obj->q1)){QueuePush(&obj->q1, x);}else{QueuePush(&obj->q2, x);}
}int myStackPop(MyStack* obj)
{Queue* empty = &obj->q1;Queue* noempty = &obj->q2;if(QueueEmpty(&obj->q1)){empty = &obj->q2;noempty = &obj->q1;}while(QueueSize(noempty) > 1){QueuePush(empty, QueueFront(noempty));QueuePop(noempty);}int top = QueueFront(noempty);QueuePop(noempty);return top;
}int myStackTop(MyStack* obj)
{if(QueueEmpty(&obj->q1))return QueueBack(&obj->q1);elsereturn QueueBack(&obj->q2);
}bool myStackEmpty(MyStack* obj)
{int ret1, ret2;if(QueueEmpty(&obj->q1) == 0)ret1 = 0;elseret1 = 1;if(QueueEmpty(&obj->q2) == 0)ret2 = 0;elseret2 = 1;if(ret1 == 0 && ret2 == 0)return true;elsereturn false;
}void myStackFree(MyStack* obj)
{QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);
}
题目三:用栈实现队列
思路:使用两个栈,一个push栈一个pop栈,先往push栈中堆入元素,出队时,先将push栈中的元素先pop到pop栈中,再从pop栈中pop元素,其间再有元素堆入入到push栈中。
typedef int STDataType;
typedef struct Stack
{STDataType* _a;int _top; // 栈顶int _capacity; // 容量
}Stack;void StackInit(Stack* ps)
{assert(ps);ps->_a = NULL;ps->_top = 0;ps->_capacity = 0;
}void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->_capacity == ps->_top){int newCapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;STDataType* tmp = (STDataType*)realloc(ps->_a,sizeof(STDataType) * newCapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}ps->_a = tmp;ps->_capacity = newCapacity;}ps->_a[ps->_top] = data;ps->_top++;
}void StackPop(Stack* ps)
{assert(ps);assert(ps->_top > 0);ps->_top--;
}STDataType StackTop(Stack* ps)
{assert(ps);assert(ps->_top > 0);return ps->_a[ps->_top - 1];
}int StackSize(Stack* ps)
{assert(ps);return ps->_top;
}int StackEmpty(Stack* ps)
{return ps->_top;
}void StackDestroy(Stack* ps)
{assert(ps);free(ps->_a);ps->_a = NULL;ps->_capacity = 0;ps->_top = 0;
}typedef struct
{Stack pushst;Stack popst;
} MyQueue;MyQueue* myQueueCreate()
{MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));StackInit(&obj->pushst);StackInit(&obj->popst);return obj;
}void myQueuePush(MyQueue* obj, int x)
{StackPush(&obj->pushst, x);
}int myQueuePeek(MyQueue* obj)
{//pop栈为空就往其中堆入元素if(StackEmpty(&obj->popst) == 0){while(StackEmpty(&obj->pushst) > 0){StackPush(&obj->popst, StackTop(&obj->pushst));StackPop(&obj->pushst);}}return StackTop(&obj->popst);
}int myQueuePop(MyQueue* obj)
{int front = myQueuePeek(obj);StackPop(&obj->popst);return front;
}bool myQueueEmpty(MyQueue* obj)
{int ret1, ret2;if(StackEmpty(&obj->pushst) == 0)ret1 = 0;elseret1 = 1;if(StackEmpty(&obj->popst) == 0)ret2 = 0;elseret2 = 1;if(ret1 == 0 && ret2 == 0)return true;elsereturn false;
}void myQueueFree(MyQueue* obj)
{StackDestroy(&obj->pushst);StackDestroy(&obj->popst);free(obj);
}
相关文章:

数据结构之队列的实现(附源码)
目录 一、队列的概念及结构 二、队列的实现 拓展:循环队列 三、初学的队列以及栈和队列结合的练习题 一、队列的概念及结构 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(Fi…...

[A题]2023 年全国大学生数学建模比赛思路、代码更新中.....
💥1 概述 构建以新能源为主体的新型电力系统,是我国实现“碳达峰”“碳中和”目标的一项重要措施。塔式太阳能光热发电是一种低碳环保的新型清洁能源技术[1]。定日镜是塔式太阳能光热发电站(以下简称塔式电站)收集太阳能的基本组…...

Tailwind 练手项目
Tailwind 练手项目 用到的技巧 Tailwind CSS 速成 应该都提过了,我不记得这里有什么特别新的知识 整体完成图大概这样: 一个纯静态页面,没有做 JS 之类的特效,不过做了移动端适配,说实话我写到一半的时候改了不少………...

SpringMVC_SSM整合
一、回顾SpringMVC访问接口流程 1.容器加载分析 容器分析 手动注册WebApplicationContext public class ServletConfig extends AbstractDispatcherServletInitializer {Overrideprotected WebApplicationContext createServletApplicationContext() {//获取SpringMVC容器An…...

【操作系统】电脑上没有IIS怎么办
文章目录 前言一、查看二、解决 前言 有的新机刚开始在计算机-管理-服务下没有IIS网络服务怎么办。 一、查看 桌面计算机/此电脑 鼠标右键:管理 服务和应用 发现没有IIS 二、解决 控制面板 程序和功能 启动或关闭Windows功能 IIS相关的所有功能选中ÿ…...
【vue】vue项目中批量下载文件并打压缩包
前言 一开始用的是循环单个文件下载,即从后台获取到文件url列表,循环对每个url单独进行下载,这样的问题是每调用一次下载,浏览器都会进行“另存为”的弹框,很麻烦!!! 关闭“下载前…...

Linux中的软件管家——yum
目录 编辑 一,软件安装的方式 二,对yum的介绍 1.yum的作用 2,yum的库 三,yum下载软件的操作 1.yumlist 2.yuminstall 3.yumremove 四,yum源的转换 一,软件安装的方式 软件安装的方式大概分为三种…...

安卓绘制原理概览
绘制原理 Android 程序员都知道 Android 的绘制流程分为 Measure、Layout、Draw 三步骤,其中 Measure 负责测量 View 的大小Layout 负责确定 View 的位置Draw 负责将 View 画在屏幕上 由 ViewRootImpl 实现的 performTraversal 方法是 Measure、layout、draw 的真正…...

接口测试工具开发文档
1 开发规划 1.1 开发人员 角 色 主要职责 负责模块 人员 备注 n xxx模块 xxx 1.2 开发计划 <附开发计划表> 1.3 开发环境和工具 开发工具 工具 作用 Notepad 编辑器 Perl 解释器 2 总体设计 设计思路:因为测试app和server。首先必须…...

面试题速记:JavaScript有哪些数据类型,它们的区别是?
JavaScript有哪些数据类型,它们的区别? JavaScript共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。 其中 Symbol 和 BigInt 是ES6 中新增的数据类型: ●Symbol 代表创建后独一无二…...

Spring Cloud面试题
为什么需要学习Spring Cloud 不论是商业应用还是用户应用,在业务初期都很简单,我们通常会把它实现为单体结构的应用。但是,随着业务逐渐发展,产品思想会变得越来越复杂,单体结构的应用也会越来越复杂。这就会给应用带…...

计算机网络自顶向下-web页面请求历程
1. 准备: DHCP、 UDP、 IP 和以太网 假定 Bob 启动他的便携机,然后将其用一根以太网电缆连接到学校的以太网交换机 , 交换机与学校的路由器相连。学校的路由器与一个 ISP 连接, 本例中 ISP 为 comcast.net ,为学校提供了 DNS 服务…...

打造西南交通感知新范式,闪马智能携手首讯科技落地创新中心
9月4日,2023年中国国际智能产业博览会(以下简称“智博会”)在重庆拉开帷幕。大会期间,由上海闪马智能科技有限公司(以下简称“闪马智能”)与重庆首讯科技股份有限公司(以下简称“首讯科技”&…...
Android11去掉Settings中的网络和互联网一级菜单
碰到一个不要wifi不要蓝牙的项目,客户要求去掉Settings中的网络和互联网一级菜单,因为硬件都不贴,所以软件对应也要去掉。 我们可以根据packages/apps/Settings/res/xml/top_level_settings.xml的布局文件找到TopLevelNetworkEntryPreferenc…...

基于Python开发的五子棋小游戏(源码+可执行程序exe文件+程序配置说明书+程序使用说明书)
一、项目简介 本项目是一套基于Python开发的五子棋小游戏,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含:项目源码、项目文档、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试&a…...

JDBC入门到精通-10w总结
JDBC核心技术 笔记是以尚硅谷讲师宋红康JDBC课程为基础,加入自身学习体会,略有修改 第1章:JDBC概述 JDBC是java应用程序和数据库之间的桥梁。JDBC提供一组规范(接口)。向上是面向应用API,共应用程序使用。向…...

Linux之查看so/bin依赖(三十一)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
day-45 代码随想录算法训练营(19)动态规划 part 07
70.爬楼梯(进阶) 分析:基本动态规划转换为完全背包,因为1、2 两种上楼梯方式是无限选择的 思路: 1. j 表示 容量为 j 时,装满有dp[j]种方法2. dp[j]dp[j-nums[i]]3. 初始化 dp[0]1,dp[1]14. 遍历顺序&am…...
static关键字和final关键字
在java的关键字中,static关键字和final关键字是两个必须掌握的关键字。static关键字和final关键字用法多样,且在一定环境下使用,可以提高程序的运行性能,优化程序的结构。下面将依次介绍static关键字和final关键字。注意ÿ…...

使用Postman如何在接口测试前将请求的参数进行自定义处理
1、前言 当我们使用 Postman 进行接口测试时,对于简单的不需要处理的接口,直接请求即可,但是对于需要处理的接口,如需要转码、替换值等,则就麻烦一些,一般我们都是先手动把修改好的值拷贝到请求里再进行请…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...

Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...