当前位置: 首页 > news >正文

C语言实现数据结构之队列

目录

  • 队列
    • 一. 队列的概念及结构
    • 二. 队列的实现
      • 1. 要实现的功能
      • 2 具体的实现
        • 2.1 结构体
        • 2.2 初始化
        • 2.3 入队列
        • 2.4 出队列
        • 2.5 返回队首元素
        • 2.6 返回队尾元素
        • 2.7 队列元素个数
        • 2.8 队列判空
        • 2.9 队列销毁
    • 三. 队列相关OJ题
      • 设计循环队列
      • 用队列实现栈
      • 用栈实现队列
    • 四. 概念选择题
    • 五. 参考代码
      • Queue.h
      • Queue.c
      • test.c

队列

一. 队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
队列的先进先出

二. 队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
入队列与出队列

1. 要实现的功能

// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* _pNext;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;
QNode* _rear;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);

另外扩展了解一下,实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。
循环队列

2 具体的实现

本次队列的实现我们基于双向链表

2.1 结构体

为了适配多种数据类型,这里使用typedef对数据类型进行重命名,便于进行统一修改。
由于链表QueueNode的节点只含有next指针和值,所以我们额外定义一个结构体Queue记录下链表的头和尾,便于快速进行相关操作。

typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead; QNode* ptail;int size;
}Queue;
2.2 初始化

初始化将记录的头和尾置空,元素个数置空

void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}
2.3 入队列

入队列创建一个新节点,并放在记录好的尾节点的位置之后,成为新的尾节点,最后元素个数增加。

void QueuePush(Queue* pq, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc failed");exit(1);}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = newnode;pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}
2.4 出队列

出队列释放掉第一个节点(头节点),然后让第二个节点成为新的头节点,最后元素个数减少。

void QueuePop(Queue* pq)
{assert(pq);assert(pq->size);QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;if (pq->phead == NULL)//just one node{pq->ptail = NULL;}pq->size--;
}
2.5 返回队首元素

返回我们记录的头节点的值即可。

QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}
2.6 返回队尾元素

返回我们记录的尾节点的值即可。

QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}
2.7 队列元素个数

返回我们记录的元素个数即可。

int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}
2.8 队列判空

返回我们记录的元素个数是否为零。

_Bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}
2.9 队列销毁

类似于单链表的销毁,依次销毁每一个节点后将头尾置空,将元素个数置空。

