【数据结构】循环队列

这篇具有很好参考价值的文章主要介绍了【数据结构】循环队列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。
🐌 个人主页:蜗牛牛啊
🔥 系列专栏:🛹数据结构、🛴C++
📕 学习格言:博观而约取,厚积而薄发
🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与诸君一同成长! 🌹


循环队列

队列又称为"先进先出(FIFO)"线性表:插入操作只能在队尾进行,删除操作只能在队首进行。

而循环队列是队列的一种特殊形式,循环队列(也被称为环形队列)是一种线性数据结构,其操作表现基于先进先出原则,并且队尾被连接在队首之后以形成一个循环。

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

循环队列固定大小,空间能够重复利用。

循环队列可以用数组或者链表实现,那下面我们来分析一下哪种方式更好:

当我们想使用链表实现时,假设我们想要开辟的队列长度为k = 4;front表示队头指针,rear表示队尾指针:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

由上图可知,当rear和front 都指向同一个位置时队列为空。

插入一个数据之后:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

rear向后移动,此时我们知道rear指向的位置是最后一个数据的下一个位置。

那当我们一直插入数据,直至队列为满:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

但是当队列满的时候,我们发现rear 和 front也指向同一个位置。那当队列为空和队列为满的时候,rear和front都指向同一个位置,我们怎么判断此时队列是满还是空?

通过判断front和rear是否为空可以吗?不行,front和rear刚开始都会指向节点,不会为空。

解决方法:1.增加一个size或者flag解决;2.增加一个空余节点。

我们可以多开一个节点,不是哨兵位节点,和头节点一样,此时:

队列为空时:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

队列满时:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

满的时候不能再插入数据,现在假设我们删除两个数据:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

再插入两个数据:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

如果我们不断pop,当rear和front指向同一个位置时,队列就变为空了。

那我们可以用单链表来实现循环队列吗?使用链表最不好解决的一个问题就是取队尾数据,单链表不容易取当前节点的前一个结点数据,我们可以通过增加一个指针rear->prev指向前一个结点。

当我们想使用数组实现时,假设我们想要开辟的队列长度为k = 4;front表示队头的下标,rear表示队尾的下标:

使用数组实现同样也面临着front和rear相等时无法判断队列是空还是满的问题,所以我们也可以通过增加一个size或者多开辟一个空间来解决该问题。

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

当我们插入一个数据后发现rear指向队尾数据的下一个位置,在链表中存在的找队尾问题,在这里找队尾数据变得简单。

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

当队列为空时下标front == rear:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

当队列满时可以通过公式(rear + 1) % (k + 1) == front来判断队列是否满了:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

插入数据在rear++之后可以通过rear % (k + 1)来计算插入数据之后rear的下标:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

删除数据可以在front++之后通过front % (k + 1)得出删除数据之后front的下标:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

练习:现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为 ?

A (rear - front + N) % N + 1
B (rear - front + N) % N
C (rear - front) % (N + 1)
D (rear - front + N) % (N - 1)

假设队列如下图所示:

【数据结构】循环队列,数据结构,数据结构,后端,开发语言

队内有效长度为2,两个指针相减得到的是两个指针之间的元素个数(rear - front) = 2;上面的四个选项中代入计算只有B符合要求。

设计循环队列

题目:设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

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

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

提示:

  • 所有的值都在 0 至 1000 的范围内;
  • 操作数将在 1 至 1000 的范围内;
  • 请不要使用内置的队列库。

思路:

可以使用数组的方式实现循环队列,在结构体中定义一个一级指针int* arr、队头下标front、队尾下标rear以及要开辟的队列长度k;然后通过开辟空间及上面关于循环队列的知识完成循环队列的设计。

注:下面提供的代码第一个是通过if来计算插入时rear下标和删除时front下标的,第二个是通过公式计算的。

代码1:

typedef struct {
    int* arr; //用来指向空间的指针
    int front;//队头下标
    int rear;//队尾下标
    int k;//队列长度
} MyCircularQueue;

构造器,设置队列长度为 k
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* r = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//申请一个结构体指针
    int* tmp = (int*)malloc(sizeof(int) * (k + 1));//多开一个空间
    if(tmp == NULL)
    {
        perror("malloc");
        exit(0);
    }
    r->arr = tmp;//给指针赋值
    r->front = 0;//设置队头下标
    r->rear = 0;//设置队尾下标
    r->k = k;//队列长度
    return r;
}

//检查循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if(obj->rear == obj->front)//相等时为空
        return true;
    return false;
}
// 检查循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if((obj->rear + 1)%( obj->k + 1) == obj->front)
        return true;
    return false;
}
//向循环队列插入一个元素。如果成功插入则返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))//队列满时不能再插入
        return false;
    obj->arr[obj->rear++] = value;//插入数据
    if(obj->rear > obj->k)//计算rear下标
    {
        obj->rear = 0;
    }
    return true;
}
//从循环队列中删除一个元素。如果成功删除则返回真
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))//为空时不能删除
        return false;
    obj->front++;
    if(obj->front > obj->k)//计算front下标
    {
        obj->front = 0;
    }
    return true;

}
//从队首获取元素。如果队列为空,返回 -1
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->arr[obj->front];
}
//获取队尾元素。如果队列为空,返回 -1
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    int n = obj->rear-1;
    if(n < 0)
    {
        n = obj->k;
    }
    return obj->arr[n];
}
//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

代码2:文章来源地址https://www.toymoban.com/news/detail-533210.html

