目录

  • 一.引入
  • 二.队列的定义
  • 三.队列的抽象数据类型
  • 四.队列的存储方式
  • 五.队列的顺序存储(不太常用 后面5.4会给出原因)
    • 5.1顺序存储队列的基本知识点
    • 5.2队列的顺序存储描述
    • 5.3顺序存储队列的操作
      • 5.3.1初始化
      • 5.3.2进队操作
      • 5.3.3出队操作
      • 5.3.4判空操作
      • 5.3.5判满操作
    • 5.4假溢出问题
  • 六.循环队列
    • 6.1循环队列的定义
    • 6.2循环队列如何判满/空
    • 6.3循环队列的存储结构
    • 6.4循环队列的操作
      • 6.4.1循环队列的初始化
      • 6.4.2循环队列求队列长度
      • 6.4.3循环队列入队列操作
      • 6.4.4循环队列出队列操作
  • 七.队列的链式存储结构
    • 7.1链队列示意图
    • 7.2链队列结构描述
    • 7.3链队列基本操作
      • 7.3.1链队列初始化
      • 7.3.2链队列入队操作
      • 7.3.3链队列出队操作
  • 八.总结

一.引入

最近,大家肯定都有排队做核酸检测的经历,检测医生与待检人员相比总是少数的,在所有检测窗口都有人正在检测的情况下,后面的人会被要求等待,直到某一窗口空下来,才可以让最前面等待的人做核酸。
在这一过程中,应用了一种数据结构来实现刚才提到的先进先出的排队功能,这种数据结构就是队列。

二.队列的定义

队列是只允许在一端进行插入操作,而另一端进行删除操作的线性表。

队列是一种先进先出的线性表,简称FIFO,允许插入的一端为队尾;允许删除的一端为队头。

三.队列的抽象数据类型

队列同样是线性表,队列也有类似线性表的各种操作,不同的是插入和删除:插入的是时候在队尾进行,删除的时候在队头进行。

ADT 队列(Queue)
Data
同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
InitQueue(*Q): 初始化操作,建立一个空队列Q。
DestroyQueue(*Q): 若队列Q存在,則销毀它。
ClearQueue(*Q): 将队列 Q 清空。
QueueEmpty(Q): 若队列Q为空,送回true,否則退回false。
GetHead(Q, *e): 若队列Q存在且非空,用e返因队列Q的队头元素。
EnQueue(*Q,e): 若队列Q存在,插入新元素e到队列Q中并成为队尾元素。
DeQueue(*Q, *e): 刪除队列Q中队头元素,并用e返回其值。
QueueLength(Q): 送回队列Q的元素个教。
endADT

四.队列的存储方式

线性表有顺序存储和链式存储,同样,队列作为一种特殊的线性表,也同样存在这两种存储方式;
下面对这两种存储方式进行详细讲解。

五.队列的顺序存储(不太常用 后面5.4会给出原因)

5.1顺序存储队列的基本知识点

队列的顺序存储分配一块连续的存储单元存放队列中的元素,并附设两个指针 front 和 rear 分别指示队头元素和队尾元素的位置。
设队头指针指向队头元素,队尾指针指向队尾元素的下一个位置。

5.2队列的顺序存储描述

代码如下:

#define MAXSIZE 100
typedef struct {ElemType data[MAXSIZE];int front,rear;
} SqQueue;

5.3顺序存储队列的操作

5.3.1初始化

初始状态(队空):Q.front == Q.rear == 0;

5.3.2进队操作

队不满时,先送值到队尾元素,将队尾指针加1。

5.3.3出队操作

队非空时,先删除队头元素,再将队头指针加1。

5.3.4判空操作

Q.front == Q.rear == 0;

5.3.5判满操作

大家试想Q.rear == MAXSIZE 作为队列已满的条件呢?

这显然是不行的,因为队尾指针在这个过程中可能已经到了最尾端,但是队头指针可能不在初始位置,而是在队列的中间。

因为我们无法对队列进行判满操作,因此就会出现下面“假溢出”的问题。

5.4假溢出问题

下图为队列的假溢出图,即下标 0 和 1 的位置还是空闲的,然而指向队尾的指针rear已经出现了数组越界的错误。为了避免这种越界的情况,一般顺序队列也指循环队列。

所以解决假溢出的办法就是后面满了,就从头开始,因此我们需要引入循环队列。

六.循环队列

6.1循环队列的定义

我们把队列的头尾相接的顺序存储结构称为循环队列。

注意
对于循环队列来说:我们是将队列臆造成一个环状的空间,即把存储队列元素的表从按逻辑上视为一个环这样方便我们的理解,真实的物理内存不是环状的。

6.2循环队列如何判满/空