void QueueDestroy(Queue* pq)
{assert(pq);QNode* pcur = pq->phead;while (pcur){QNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}

三. 队列相关OJ题

设计循环队列

题目链接:设计循环队列
循环队列

//顺序表
typedef struct 
{int* a;int head;int tail;int k;    
} MyCircularQueue;bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);MyCircularQueue* myCircularQueueCreate(int k) 
{MyCircularQueue* pq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多开辟一个空间解决假溢出问题pq->a = malloc(sizeof(int) * (k + 1));pq->head = 0;pq->tail = 0;pq->k = k;return pq;
}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{if(myCircularQueueIsFull(obj)){return false;}obj->a[obj->tail] = value;obj->tail++;obj->tail %= (obj->k + 1);return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return false;}   obj->head++;obj->head %= obj->k + 1;return true;
}int myCircularQueueFront(MyCircularQueue* obj)
{if(myCircularQueueIsEmpty(obj)){return EOF;}else{return obj->a[obj->head];}   
}int myCircularQueueRear(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return EOF;}else{//return obj->tail == 0 ? obj->a[obj->k] : obj->a[obj->tail - 1];//return obj->a[(obj->tail - 1 + obj->k + 1) % (obj->k + 1)];return obj->a[(obj->tail + obj->k) % (obj->k + 1)];}
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{return obj->head == obj->tail;    
}bool myCircularQueueIsFull(MyCircularQueue* obj) 
{return (obj->tail + 1) % (obj->k + 1) == obj->head;    
}void myCircularQueueFree(MyCircularQueue* obj) 
{free(obj->a);free(obj);
}/*** Your MyCircularQueue struct will be instantiated and called as such:* MyCircularQueue* obj = myCircularQueueCreate(k);* bool param_1 = myCircularQueueEnQueue(obj, value);* bool param_2 = myCircularQueueDeQueue(obj);* int param_3 = myCircularQueueFront(obj);* int param_4 = myCircularQueueRear(obj);* bool param_5 = myCircularQueueIsEmpty(obj);* bool param_6 = myCircularQueueIsFull(obj);* myCircularQueueFree(obj);
*/

用队列实现栈

题目链接:用队列实现栈

typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead; QNode* ptail;int size;
}Queue;队尾插入
//void QueuePush(QNode** pphead, QNode** pptail, QDataType x);
//
队头删除
//void QueuePop(QNode** pphead, QNode** pptail);//初始化
void QueueInit(Queue* pq);//队尾插入
void QueuePush(Queue* pq, QDataType x);//队头删除
void QueuePop(Queue* pq);//取队头数据
QDataType QueueFront(Queue* pq);//取队尾数据
QDataType QueueBack(Queue* pq);//队列元素个数
int QueueSize(Queue* pq);//判空
_Bool QueueEmpty(Queue* pq);//队列的销毁
void QueueDestroy(Queue* pq);void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}void QueuePush(Queue* pq, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc failed");exit(1);}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = newnode;pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}void QueuePop(Queue* pq)
{assert(pq);assert(pq->size);QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;if (pq->phead == NULL){pq->ptail = NULL;}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;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}_Bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}void QueueDestroy(Queue* pq)
{assert(pq);QNode* pcur = pq->phead;while (pcur){QNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}typedef struct {Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() 
{MyStack* pst = (MyStack*)malloc(sizeof(MyStack));if(pst == NULL){perror("malloc failed");exit(1);}QueueInit(&pst->q1);QueueInit(&pst->q2);return pst;
}void myStackPush(MyStack* obj, int x) 
{if(!QueueEmpty(&(obj->q1))){QueuePush(&(obj->q1), x);}else{QueuePush(&(obj->q2), x);}
}int myStackPop(MyStack* obj) 
{//如果队列不为空,就把前size - 1个数据放在另一个队列中,释放最后一个节点的数据Queue* emp = &(obj->q1);//假设q1为空Queue* noemp = &(obj->q2);if(QueueEmpty(&(obj->q2)))//如果q2为空{emp = &(obj->q2);noemp = &(obj->q1);}int sz = QueueSize(noemp);while(sz > 1){QueuePush(emp, QueueFront(noemp));QueuePop(noemp);sz--;}int top = QueueFront(noemp);QueuePop(noemp);return top;
}int myStackTop(MyStack* obj) 
{if(!QueueEmpty(&(obj->q1))){return QueueBack(&(obj->q1));}else{return QueueBack(&(obj->q2));}
}bool myStackEmpty(MyStack* obj) 
{return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
}void myStackFree(MyStack* obj) 
{QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);
}/*** Your MyStack struct will be instantiated and called as such:* MyStack* obj = myStackCreate();* myStackPush(obj, x);* int param_2 = myStackPop(obj);* int param_3 = myStackTop(obj);* bool param_4 = myStackEmpty(obj);* myStackFree(obj);
*/

用栈实现队列

题目链接:用栈实现队列
用栈实现队列

typedef int STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;//初始化
void STInit(ST* pst);//销毁
void STDestroy(ST* pst);//插入数据(入栈)
void STPush(ST* pst, STDataType x);//删除数据(出栈)
void STPop(ST* pst);//获取栈顶数据
STDataType STTop(ST* pst);//判空
_Bool STEmpty(ST* pst);//获取数据个数
int STSize(ST* pst);void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->capacity = 0;// top指向栈顶数据的下一个位置pst->top = 0; top指向栈顶数据//pst->top = -1;
}void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->capacity = 0;pst->top = 0;
}void STPush(ST* pst, STDataType x)
{assert(pst);//扩容if (pst->top == pst->capacity){int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc failed");exit(1);}pst->a = tmp;pst->capacity = newcapacity;}//存放数据pst->a[pst->top] = x;pst->top++;
}void STPop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->a[pst->top - 1];
}_Bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}int STSize(ST* pst)
{assert(pst);return pst->top;
}typedef struct 
{ST s1;ST s2;
} MyQueue;MyQueue* myQueueCreate() 
{MyQueue* pqe = (MyQueue*)malloc(sizeof(MyQueue));if(pqe == NULL){perror("malloc failed");exit(1);}STInit(&(pqe->s1));STInit(&(pqe->s2));return pqe;
}void myQueuePush(MyQueue* obj, int x) 
{if(!STEmpty(&(obj->s1))){STPush(&(obj->s1), x);}else{STPush(&(obj->s2), x);}
}int myQueuePop(MyQueue* obj)
{ST* emp = &(obj->s1);//假设s1为空ST* noemp = &(obj->s2);if (STEmpty(&(obj->s2)))//如果s2为空{emp = &(obj->s2);noemp = &(obj->s1);}int sz = STSize(noemp);if (sz == 1){int top = STTop(noemp);STPop(noemp);return top;}else{while (sz > 1){STPush(emp, STTop(noemp));STPop(noemp);sz--;}int top = STTop(noemp);STPop(noemp);ST* tmp = noemp;noemp = emp;emp = tmp;sz = STSize(noemp);while (sz > 0){STPush(emp, STTop(noemp));STPop(noemp);sz--;}return top;}
}int myQueuePeek(MyQueue* obj)
{ST* emp = &(obj->s1);//假设s1为空ST* noemp = &(obj->s2);if (STEmpty(&(obj->s2)))//如果s2为空{emp = &(obj->s2);noemp = &(obj->s1);}int sz = STSize(noemp);if (sz == 1){int top = STTop(noemp);return top;}else{while (sz > 1){STPush(emp, STTop(noemp));STPop(noemp);sz--;}int top = STTop(noemp);STPush(emp, STTop(noemp));STPop(noemp);ST* tmp = noemp;noemp = emp;emp = tmp;sz = STSize(noemp);while (sz > 0){STPush(emp, STTop(noemp));STPop(noemp);sz--;}return top;}
}bool myQueueEmpty(MyQueue* obj) 
{return STEmpty(&obj->s1) && STEmpty(&obj->s2);
}void myQueueFree(MyQueue* obj) 
{STDestroy(&obj->s1);STDestroy(&obj->s2);free(obj);  
}/*** Your MyQueue struct will be instantiated and called as such:* MyQueue* obj = myQueueCreate();* myQueuePush(obj, x);* int param_2 = myQueuePop(obj);* int param_3 = myQueuePeek(obj);* bool param_4 = myQueueEmpty(obj);* myQueueFree(obj);
*/

