[C/C++]数据结构 循环队列

前言:

队列是一种具有先进先出特性的结构,但是当数据出队列以后,前面的空间就无法再次利用了,循环队列就可以解决这个问题

一:概念及结构:

1.循环队列概念

循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环.

2.循环队列结构

循环队列可以使用数组实现也可以使用链表实现,但是还是建议使用数组实现.另外在给数组开辟空间时,要比队列实际长度多一个,如果开辟空间和队列存储数据的长度一样的话,在判断队列为空和队列为满时,两者都为 front==rear 会出现一样的情况导致无法判断,如

所以必须多开辟一个空间,这个空间不存储数据,这样就可以区分出两种情况

结构定义:

front用于维护队头,指向队头元素位置,back用于维护队尾,总是指向队尾元素的下一个位置,k表示队列实际存数据的长度

ps:循环队列的长度是固定的

复制代码
typedef struct {
    int *a;
    int front; 
    int back;
    int k;  //队列大小
} MyCircularQueue;

二:功能实现

1.入队:

复制代码
    首先要判断队列是否已满,再进行入队的操作,入队操作需要考虑索引循环的问题,当索引越界,需要让它变成最小值

如果入队是这种情况,直接在队尾处插入数据,back++即可

但是如果碰到这种情况,back就不能简单加一就完事了了,还需要将back重新指向数组刚开始的空间,不然就体现不出循环的特点了

所以在队尾插入数据back++后,进行 back=(back)%(k+1) 就可以使back重新指向数组起始位置(这里要注意的是,我定义的k是队列不带多开辟的那一个空间的长度)

复制代码
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
   if(myCircularQueueIsFull(obj))//入队前先判断是否还有空间
   return false;

   obj->a[obj->back]=value;
   obj->back++;
   obj->back%=(obj->k+1);
   return true;
}

2.出队:

首先判断队列是否为空,在进行出队操作,出队也需要考虑front的索引问题

复制代码
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    return false;

    obj->front++;
    obj->front%=(obj->k+1);
    return true;
}

3.取队头元素

front指向的就是队头元素

复制代码
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    return -1;
    return obj->a[obj->front];
}

4.取队尾元素

由于back始终指向队尾的下一个元素,在一般情况下直接返回back-1所指向的元素即可,但是有一种特殊情况,如果此时back指向的是数组起始位置的话,访问back-1所指向的元素就会越界,所以这里也涉及循环的问题

方法一: 把特殊情况分离出来

复制代码
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    return -1;

    if(obj->back==0)
    return obj->a[obj->k];
    else
    return obj->a[obj->back-1];
}

方法二: 两种情况统一处理

复制代码
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    return -1;

    return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)];
}

5.判空

复制代码
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->back;
}

6.判满

复制代码
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->back+1)%(obj->k+1)==obj->front;
}

7.销毁队列

复制代码
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    obj->front=obj->back=0;
    obj->k=0;
}

8.求队列当前元素个数

当back在front之后时,back-front就可获得当前队列元素个数,但是当back在front前面时,back+(k+1)

可以让back指向不处理循环问题本身应该指向的位置

复制代码
int myCircularQueueSize(MyCircularQueue* obj) {
    return (obj->back+(k+1)-obj->front)%(k+1);
}
相关推荐
在下雨5991 小时前
项目讲解1
开发语言·数据结构·c++·算法·单例模式
今后1232 小时前
【数据结构】栈详解
数据结构·
songx_994 小时前
leetcode10(跳跃游戏 II)
数据结构·算法·leetcode
先做个垃圾出来………5 小时前
差分数组(Difference Array)
java·数据结构·算法
dragoooon346 小时前
[数据结构——lesson5.1链表的应用]
数据结构·链表
神里流~霜灭8 小时前
(C++)数据结构初阶(顺序表的实现)
linux·c语言·数据结构·c++·算法·顺序表·单链表
要开心吖ZSH9 小时前
软件设计师备考-(十六)数据结构及算法应用(重要)
java·数据结构·算法·软考·软件设计师
zhong liu bin11 小时前
MySQL数据库面试题整理
数据结构·数据库·mysql
bkspiderx21 小时前
C++经典的数据结构与算法之经典算法思想:贪心算法(Greedy)
数据结构·c++·算法·贪心算法
中华小当家呐1 天前
算法之常见八大排序
数据结构·算法·排序算法