栈和队列(二) 队列操作详解及栈与队列的相互实现

文章目录

  • 四、队列
    • 1、什么是队列
    • 2、队列的基本操作
      • Queue.h
      • Queue.c
        • 初始化队列
        • 队尾入队列
        • 队头出队列
        • 获取队列头部元素
        • 获取队列队尾元素
        • 获取队列中有效元素个数
        • 检测队列是否为空,如果为空返回非零结果,如果非空返回0
        • 销毁队列
  • 五、设计循环队列
  • 六、栈与队列的相互实现
    • 1、用栈实现队列
    • 2、用队列实现栈

栈操作实现:栈和队列(一) 栈操作详解

在这里插入图片描述

四、队列

1、什么是队列

队列就像是高速公路上的一个隧道一样,所有的车辆只允许从入口驶入,从出口驶出,先进先出,不允许逆行。

队列(queue)是一种线性数据结构,队列的元素只能先入先出(First In First Out,简称FIFO)。
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

在这里插入图片描述

2、队列的基本操作

利用单链表来实现队列的基本操作

在这里插入图片描述

代码结构设计:

  • Queue.h: 存放队列结构及需要用到的头文件,函数声明等
  • Queue.c: 各种操作函数的具体实现

Queue.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//方便修改数据类型
typedef int QDataType;// 链式结构:表示队列 
typedef struct QListNode
{struct QListNode* next;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);

Queue.c

#include "Queue.h"

初始化队列

void QueueInit(Queue* q)
{assert(q);q->front = NULL;q->rear = NULL;
}

队尾入队列

void QueuePush(Queue* q, QDataType data)
{assert(q);//创建一个节点放数据QNode* newNode=(QNode*)malloc(sizeof(QNode));if (newNode == NULL){perror("malloc fail");exit(-1);}newNode->data = data;newNode->next = NULL;//判断是否是第一个入队元素if (q->rear == NULL){q->front = q->rear = newNode;}else{q->rear->next= newNode;q->rear = newNode;}
}

在这里插入图片描述

队头出队列

void QueuePop(Queue* q)
{assert(q);assert(!QueueEmpty(q));//判断是否只有一个元素if (q->front->next == NULL){free(q->front);q->front = q->rear = NULL;}else{QNode* del = q->front;q->front = q->front->next;free(del);}
}

在这里插入图片描述

获取队列头部元素

front是队头节点,它的数据便是队头元素

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

获取队列队尾元素

rear是队尾节点,它的数据便是队尾元素

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

获取队列中有效元素个数

遍历一遍链表就能得到有效元素个数,也可以直接给队列的结构里加上一个size

int QueueSize(Queue* q)
{assert(q);QNode* cur = q->front;int size = 0;while (cur){cur = cur->next;size++;}return size;
}

检测队列是否为空,如果为空返回非零结果,如果非空返回0

int QueueEmpty(Queue* q)
{assert(q);//队头节点为空说明队列为空return q->front == NULL;
}

销毁队列

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

五、设计循环队列

循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

设计循环队列实现以下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

创建队列时多开辟一个空间来区分空和满
如下是一个队列长度k=4的循环队列:
在这里插入图片描述
用数组实现

//循环队列结构
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=0;obj->rear=0;obj->k=k;return obj;
}
//判断队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//当队头和队尾相等时队列为空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++;//特殊情况(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;}return obj->a[obj->front];
}
//获取队尾元素
//rear是队尾元素下一个元素的下标,所以队尾元素的下标为rear-1
//但当rear等于0的时候队尾元素下标为k,需要特殊处理
int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}// if(obj->rear==0)// {//     return obj->a[obj->k];// }else// {//     return obj->a[obj->rear-1];// }return obj->a[((obj->rear)+(obj->k))%(obj->k+1)];
}

在这里插入图片描述

//销毁队列
void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);
}

六、栈与队列的相互实现

1、用栈实现队列

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路:

用两个栈实现先入先出队列,当有元素入队时,就是在pushst入栈

在这里插入图片描述
当出队时,将pushst中元素依次出栈放进popst中,然后对popst进行出栈操作

在这里插入图片描述

代码实现:

用的是前面自己实现的栈来实现的

typedef struct {ST pushst;ST popst;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));STInit(&obj->pushst);STInit(&obj->popst);return obj;
}void myQueuePush(MyQueue* obj, int x) {STPush(&obj->pushst,x);
}int myQueuePeek(MyQueue* obj) {if(STEmpty(&obj->popst)){while(!STEmpty(&obj->pushst)){STPush(&obj->popst,STTop(&obj->pushst));STPop(&obj->pushst);}}return STTop(&obj->popst);
}int myQueuePop(MyQueue* obj) {int ret=myQueuePeek(obj);STPop(&obj->popst);return ret;
}bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}void myQueueFree(MyQueue* obj) {STDestroy(&obj->pushst);STDestroy(&obj->popst);free(obj);
}

2、用队列实现栈

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

思路:

用两个队列q1和q2来实现一个后入先出的栈

入栈:放进不为空的那个队列
在这里插入图片描述

出栈:不为空队列的前n-1个出队列插入空队列,删除剩下的一个即可