typedef struct {
    int* arr; //用来指向空间的指针
    int front;//队头下标
    int rear;//队尾下标
    int k;//队列长度
} MyCircularQueue;
//构造器,设置队列长度为 k 。
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//申请一个结构体指针
    obj->arr=(int*)malloc(sizeof(int)*(k+1));//开辟k+1个int空间用来存储数据,要多开辟一个
    obj->k=k;//队列长度
    obj->front = obj->rear = 0;
    return obj;
}
//检查循环队列是否为空。
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    return obj->front == obj->rear; //相等时为空
}
// 检查循环队列是否已满。
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    assert(obj);
    return ((obj->rear+1)%(obj->k+1) == obj->front);
}

//向循环队列插入一个元素。如果成功插入则返回真。
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    assert(obj);
    if(myCircularQueueIsFull(obj))//队列满时不能再插入
        return false;
    obj->arr[obj->rear++] = value;//插入数据
    obj->rear = obj->rear%(obj->k+1);//计算rear下标
    return true;
}
//从循环队列中删除一个元素。如果成功删除则返回真。
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    assert(obj);
    if(myCircularQueueIsEmpty(obj))//为空时不能删除
        return false;
    obj->front++;
    obj->front = obj->front % (obj->k+1);//计算front下标
    return true;
}
//从队首获取元素。如果队列为空,返回 -1 。
int myCircularQueueFront(MyCircularQueue* obj) {
    assert(obj);
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->arr[obj->front];
}
//获取队尾元素。如果队列为空,返回 -1 。
int myCircularQueueRear(MyCircularQueue* obj) {
    assert(obj);
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->arr[(obj->rear+obj->k)%(obj->k+1)];
} 

//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

到了这里,关于【数据结构】循环队列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构--队列与循环队列

            队列是什么,先联想一下队,排队先来的人排前面先出,后来的人排后面后出;队列的性质也一样,先进队列的数据先出,后进队列的后出;就像图一的样子:  图1         如图1,1号元素是最先进的,开始出队时,那么他就是最先出的,然后12进队,就应该排在最

    2024年02月10日
    浏览(42)
  • 【数据结构和算法】--队列的特殊结构-循环队列

    循环队列是队列的一种特殊结构,它的 长度是固定的 k ,同样是 先进先出 ,理论结构是 首尾相连的环形循环结构 。其理论结构大致如下: 具体结构描述可以参考 LeetCode : 622. 设计循环队列的题目要求,大致如下: 设计你的循环队列实现。 循环队列是一种 线性数据结构 ,

    2024年02月04日
    浏览(49)
  • 数据结构:循环队列的实现(leetcode622.设计循环队列)

      目录 一.循环队列简单介绍 二.用静态数组实现循环队列 1.数组循环队列结构设计 2.数组循环队列的堆区内存申请接口  3.数据出队和入队的接口实现 4.其他操作接口 5.数组循环队列的实现代码总览  三.静态单向循环链表实现循环队列  1.链表循环队列的结构设计 2.创建静态

    2024年02月03日
    浏览(45)
  • 【数据结构】循环队列

    🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。 🐌 个人主页:蜗牛牛啊 🔥 系列专栏:🛹数据结构、🛴C++ 📕 学习格言:博观而约取,厚积而薄发 🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与

    2024年02月12日
    浏览(43)
  • 数据结构--循环队列、链队

    //循环队列数据结构 typedef struct { QElemType data[MaxQSize];//数据域 int front,rear; //队头队尾指针 }SqQueue; //链队结点数据结构 typedef struct QNode { int data;//数据域 struct QNode* next;//指针域 }QNode, * QueuePtr; typedef struct { struct QNode* front, * rear;//rear指针指向队尾 用于入队 front指针指向队头 用于

    2024年02月15日
    浏览(42)
  • 数据结构——循环队列详解

    目录 一、循环队列的定义 二、 循环队列的基本操作 三、循环队列的实现  1、循环队列的定义 2、循环队列的初始化  3、循环队列出队  4、循环队列入队  5、队列判空 6、 队列判满 7、取队头元素 8、输出队列  9、求队列长度  四、完整代码  五、小结  六、参考文献 一、

    2024年02月04日
    浏览(44)
  • 数据结构——循环队列的实现

    hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥 个人主页:大耳朵土土垚的博客 💥 所属专栏:数据结构学习笔记 💥对于数据结构顺序表、链表、堆有疑问的都可以在上面数据结构的专栏进行学习哦~ 有问题可以写在评论区或者私信

    2024年03月24日
    浏览(42)
  • 九、数据结构——顺序队列中的循环队列

    一、循环队列的定义 二、循环队列的实现 三、循环队列的基本操作 ①初始化 ②判空 ③判满 ④入队 ⑤出队 ⑥获取长度 ⑦打印 四、循环队列的应用 五、全部代码 在数据结构中,队列(Queue)是一种常见的线性数据结构,遵循先进先出(First In First Out,FIFO)的原则。循环队

    2024年02月15日
    浏览(50)
  • 数据结构第九弹---循环队列

    顺序队列在使用过程中容易出现虚假的满状态, 为了解决这个问题,就产生了一个较巧妙的方法,将顺序队列臆造为一个环状的空间,称之为循环队列。循环队列中指针和队列元素之间的关系不变,我们只需要利用模运算就可以很容易实现指针的循环移动。但是循环队列中存

    2024年01月16日
    浏览(40)
  • 数据结构OJ:设计循环队列

    本题为LeetCode上的经典题目,题目要求我们设计一种循环队列,满足FIFO原则且队尾被连接在队首之后。 题目中介绍循环队列的好处是可以重复利用空间,所以我们很容易想到在初始化时即开辟指定大小的空间,之后便不需要再开辟空间,只需后续销毁即可。 首先我们要选择

    2024年04月17日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包