在空队列时:front等于rear,当队列满时:也是front等于rear;那么如何判断此时的队列是空是满,以下有两种方法:

  1. 设置一个标志变量flag,当front= =rear,且flag=0时为队列空,当front= =rear,且flag=1时为队列满。
  2. 当队列空时,条件就是front=rear,当队列满时,我们修改它的条件,保留一个元素空间。也就是说,当队列满时,数组中还有一个空闲单元,我们就认为此队列满了,如下图所示:

    不允许出现以下情况出现:

接下来我们对第二种方式进行实现:

  1. 队列空的条件:front = = rear
  2. 队列满的条件:(rear + 1)% QueueSize = = front其中,rear为指向队尾元素的下一位置的指针,front 为指向队头元素的指针。QueueSize为队列的最大长度。
  3. 通用计算队列长度公式:
    (rear - front + QueueSize) % QueueSize

6.3循环队列的存储结构

代码如下:

typedef int QElemtype;
typedef struct
{QElemtype data[MAXSIZE];int front; //头指针int rear;  //尾指针,若队列不空,指向队列尾元素的下一个位置
}SqQueue;

6.4循环队列的操作

6.4.1循环队列的初始化

代码如下:

//初始化一个空队列
bool InitQueue(SaQueue *Q)
{Q->front=0;Q->rear=0;return true;
}

6.4.2循环队列求队列长度

注意: 这个公式一定要记住,很重要:
(Q.rear-Q.front+MAXSIZE)%MAXSIZE;
代码如下:

//返回Q的元素个数,也是队列的当前长度
int QueueLength(SqQueue Q)
{return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}

6.4.3循环队列入队列操作

代码如下:

//若队列未满,则插入元素e为Q新的队尾元素
bool EnQUeue(SqQueue *Q,QElemType e)
{if ((Q->rear+1)%MAXSIZE==Q->front)//队列满的判断return FALSE;Q->data[Q->rear]=e;//将元素e赋值给队尾Q->rear=(Q->rear+1)%MAXSIZE;//rear指针向后移一位置//若到最后则转到数组头部return TRUE;
}

6.4.4循环队列出队列操作

代码如下:

//若队列不空,则删除Q中队头,用e返回其值
bool DeQueue(SqQueue *Q,QELemType *e)
{if(    Q->front==Q->reat=r)   //队列空的判断return FALSE;*e =Q->data[Q->front];//将队头元素赋值给eQ->front=(Q->front+1)%MAXSIZE;//front指针向后移一位置//若到最后则转到数组头部return TRUE;
}

循环队列还会面临着数组溢出的问题,所以下一部分我们将会讲解不用担心队列长度的链式存储结构。

七.队列的链式存储结构

队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列。

7.1链队列示意图

为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端结点。
示意图如下:

空队列时,front和rear都指向头结点,如图所示:

7.2链队列结构描述

代码如下:

typedef struct LinkNode{ElemType data;struct LinkNode* next;
}LinkNode;
typedef struct{LinkNode *front, *rear;
}LinkQueue;

7.3链队列基本操作

7.3.1链队列初始化

代码如下:

void InitQueue(LinkQueue& Q){//初始化时,Q.front 和 Q.rear 同时指向头结点Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));Q.front->next = nullptr;
}

7.3.2链队列入队操作

入队操作,就是在链表尾部插入节点,示意图如下:

代码如下:

bool EnQueue(LinkQueue& Q, ElemType x){LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));s->data = x;s->next = nullptr;Q.rear->next = s; //步骤(1)Q.rear = s;      //步骤(2)return true;
}

7.3.3链队列出队操作

出队操作就是头结点的后继结点出队,将头结点的后继改为它后面的结点,若链表除头结点外只剩一个元素时,则需将rear指向头结点;示意图如下:
代码如下:

bool DeQueue(LinkQueue& Q, ElemType &x){if( Q.rear == Q.front ){return false;}LinkNode* p = Q.front->next; //因为有头结点,所以队头节点为Q.front->next   //(1)步骤x = p->data;Q.front->next = p->next; //(2)步骤if( Q.rear == p ){           //只剩一个结点,删除后变空只剩头结点Q.rear = Q.front;}free(p);return true;
}

八.总结

对于循环队列与链队列的比较,可以从两方面来考虑:

时间上 空间上
循环队列事先申请号空间,使用期间不释放 循环队列必须有一个固定的长度,所以就有存储元素和空间浪费的问题
链队列每次申请和释放结点也会存在一些时间开销 链队列不会存在上述问题,尽管需要一个指针域,有空间消耗但可以接受

总的来说:在可以确定队列长度最大值的情况下,建议用循环队列,如果你无法预估队列的长度时,则使用链队列。