四. 概念选择题

  1. 循环队列的存储空间为 Q(1:100) ,初始状态为front=rear=100 。经过一系列正常的入队与退队操作后, front=rear=99 ,则循环队列中的元素个数为( )
    A 1
    B 2
    C 99
    D 0或者100
  2. 以下( )不是队列的基本运算?
    A 从队尾插入一个新元素
    B 从队列中删除第i个元素
    C 判断一个队列是否为空
    D 读取队头元素的值
  3. 现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设队头不存放数据)
    A (rear - front + N) % N + 1
    B (rear - front + N) % N
    C ear - front) % (N + 1)
    D (rear - front + N) % (N - 1)
    答案
  4. D
  5. B
  6. B

五. 参考代码

Queue.h

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead; QNode* ptail;int size;
}Queue;队尾插入
//void QueuePush(QNode** pphead, QNode** pptail, QDataType x);
//
队头删除
//void QueuePop(QNode** pphead, QNode** pptail);//初始化
void QueueInit(Queue* pq);//队尾插入
void QueuePush(Queue* pq, QDataType x);//队头删除
void QueuePop(Queue* pq);//取队头数据
QDataType QueueFront(Queue* pq);//取队尾数据
QDataType QueueBack(Queue* pq);//队列元素个数
int QueueSize(Queue* pq);//判空
_Bool QueueEmpty(Queue* pq);//队列的销毁
void QueueDestroy(Queue* pq);

