数据结构之队列

目录

队列的定义与结构

  队列的实现

队列的结构

初始化空队列

销毁队列

队尾入队列

队头出队列

获取队列头部元素

获取队列尾部元素

判断队列是否为空

获取队列长度

栈与队列经典试题

队列实现栈

栈实现队列


队列的定义与结构

队列是一种先进先出(First In First Out)的顺序表,队列只允许在表的一端进行插入,而在另一端删除元素;队列中允许插入的一端叫做队尾允许删除的一端称为队头;假设队列为q=(a1,a2,a3,......,an),那么a1就是对头元素,an就是队尾元素;

入队列的顺序为a1,a2,a3,.....an,出队列的顺序为a1,a2,a3,......an退出;

  队列的实现

思考:选择数组还是链表去实现队列?

若选择数组实现队列,当元素出队列时,头部与尾部都要移动元素,时间复杂度为O(N)

若选择链表实现队列,通过定义队头指针和队尾指针,入队列与出队列的时间复杂度为O(1);

采用单链表的思考:

队列在尾部添加元素,在头部删除元素(尾进头出);采用链表头作为队列的头部,因为链表头部容易执行删除操作(出队)链表尾作为队列的尾部,执行插入操作(入队);但是执行插入操作时,首先得遍历整个链表,找到最后一个链表结点(尾结点),才能执行插入操作(入队列),为了减少遍历,需要维护一个尾指针,指向链表尾部;使用单列表实现一个队列,链表需要维护俩个指针,头指针和尾指针;头指针指向链表头部,用于出队列尾指针指向链表尾部,用于入队列

  • 空队列示意图

  •  空队列插入第一个元素示意图

  • 入队(单链表尾插)

  • 出队 (单链表头删)

队列的结构

typedef int QDataType;
typedef struct QueueNode
{QDataType data;//数据域struct QueueNode* next;//指针域-指向下一个队列结点
}QueueNode;//当进行出队列操作(头删),需要修改队头指针,但是对于形参的修改不影响实参,只能传递二级指针;
//采取如下方案:将对头指针,队尾指针封装成结构体,只需要修改结构体指针即可修改结构体变量;
typedef struct Queue
{QueueNode* head;//队头指针QueueNode* tail;//队尾指针int size;//获取队列的长度
}Queue;

初始化空队列

当队头指针head与队尾指针均为空指针,且队列的长度为0,此时链队列为空;

void InitQueue(Queue* ps)
{assert(ps != NULL);ps->tail = ps->head = NULL;ps->size = 0;
}

销毁队列

void DestroyQueue(Queue* ps)
{assert(ps != NULL);QueueNode* cur = ps->head;while (cur != NULL){QueueNode* next = cur->next;free(cur);cur= next;}ps->head = NULL;ps->tail = NULL;ps->size = 0;
}

队尾入队列

//队尾入队列(尾插)
void QueuePush(Queue* ps, QDataType x)
{assert(ps != NULL);//创建新队列结点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc failed:");exit(-1);}newnode->data = x;newnode->next = NULL;//入队列(尾插)//空队列时通过赋值完成尾插,队列中存在队列结点,按照逻辑关系完成连接;if (ps->tail == NULL){ps->head = ps->tail = newnode;}else{ps->tail->next = newnode;ps->tail = newnode;}ps->size++;
}

队头出队列

//队头出队列(头删)
void QueuePop(Queue* ps)
{assert(ps != NULL);//空队列不可删assert(ps->tail != NULL);//出队列//队列中只有一个队列结点if (ps->head->next == NULL){free(ps->head);ps->head = ps->tail = NULL;}//队列中有两个以上队列结点else{QueueNode* next = ps->head->next;free(ps->head);ps->head = next;}ps->size--;
}

获取队列头部元素

//获取队列头部元素
QDataType QueueFront(Queue* ps)
{assert(ps != NULL);//队列不为空assert(ps->head != NULL);return ps->head->data;
}

获取队列尾部元素

//获取队列尾部元素
QDataType QueueBack(Queue* ps)
{assert(ps != NULL);//队列不为空assert(ps->tail != NULL);return ps->tail->data;
}

判断队列是否为空

队列为空返回true,队列不为空false;

//判断队列是否为空
bool QueueEmpty(Queue* ps)
{assert(ps);if (ps->tail == NULL){return true;}return false;
}