在这里插入图片描述
代码实现:

用的是前面自己实现的队列来实现的

typedef struct {Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() {MyStack* p=(MyStack*)malloc(sizeof(MyStack));QueueInit(&p->q1);QueueInit(&p->q2);return p;
}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);}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);
}

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

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

相关文章

整数中1出现的次数(从1到n整数中1出现的次数)

解题思路1&#xff1a; 设定整数点&#xff08;如1、10、100等等&#xff09;作为位置点i&#xff08;对应n的各位、十位、百位等等&#xff09;&#xff0c;分别对每个数位上有多少包含1的点进行分析。 第一步&#xff1a;对n进行分割&#xff0c;分为两部分&#xff1a;高位…

标准化归一化 batch norm, layer norm, group norm, instance norm

Layer Normalization - EXPLAINED (in Transformer Neural Networks) Layer Normalization - EXPLAINED (in Transformer Neural Networks) 0~4min:什么是multi-head attention 5~7min:layer norm图示 7~9min:公式举例layer norm 9:54-end:layer norm的代码示例 group n…

Redis安装配置远程连接

1. yum 安装 redis&#xff1a; 直接使用命令&#xff0c;将 redis 安装到 linux 服务器中&#xff1a; yum -y install redis 2. 启动 redis&#xff1a; 在 xshell 里&#xff0c;可以使用下面命令&#xff0c;以后台方式启动 redis&#xff1a; [rootVM-8-17-centos /]…

【李宏毅机器学习·学习笔记】Tips for Training: Batch and Momentum

本节课主要介绍了Batch和Momentum这两个在训练神经网络时用到的小技巧。合理使用batch&#xff0c;可加速模型训练的时间&#xff0c;并使模型在训练集或测试集上有更好的表现。而合理使用momentum&#xff0c;则可有效对抗critical point。 课程视频&#xff1a; Youtube&…

# X11、Xlib、XFree86、Xorg、GTK、Qt、Gnome和KDE之间的关系

X11、Xlib、XFree86、Xorg、GTK、Qt、Gnome和KDE之间的关系 很多人对于他们是啥是傻傻分不清的&#xff0c;我做了个表格供大家参考。 摘抄&#xff1a; X11是X Window System Protocol, Version 11&#xff08;RFC1013&#xff09;&#xff0c;是X server和X client之间的通…

Observability:识别生成式 AI 搜索体验中的慢速查询

作者&#xff1a;Philipp Kahr Elasticsearch Service 用户的重要注意事项&#xff1a;目前&#xff0c;本文中描述的 Kibana 设置更改仅限于 Cloud 控制台&#xff0c;如果没有我们支持团队的手动干预&#xff0c;则无法进行配置。 我们的工程团队正在努力消除对这些设置的限制…

100G光模块的应用案例分析:电信、云计算和大数据领域

100G光模块是一种高速光模块&#xff0c;由于其高速率和低延迟的特性&#xff0c;在电信、云计算和大数据领域得到了广泛的应用。在本文中&#xff0c;我们将深入探讨100G光模块在这三个领域的应用案例。 一、电信领域 在电信领域&#xff0c;100G光模块被广泛用于构建高速通…

ECRS工时分析:什么叫标准化作业管理?为什么要进行作业标准化管理

中国自古就有标准化。《孙子兵法》中&#xff0c;孙子训练射箭&#xff0c;射箭的姿势是“标准化操作”&#xff1b;中国武术中的套路是“标准化”&#xff1b;在中国古诗中&#xff0c;字数甚至被“标准化”来打开中国历史&#xff0c;“标准化”作业的例子数不胜数。 而在工厂…

mac-右键-用VSCode打开

1.点击访达&#xff0c;搜索自动操作 2.选择快速操作 3.执行shell脚本 替换代码如下&#xff1a; for f in "$" doopen -a "Visual Studio Code" "$f" donecommand s保存会出现一个弹框&#xff0c;保存为“用VSCode打开” 5.使用

Spring项目整合过滤链模式~实战应用

代码下载 设计模式代码全部在gitee上,下载链接: https://gitee.com/xiaozheng2019/desgin_mode.git 日常写代码遇到的囧 1.新建一个类,不知道该放哪个包下 2.方法名称叫A,干得却是A+B+C几件事情,随时隐藏着惊喜 3.想复用一个方法,但是里面嵌套了多余的逻辑,只能自己拆出来…

MFC计算分贝

分贝的一种定义是&#xff0c;表示功率量之比的一种单位&#xff0c;等于功率强度之比的常用对数的10倍&#xff1b; 主要用于度量声音强度&#xff0c;常用dB表示&#xff1b; 其计算&#xff0c;摘录网上一段资料&#xff1b; 声音的分贝值可以通过以下公式计算&#xff1…

css内容达到最底部但滚动条没有滚动到底部

也是犯了一个傻狗一样的错误 &#xff0c;滚动条样式是直接复制的蓝湖的代码&#xff0c;有个高度&#xff0c;然后就出现了这样的bug 看了好久一直以为是布局或者overflow的问题&#xff0c;最后发现是因为我给这个滚动条加了个高度&#xff0c;我也是傻狗一样的&#xff0c;…