首页 > 其他分享 >[数据结构] 队列

[数据结构] 队列

时间:2024-02-07 13:22:05浏览次数:37  
标签:队列 MaxSize front 数据结构 LinkNode rear 指针

队列的基本概念

队列(Queue),是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。向队列中插入元素称为入队,删除元素称为出队。其操作特性是先进先出

image

队列的常见操作:

函数名 功能
InitQueue(*Q) 初始化队列,构造一个空队列Q
QueueEmpty(Q) 判断队列空
EnQueue(*Q, x) 入队,若队列未满,将x加入
DeQueue(*Q, *x) 出队,若队列非空,删除队头元素
GetHead(*Q, *x) 读队头元素

队列的顺序存储结构

队列的顺序存储

队列的顺序实现是分配一块连续的存储单元存放队列中的元素,并设置两个指针:队头指针front队尾指针rear

存储类型结构体如下:

#define MaxSize 50
typedef struct {
    int data[MaxSize];
    int front, rear;
}Queue;

初始时:Q->front = Q->rear = 0;(如下图1)

进队:队列不满时,先送值到队尾元素,再将队尾指针加一;(如下图2)

出队:队列非空时,先取队头元素值,再将队头指针加一。(如下图3)

image
image
image

我们能不能使用Q->rear == MaxSize作为队列满的条件呢?

答案是:不能!!

如下图4所示,队列中仅有一个元素时,仍满足该条件,但此时队列出现上溢出

image

这种溢出不是真正的溢出,在data数组中仍然存在很多可以存放元素的空位置,是假溢出

循环队列

为了解决上文提到的假溢出,我们引入了循环队列——把顺序队列的表从逻辑上视作一个环,当队首指针Q->front = MaxSize - 1后,再向前一个位置就自动回到0。

一些运算

初始时:Q->front = Q->rear = 0;

队首指针进1: Q->front = (Q->front + 1) % MaxSize;

队尾指针进1: Q->rear = (Q->rear + 1) % MaxSize;

队列长度: (Q->rear + MaxSize - Q->front) % MaxSize;

判空

显然队空的条件是Q->front == Q->rear

那么,当入队元素的速度快于出队元素的速度,会发生什么呢?

===》队尾指针会很快赶上队首指针,如下图d1所示。

为了区分是队空还是队满,有三种处理方式:

  • 如下图d2,牺牲一个单元来区分队空和队满,入队时少用一个队列单元,约定以”队头指针在队尾指针的下一个位置作为队满的标志“

    队满条件:(Q->rear + 1) % MaxSize == Q->front;

    队空条件: Q->front == Q->rear;

    队列元素个数: (Q->rear - Q->front + MaxSize) % MaxSize

  • 类型中增设一个size数据成员,用于表示元素个数。删除成功size减一,插入成功size加一。队空时,Q->size == 0;队满时, Q->size == MaxSize。

  • 类型中增设一个tag数据成员,以区分是队空开始队满。删除成功置tag=0,若导致 Q->front == Q->rear,则队空;插入成功置1,若导致 Q->front == Q->rear,则队满。

接下来我们来看图,图示循环队列出入队:

image

代码

初始化
void InitQueue(Queue *Q) {
    Q->rear = Q->front = 0;
}
判空
bool IsEmpty(Queue *Q) {
	return Q->rear == Q->front;
}
入队
void EnQueue(Queue *Q, int x) {
    if((Q->rear + 1) % MaxSize == Q->front)
        return ;
    Q->data[Q.rear] = x;
    Q->dear = (Q->dear + 1) % MaxSize;
}
出队
void DeQueue(Queue *Q, int *x) {
    if(IsEmpty(Q))
        return ;
    *e = Q->data[Q->front];
    Q->front = (Q->front + 1) % MaxSize;
}

队列的链式存储结构

队列的链式表示称为链队列,实际上是一个同时又队头指针和队尾指针的单链表。头指针指向队头节点,尾指针指向队尾节点。

结构体:

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

image
image
image
image
以上图源来自我的大佬同学,作者:Amαdeus,出处:https://www.cnblogs.com/MAKISE004/p/17063234.html

代码

初始化

void InitQUeue(LinkQueue *Q) {
    Q->front = Q->rear = (LinkNode *)malloc(sizeof(LinkNode));
    Q->front->next = NULL;
}

判空

bool IsEmpty(LinkQueue *Q) {
    return Q->front == Q->rear;
}

入队

void EnQueue(LinkQueue *Q, int x) {
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
    s->data = x;
    s->next = NULL;
    Q->rear->next = s;
    Q->rear = s;
}

出队

void DeQueue(LinkQueue *Q, int *x) {
    if(IsEmpty(Q))
        return ;
    LinkNode *m = Q->front->next;
    x = p->data;
    Q->front->next = m->next;
    if(Q->rear == m)
        Q->rear = Q->front;
    free(m);
}