数据结构 队列(顺序队列 循环队列 链队列)相关推荐

  1. 【数据结构(C++)】用链队列计算杨辉三角

    目录 第一节 概述 第二节 开源代码 第一节 概述 杨辉三角是二项式系数在三角形中的一种几何排列,是中国古代数学的杰出研究成果之一.它把二项式系数图形化,把组合数内在的一些代数性质直观地从图形中体现出 ...

  2. 【C++算法与数据结构学习笔记------用循环数组实现队列】

    照王晓东<数据结构>(C++语言版)上打的,以备留用. 1 #include <iostream> 2 using namespace std; 3 template<t ...

  3. 数据结构与算法(3-2)队列(顺序队列、循环队列与链队列)

    目录 一.顺序队列 1.存储结构 2.入队和出队 总代码 二.循环队列 总代码: 三.链队列 1.存储结构 2.入队和出队 总代码 一.顺序队列 队列特征:先进后出.后进后出. 1.存储结构 //队列 ...

  4. c语言循环队列入列算法,C语言——循环队列和链队列的基本运算

    // 循环队列 #include #include "SeqQue.h" // 循环队列的基本运算 /* const int maxsize = 20; typedef struc ...

  5. 《恋上数据结构第1季》队列、双端队列、循环队列、循环双端队列

    队列(Queue) 队列 Queue 队列的接口设计 队列源码 双端队列 Deque 双端队列接口设计 双端队列源码 循环队列 Circle Queue 循环队列实现 索引映射封装 循环队列 – %运 ...

  6. 数据结构(严蔚敏)之六——链式队列c语言实现

    实验: 编写一个程序实现链队列的各种基本运算,并在此基础上设计一个主程序,完成如下功能: (1)初始化并建立链队列 (2)入链队列 (3)出链队列 (4)遍历链队列 分析: 队列的链式存储结构简称为链 ...

  7. 《数据结构C语言版》——栈和队列详解(图文并茂),从零开始的学习

    哈喽!这里是一只派大鑫,不是派大星.本着基础不牢,地动山摇的学习态度,从基础的C语言语法讲到算法再到更高级的语法及框架的学习.更好地让同样热爱编程(或是应付期末考试 狗头.jpg)的大家能够在学习阶段 ...

  8. 【练习】c++分别用链队列和普通队列输出杨辉三角

    普通队列: class queue {public:queue();bool empty()const;bool full() const;int get_front(int& x)const ...

  9. 【数据结构】队列-顺序队列、循环队列、链队、双端队列

    定义 队列是只允许在一端进行插入,而在另一端进行删除的线性表. 队头(Front):允许删除的一端,又称为队首. 队尾(Rear): 允许插入的一端. 先进入队列的元素必然先离开队列,即先进先出(Fi ...

最新文章

  1. 一年融4轮,虎赞科技完成红杉领投3000万美元B轮融资
  2. (jQuery,YUI)哪一个适合我?
  3. nginx 服务器的学习(1)
  4. crf linux使用教程,Linux下CRF++的使用
  5. Js中的数据属性和访问器属性
  6. STM32F407VG uCOS-II2.91 IAR工程 以及uCOS使用库编译的方法
  7. python布尔类型运算_Python bool类型和比较运算符(入门必读)
  8. MyBatis学习笔记(2)-MyBatis入门
  9. 第四季-专题10-字符设备驱动模型
  10. hashmap 和 hashtable 的区别和联系
  11. 微信小程序获取公众号文章列表及显示文章
  12. web切图怎么做_Web前端切图快捷键、技巧和经验
  13. IBM Power小型机用前面板液晶屏查看HMC端口IP
  14. HashMap源码分析与实现
  15. centos php安装 pecl,pecl是什么?如何在centos下安装pecl?
  16. 闲云野鹤:吃鸡(一)之场景制作:使用GPU instancing方式制作刷草插件
  17. 企业成功的秘密:成为独角兽
  18. restapi是什么意思_网上整理的对于Rest和Restful api的理解
  19. java素数对算法_Java版本 质数(也叫素数)算法
  20. 诙谐幽默的个性自我介绍

热门文章

  1. MySQL高级---索引优化分析(Explain性能分析 一)
  2. 【档案专题】一、电子档案
  3. 人大李崇轩:我的生成模型修炼之路丨智源大会嘉宾风采
  4. 计算机毕业设计系列基于JavaWeb的医院挂号预约管理系统
  5. CPU的发展历史和工作原理
  6. 日常记录(关于sessionStorage.setItem)
  7. 关于localstorage.setItem的内容
  8. 手机电子邮件服务器是什么,什么是电子邮件服务器名?在哪找到接收邮件服 – 手机爱问...
  9. matlab 跳转到函数,matlab中fmincon函数如何调用??
  10. 小白学习DirectX11:第一个demo