获取队列长度

//获取队列长度
int QueueLength(Queue* ps)
{assert(ps);return ps->size;
}

栈与队列经典试题

  • 队列实现栈

题目描述

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty);

实现 MyStack 类:

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

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

假设栈中入栈顺序为A B C D;则出栈顺序为D C B A; 如何用队列达到这种效果?

首先将栈中的数据全部存放于一个队列,其次将存放数据的队列取对头元素入空队列,直至原先存放数据的队列只剩一个数据为止;

此时原先的队列只剩一个元素,调用QueuePop()函数就可达到StackPop()函数的效果,但仅仅是一个元素达到了后进先出,将元素D删除后,回到原先假设情形;

 继续将非空队列中的数据放入空队列,直至非空队列只剩1个元素,调用QueuePop()函数删除仅剩元素;

按此循环,直至两个队列全部为空;这样达到了出栈顺序为D C B A;

假设栈中入栈顺序为A B C D,出栈两个元素即先删除D,后删除C;然后再入栈元素E, 那么元素E应该送入那个队列?才能完成出栈顺序为D C E B A?

为了维持原先逻辑的一致性,选择将元素E送入到非空队列;然后继续按照原先逻辑pop数据;

 

 思路总结:

数据入队列时,首先判断出那个队列不是空队列,然后将数据送入非空队列;

数据出队列时,非空队列的前size-1个数据全部插入到空队列,然后删除非空队列仅剩的一个元素;两个队列始终保持一个为空;

(注:队列定义时size为队列中有效数据的个数)

