数据结构之队列的实现(附源码)

目录

一、队列的概念及结构

二、队列的实现

 拓展:循环队列

三、初学的队列以及栈和队列结合的练习题


一、队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出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);
}

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

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

相关文章

后端SpringBoot+前端Vue前后端分离的项目(一)

前言&#xff1a;后端使用SpringBoot框架&#xff0c;前端使用Vue框架&#xff0c;做一个前后端分离的小项目&#xff0c;需求&#xff1a;实现一个表格&#xff0c;具备新增、删除、修改的功能。 目录 一、数据库表的设计 二、后端实现 环境配置 数据处理-增删改查 model…

C++的纯虚函数和抽象类

在C++中,可以将虚函数声明为纯虚函数,语法格式为: virtual 返回值类型 函数名 (函数参数) = 0; 纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0,表明此函数为纯虚函数。 最后的=0并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数”。…

MySQL的概述、版本、安装过程

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、MySQL的概述 二、MySQL的版本 三、MySQL的下载与安装 前言 本文将来谈谈MySQL的概述&#xff0c;MySQL的版本&#xff0c;以及它…

Redis 缓存穿透击穿和雪崩

一、说明 Redis 缓存的使用&#xff0c;极大的提升了应用程序的性能和效率&#xff0c;特别是数据查询方面。但同时&#xff0c;它也带来了一些问题。其中&#xff0c;最要害的问题&#xff0c;就是数据的一致性问题&#xff0c;从严格意义上讲&#xff0c;这个问题无解。如果对…

C++11新特性③ | 可变参数模板介绍

目录 1、引言 2、可变参数模板函数 2.1、可变参数模板函数的定义 2.2、参数包的展开 3、可变参数模板类 3.1、继承方式展开参数包 3.2、模板递归和特化方式展开参数包 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff…

js获得相对路径文件,并上传到服务器

如何通过js获得相对路径文件 已知一个相对路径文件&#xff0c;如何使用js将该文件读取为File格式&#xff0c;最后上传到服务器中呢。 1.最简单的解决方案——fetch 代码 import ./index.scss// js通过相对路径获取文件 function FetchGetLocalFile() {const fetchLocalFile …

Python Opencv实践 - Shi-Tomasi角点检测

参考资料&#xff1a;Harris和Shi-tomasi角点检测笔记&#xff08;详细推导&#xff09;_harris焦点检测_亦枫Leonlew的博客-CSDN博客 cv.goodFeaturesToTrack&#xff1a;Shi-Tomasi角点检测-OpenCV-python_独憩的博客-CSDN博客 import cv2 as cv import numpy as np import …

Python入门学习12

一、Python包 什么是Python包 从物理上看&#xff0c;包就是一个文件夹&#xff0c;在该文件夹下包含了一个 __init__.py 文件&#xff0c;该文件夹可用于包含多个模块文件。从逻辑上看&#xff0c;包的本质依然是模块 包的作用: 当我们的模块文件越来越多时,包可以帮助我们管…

如何处理异步编程中的回调地狱问题?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 解决回调地狱问题的方法⭐使用 Promise⭐使用 async/await⭐ 使用回调函数库⭐模块化⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端…

YOLOV8从零搭建一套目标检测系统(修改model结构必看)附一份工业缺陷检测数据集

目录 1.YOLOV8介绍 2.YOLOV8安装 2.1环境配置 3.数据集准备 1.YOLOV8介绍 Yolov8结构图&#xff1a; YoloV8相对于YoloV5的改进点&#xff1a; Replace the C3 module with the C2f module. Replace the first 6x6 Conv with 3x3 Conv in the Backbone. Delete two Convs …

processflow流程图多人协作预热

前言 在线上办公如火如荼的今天&#xff0c;多人协作功能是每个应用绕不开的门槛。processflow在线流程图&#xff08;前身基于drawio二次开发&#xff09;沉寂两年之久&#xff0c;经过长时间设计开发&#xff0c;调整&#xff0c;最终完成了多人协作的核心模块设计。废话不多…

【SpringSecurity】九、Base64与JWT

文章目录 1、base64编码2、Base64Url3、JWT的产生背景4、JWT介绍5、JWT组成5.1 Header5.2 Payload5.3 Signature 6、JWT的使用方式7、JWT的几个特点 1、base64编码 base64是一种编码方式&#xff0c;不是加密方式。 所谓Base64&#xff0c;就是说选出64个字符&#xff1a;小写…

【办公类-19-03】办公中的思考——Python批量制作word单元格照片和文字(小照片系列)

背景需求&#xff1a; 工会老师求助&#xff1a;如何在word里面插入4*8的框&#xff0c;我怎么也拉不到4*8大小&#xff08;她用的是我WORD 文本框&#xff09; 我一听&#xff0c;这又是要手动反复黏贴“文本框”“照片”“文字”的节奏哦 我问&#xff1a;你要做几个人&…

搭建hadoop集群的常见问题及解决办法

问题一: namenode -format重复初始化 出现问题的原因是重复初始化时会重新生成集群ID&#xff0c;而dn还是原先的集群ID&#xff0c;两者不匹配时无法启动相应的dn进程。 怎么查找问题原因&#xff1a;在logs目录下找到对应节点的.log文件&#xff0c;使用tail -200 文件名来查…

远程工作面试:特殊情况下的面试技巧

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Web3 solidity编写cancelorder取消订单函数 并梳理讲述逻辑

上文 Web3 solidity订单池操作 中 我们讲述了订单池的基本概念 并手动编写了创建订单的操作 最近的 我们还是先将 ganache 环境起起来 然后 我们打开项目 上文中 我们写了makeOrder创建订单的函数 但是 也带出一个问题 我们创建之后 如果不要了 怎么干掉呀&#xff1f; js中我…

MongoDB常用的比较符号和一些功能符号

比较符号 results collection.find({age: {$gt: 20}})功能符号 results collection.find({name: {$regex: ^M.*}})

电水壶上要求亚马逊美国站SOR/2016-181和CSA22.1标准?

电水壶作为一种常见的小家电&#xff0c;受到了广大消费者的喜爱。然而&#xff0c;由于安全问题的日益重视&#xff0c;亚马逊加拿大站决定加强对电水壶产品的审核&#xff0c;以确保消费者的安全和权益。 近日&#xff0c;亚马逊平台发布公告&#xff0c;要求在加拿大站销售…

鸿蒙应用程序入口UIAbility详解

一、UIAbility概述 UIAbility是一种包含用户界面的应用组件&#xff0c;主要用于和用户进行交互。UIAbility也是系统调度的单元&#xff0c;为应用提供窗口在其中绘制界面。每一个UIAbility实例&#xff0c;都对应于一个最近任务列表中的任务。一个应用可以有一个UIAbility&am…

java从入门到起飞(八)——循环和递归

文章目录 Java循环1. 什么是循环&#xff1f;1.1 为什么需要循环&#xff1f;1.2 循环的分类 2. Java中的循环结构2.1 for循环2.2 while循环2.3 do-while循环 3. 循环控制语句3.1 break语句3.2 continue语句 4. 总结 Java递归1. 什么是递归2. 递归的原理3. 递归的实现4. 递归的…