Queue.c

#include "Queue.h"void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}void QueuePush(Queue* pq, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc failed");exit(1);}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = newnode;pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}void QueuePop(Queue* pq)
{assert(pq);assert(pq->size);QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;if (pq->phead == NULL)//just one node{pq->ptail = NULL;}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;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}_Bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}void QueueDestroy(Queue* pq)
{assert(pq);QNode* pcur = pq->phead;while (pcur){QNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}

test.c

#include "Queue.h"int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePush(&q, 5);while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));QueuePop(&q);}return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于GeoTools使用JavaFx进行矢量数据可视化实战
  • NoSQL之Redis配置与优化
  • 36集网剧《天降神医朱丹溪》电影《百草园里杏花香》在义乌启动
  • Java 并发编程:ReentrantLock 锁与 AQS
  • 【机器人学】6-5.六自由度机器人运动学参数辨识-逆运动学迭代解【附MATLAB代码】
  • 响应式Web设计的发展与特点
  • 【rz sz】Centos/Linux 如何快捷的上传下载文件到系统当中?
  • 白骑士的Matlab教学基础篇 1.4 函数与脚本
  • LeetCode Hot100 LRU缓存
  • Npm使用教程(详细讲解)
  • 算法打卡 Day19(二叉树)-平衡二叉树 + 二叉树的所有路径 + 左叶子之和 + 完全二叉树的节点个数
  • 【学习笔记】:Maven初级
  • 2024rk(案例三)
  • 【debian系统arm架构安装docker】且换源后依旧不行就离线导入镜像
  • c++修仙小游戏预告
  • 【Amaple教程】5. 插件
  • eclipse(luna)创建web工程
  • Js基础——数据类型之Null和Undefined
  • Linux后台研发超实用命令总结
  • orm2 中文文档 3.1 模型属性
  • php中curl和soap方式请求服务超时问题
  • Redis学习笔记 - pipline(流水线、管道)
  • 彻底搞懂浏览器Event-loop
  • 猴子数据域名防封接口降低小说被封的风险
  • 来,膜拜下android roadmap,强大的执行力
  • 蓝海存储开关机注意事项总结
  • 使用API自动生成工具优化前端工作流
  • 最近的计划
  • 《天龙八部3D》Unity技术方案揭秘
  • 阿里云API、SDK和CLI应用实践方案
  • $nextTick的使用场景介绍
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (LLM) 很笨
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (二) 初入MySQL 【数据库管理】
  • (三)Honghu Cloud云架构一定时调度平台
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET CORE Aws S3 使用
  • .net framework4与其client profile版本的区别
  • .NET Micro Framework初体验
  • .Net 中Partitioner static与dynamic的性能对比
  • .Net实现SCrypt Hash加密
  • .sh
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [ 隧道技术 ] 反弹shell的集中常见方式(二)bash反弹shell
  • [AI Google] Ask Photos: 使用Gemini搜索照片的新方法
  • [AI 大模型] 百度 文心一言
  • [C#C++]类CLASS
  • [CC-FNCS]Chef and Churu
  • [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated c
  • [GXYCTF2019]BabyUpload1 -- 题目分析与详解
  • [hadoop读书笔记] 第十五章 sqoop1.4.6小实验 - 将mysq数据导入HBASE