写在最后

画图花了好长时间,果然昨天先写数组是一种正确的选择(经过一学期的最优化学习,我的LaTeX和markdown功底已经突飞猛进了(我的意思不是这学期的课只学会了LaTeX),敲代码总比画图快)。好了,开玩笑归开玩笑,还是希望学有所成的!

标签:队列,MaxSize,front,数据结构,LinkNode,rear,指针
From: https://www.cnblogs.com/wanyy-home/p/18010843

相关文章

  • 单调队列优化DP&斜率优化&四边形不等式
    在本文中,我们将通过一道题来浅谈DP优化三大妈。P3195[HNOI2008]玩具装箱-洛谷|计算机科学教育新生态(luogu.com.cn)对于这种类型的题目,我们一般可以转化为如下形式:那么,$val(i,j)$又通常分为两种情况:其值仅与$i,j$中的一个有关。其值与$i,j$两者都有关。单调队列......
  • 并发容器【ConcurentHashMap、CopyOnWriteArrayList、阻塞队列、ArrayBlockingQueue】
    (并发容器)转自极客时间什么是并发容器?在JUC包中,有一大部分是关于并发容器的,如ConcurrentHashMap,ConcurrentSkipListMap,CopyOnWriteArrayList及阻塞队列。这里将介绍使用频率、面试中出现频繁的最高的ConcurrentHashMap和阻塞队列。注意:这里说到的容器概念,相当于我们理解中......
  • 单调队列优化DP
    单调队列在DP中的基本应用,是对这样一类DP状态转移方程进行优化:\(dp[i]=\min\{dp[j]+a[i]+b[j]\},L(i)\lej\leR(i)\)。方程中的\(\min\)也可以是\(\max\),方程的特点是其中关于\(i\)的项\(a[i]\)和关于\(j\)的项\(b[j]\)是独立的,而\(j\)被限制在窗口......
  • [数据结构] 数组与特殊矩阵
    写在前面偷懒,先写了数组,列表要画图,所以今天就先不写了数组的定义数组是由n个相同类型的数据元素构成的有限序列。每个数据元素被称为一个数组元素,每个元素在n个线性关系中的序号称为该元素的下标,下标的取值范围称为数组的维界。数组与线性表的关系:数组是线性表的推广。一维数......
  • 单调队列及单调队列优化DP
    首先是单调队列: 其实单调队列就是一种队列内的元素有单调性(单调递增或者单调递减)的队列,答案(也就是最优解)就存在队首,而队尾则是最后进队的元素。因为其单调性所以经常会被用来维护区间最值或者降低$DP$的维数已达到降维来减少空间及时间的目的。类似于滑动窗口等,单调队列具有......
  • Java 中的哈希表数据结构
    哈希表数据结构HashMap集合:在JDK8之后,如果单向链表中的元素超过8个,单向链表数据结构就会变成红黑树数据结构,当红黑树上的节点数量小于6时,会重新把红黑树变成单向链表数据结构。HashMap集合底层是哈希表/散列表的数据结构哈希表是一个怎样的数据结构?哈希表是一个数组和单向链......
  • [数据结构] 栈
    栈的定义及特点栈(Stack)是只允许在一端进行插入或删除操作的线性表,如图所示:栈顶(top):线性表允许进行插入、删除的一端;栈底(bottom):不允许进行插入和删除的一端;空栈:不含任何元素的空表。如上图所示,设某个栈\(S=(a_1,a_2,a_3,a_4,a_5)\),则\(a_1\)为栈底元素,\(a_5\)为栈顶元素。......
  • 经典数据结构题目-图
    图200.岛屿数量思路遍历二维数组,遇到等于1的进行计算。同时修改同岛的位置为0,避免重复计算遍历同岛的位置,可以采用dfs深度优先搜索代码char[][]g;publicintnumIslands(char[][]grid){intsum=0;g=grid;for(inti=0;......
  • 有关各种数据结构模板
    FHQ-Treap模板题-普通平衡树#include<bits/stdc++.h>#definelstr[u].l#definerstr[u].rusingnamespacestd;constintN=3e5+10;structNode{intl,r;intkey,v;intsize;}tr[N];introot,idx;intn,m;voidpushup(intu){tr[u].size......
  • 2.1 不会有人数据结构比我还菜吧?
    记录三道自己菜死了的与根号有关的题。其中每道题都有polylog解法。题目名称太长了,就不放了。CF1017GTheTree根号做法:考虑操作分块,然后建虚树。建出虚树之后我们就发现很好处理了。同样的,处理每一个块结束后的真实形态,也可以借助这个虚树。总的来说,需要暴力维护一下每个虚......