typedef struct 
{Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() 
{MyStack* p=(MyStack*)malloc(sizeof(MyStack));InitQueue(&(p->q1));InitQueue(&(p->q2));return p;
}//那个队列不为空,数据尾插到那个队列
void myStackPush(MyStack* obj, int x) 
{
if(!QueueEmpty(&(obj->q1)))
{QueuePush(&(obj->q1),x);
}
//队列q1为空,无论队列q2为不为空,数据尾插到q2;
else
{QueuePush(&(obj->q2),x);
}
}int myStackPop(MyStack* obj) 
{//首先判断那个是空队列,假设法;Queue* Empty=&(obj->q1);Queue* NonEmpty=&(obj->q2);if(!QueueEmpty(&(obj->q1))){Empty=&(obj->q2);NonEmpty=&(obj->q1);}//空队列为Empty,非空队列为NonEmpty;//由于队列中包含队列的长度,需要将非空队列的前size-1个数据插入到空队列;//队列每出一个数据,长度自动减一,当非空队列大于1个元素,不断将非空队列的数据插入到空队列;while(QueueLength(NonEmpty)>1){QueuePush(Empty,QueueFront(NonEmpty));QueuePop(NonEmpty);}//非空队列只剩一个元素int top=QueueBack(NonEmpty);QueuePop(NonEmpty);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) 
{DestroyQueue(&(obj->q1));DestroyQueue(&(obj->q2));free(obj);
}
  • 栈实现队列

题目描述:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

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

题目链接力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

假设队列中入队列顺序为A B C D;则出队列顺序为A B C D; 如何用栈达到这种效果?

首先将队列中的数据全部存放于一个栈(pushstack),其次将存放数据的栈取栈顶元素依次入空栈(popstack),直至原先存放数据的栈为空;

此时popstack栈不断pop(删除)数据,直至popstack栈为空;达到了入队列顺序为A B C D ,出队列顺序为A B C D ;

 假设队列中入队列顺序为A B C D,出队列两个元素即先删除A,后删除B;然后再入队列元素E, 那么元素E应该送入那个栈?才能完成出队列顺序为A B C D E?

数据E只能存放于空栈pushstack,只有当非空栈数据pop(删除)结束,然后将pushstack中的数据E插入到popstack栈,才能完成出队列顺序为A B C D E;

 思路总结:

数据先送入到pushstack,不断入栈,当需要出数据时,为达到先入先出的效果,将pushstack栈中的数据全部送入popstack栈中,如果此时还有数据需要入栈,全部送入pushstack中,然后不断从popstack栈中pop(删除)数据,当popstack栈为空时,再将pushstack栈中的数据全部送入popstack栈中,按此循环;
typedef struct 
{Stack pushstack;//入数据Stack popstack;//出数据
} MyQueue;//初始化队列
MyQueue* myQueueCreate() 
{MyQueue* pst=(MyQueue*)malloc(sizeof(MyQueue));InitStack(&(pst->popstack));InitStack(&(pst->pushstack));return pst;
}//数据入栈时全部存放于pushstack;
void myQueuePush(MyQueue* obj, int x) 
{StackPush(&(obj->pushstack),x);
}//首先判断popstack栈是否为空,若popstack栈为空
//需要将pushstack栈中的数据全部送入popstack栈中;
//若popstack栈不为空,直接出数据,直到popstack为空;
int myQueuePop(MyQueue* obj) 
{if(StackEmpty(&(obj->popstack))){//捯数据,将pushstack栈中的数据全部放入popstack栈中;while(!StackEmpty(&(obj->pushstack))){StackPush(&(obj->popstack),StackTop(&(obj->pushstack)));StackPop(&(obj->pushstack));//干掉pushstack栈中栈顶元素}}//popstack栈不为空int top=StackTop(&(obj->popstack));StackPop(&(obj->popstack));return top;
}//获取队头数据即popstack栈中即将出栈的第一个数据;
int myQueuePeek(MyQueue* obj)
{if(StackEmpty(&(obj->popstack))){//捯数据,将pushstack栈中的数据全部放入popstack栈中;while(!StackEmpty(&(obj->pushstack))){StackPush(&(obj->popstack),StackTop(&(obj->pushstack)));StackPop(&(obj->pushstack));//干掉pushstack栈中栈顶元素}}//popstack栈不为空return StackTop(&(obj->popstack));
}//若队列为空当且仅当popstack与pushstack都为空;
bool myQueueEmpty(MyQueue* obj) 
{return StackEmpty(&(obj->pushstack))&&StackEmpty(&(obj->popstack));
}
//销毁队列
void myQueueFree(MyQueue* obj) 
{DestroyStack(&(obj->pushstack));DestroyStack(&(obj->popstack));free(obj);
}

                                                     

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

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

相关文章

Netty源码编译

Netty源码编译 想了解Netty源码,最好先从 netty-example 开始,多跑几个 example,了解Netty的实际应用。 编译 netty-example 会出现很多乱七八糟的问题,根本原因是因为缺少 io.netty.util.collection 包。 解决方法 1.先 instal…

指针(2)

1.数组名的理解 一般数组名就是数组首元素的地址 但是有2个例外:1.sizeof(数组名) 这里面数组名表示的是整个数组,计算整个数组的大小,单位为字节。 …

简单易用,效果卓越的电子期刊制作网站

在日常工作和生活中,我们常常需要制作各种文档和资料,比如电子期刊、宣传册、产品手册等。但有时候,我们会因为排版、设计、编辑等问题而感到烦恼。这时候,一个简单易用、效果卓越的电子期刊制作网站就成为了我们的得力助手&#…

相似性搜索:第 1 部分- kNN 和倒置文件索引

图片来源:维亚切斯拉夫叶菲莫夫 一、说明 SImilarity 搜索是一个问题,给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。 在数据科学中,相似性搜索经常出现在NLP领域,搜索引擎或推荐系统中,其中需要检索最…

目标文件格式

目标文件里有什么 目标文件格式 目标文件就是源代码编译后但未进行链接的中间文件(linux下的.o)。 ELF文件:从广义上看,目标文件与可执行文件的格式其实几乎是一样的,可以将目标文件与可执行文件看成是一种类型的文…

忘记开机密码啦!我教你用ventoy找回密码

文章目录 一、前言二、实战过程三、动态演示四、原理解析五、总结 一、前言 当你有一天突然忘记了开机密码怎么办?又要上电脑店花个几十块让人弄?在上一章《你该自己学学安装操作系统了,小白一学就会(ventoy装系统超详细&#xff…

Unity设计模式——建造者模式

Product类——产品类&#xff0c;由多个部件组成。 class Product {IList<string> parts new List<string>();//添加产品部件public void Add(string part){parts.Add(part);}public void Show(){foreach (string part in parts){Debug.Log("产品:"pa…

python+深度学习+opencv实现植物识别算法系统 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的植物识别算法研究与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 更多…

Android+Appium自动化测试环境搭建及实操

1、Appium简介1.1 Appium概念1.2 Appium工作原理 2、Appium Server环境搭建2.1 Java JDK2.1.1 下载JDK2.1.2 运行exe安装JDK&#xff0c;设置安装路径2.1.3 设置环境变量2.1.4 验证安装结果 2.2 Android SDK2.2.1 下载安装Android SDK安装包2.2.2 下载platform-tools&#xff0…

Linux下将驱动编译进内核

在开发的过程中&#xff0c;一般都是将驱动编译成模块&#xff0c;然后将其发送到开发板加载驱动进行功能验证&#xff0c;驱动的功能验证没有问题后就可以将其编译进内核了。本文将介绍如何把上一篇文章Linux下设备树、pinctrl和gpio子系统、LED灯驱动实验中的LED驱动编译到内…

【LeetCode】9. 回文数

1 问题 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff0c;121 是回文&…

【计算机网络】IP协议详解

文章目录 一、引入 二、简单认识IP协议 2、1 IP协议基本概念 2、2 IP协议报文格式 2、3 分片与组装 2、3、1 MTU 与 MSS 2、4 网段划分 2、4、1 简单理解路由 2、4、2 IP地址 2、4、3 IP地址的划分 2、4、4 CIDR&#xff08;无类别域间路由&#xff09; 2、4、5 特殊的IP地址 …

Redis微服务架构

Redis微服务架构 缓存设计 缓存穿透 缓存穿透是指查询一个根本不存在的数据&#xff0c;缓存层和存储层都不会命中&#xff0c;通常出于容错的考虑&#xff0c;如果从存储层查不到数据则不写入缓层。 缓存穿透将导致不存在的数据每次请求都要到存储层去查询&#xff0c;失去…

【Nginx32】Nginx学习:随机索引、真实IP处理与来源处理模块

Nginx学习&#xff1a;随机索引、真实IP处理与来源处理模块 完成了代理这个大模块的学习&#xff0c;我们继续其它 Nginx 中 HTTP 相关的模块学习。今天的内容都比较简单&#xff0c;不过最后的来源处理非常有用&#xff0c;可以帮我们解决外链问题。另外两个其实大家了解一下就…

Java IO流

IO 即 Input / Output &#xff0c;输入输出流。IO流在Java中分为输入流和输出流&#xff0c;而根据数据的处理方式又分为字节流和字符流。 Java IO 流的 40 多个类都是从如下 4 个 抽象类基类中派生出来的。 InputStream /Reader : 所有的输入流的基类&#xff0c;前者是字节…

大数据flink篇之三-flink运行环境安装(一)单机Standalone安装

一、安装包下载地址 https://archive.apache.org/dist/flink/flink-1.15.0/ 二、安装配置流程 前提基础&#xff1a;Centos环境&#xff08;建议7以上&#xff09; 安装命令&#xff1a; 解压&#xff1a;tar -zxvf flink-xxxx.tar.gz 修改配置conf/flink-conf.yaml&#xff1…

IDEA通过Docker插件部署SpringBoot项目

1、配置Docker远程连接端口 找到并编辑服务器上的docker.service文件。 vim /usr/lib/systemd/system/docker.service在下面ExecStart替换成下面的 ExecStart/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock2.重启docker systemctl daemon-reload s…

交叉熵Loss多分类问题实战(手写数字)

1、import所需要的torch库和包 2、加载mnist手写数字数据集&#xff0c;划分训练集和测试集&#xff0c;转化数据格式&#xff0c;batch_size设置为200 3、定义三层线性网络参数w&#xff0c;b&#xff0c;设置求导信息 4、初始化参数&#xff0c;这一步比较关键&#xff0c;…

强化学习(Reinforcement Learning)与策略梯度(Policy Gradient)

写在前面&#xff1a;本篇博文的内容来自李宏毅机器学习课程与自己的理解&#xff0c;同时还参考了一些其他博客(懒得放链接)。博文的内容主要用于自己学习与记录。 1 强化学习的基本框架 强化学习(Reinforcement Learning, RL)主要由智能体(Agent/Actor)、环境(Environment)、…

【学习笔记】项目进行过程中遇到有关composer的问题

composer.json内容详解 以项目中的composer.json为例&#xff0c;参考文档。 name&#xff1a;composer包名type&#xff1a;包的类型&#xff0c;project和library两种keywords&#xff1a;关键词&#xff0c;方便别人在安装时通过关键词检索&#xff08;没试过&#xff0c;好…