• 《数据结构学习笔记---第九篇》---循环队列的实现


       文章目录

    1.循环队列的定义

    2.循环队列的判空判满

    3.创建队列并初始化

    4.入队和出队

    5. 返回队尾队首元素

    6.释放循环队列


    1.循环队列的定义

    定义:存储队列元素的表从逻辑上被视为一个环。

           

    我们此次实现的循环队列,采用顺序表

    1. typedef struct {
    2. int*a;
    3. int front;
    4. int rear;
    5. int k;
    6. } MyCircularQueue;

    本质上是一个出入受限的顺序表,那我们是怎么实现他的环状结构的呢?毕竟顺序表是一个线性的结构而不是环状的。

    答  他用取模运算刚好在存储空间上变成了“环状”。

    例如:我们要走一个环状顺序表

    如果我们将rear=1;front=2在逻辑上我们可以正常移动,但其实我们物理存储上的指针已经溢出了,所以我们刚好可以取模来控制指针的移动。

    如果我们尾指针前进一步就可以(Q.rear+1)% k,刚好可以到达front的位置。

    2.循环队列的判空判满

    如图我们可以看到,此时rear==front既可以是判空的条件,也可以是判满的条件,那我们应该怎么区分呢?有三种方法://这里的指针变量会和题目中的不太一样,但是判断逻辑相同

    1.牺牲一个单元来进行区分

    队满:(Q.rear+1)%MaxSize ==Q.front;

    队空:   Q.front==Q.rear

    2.设置一个Size表示队列元素长度来判断。

    队满:Size==MaxSize;

    队空:Size==0

    3.设置一个 tag标记

    tag==0&& Q.front==Q.rear,队空;

    tag==1&& Q.front==Q.rear,队满。

    • isEmpty(): 检查循环队列是否为空。
    • isFull(): 检查循环队列是否已满。

    1. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    2. assert(obj);
    3. if(obj->rear==obj->front )
    4. {
    5. return true;
    6. }
    7. return false ;
    8. }
    9. bool myCircularQueueIsFull(MyCircularQueue* obj) {
    10. assert(obj);
    11. if((obj->rear+1)%(obj->k+1)==obj->front )
    12. {
    13. return true;
    14. }
    15. return false ;
    16. }

    3.创建队列并初始化

    MyCircularQueue(k): 构造器,设置队列长度为 k 

    1. MyCircularQueue* myCircularQueueCreate(int k)
    2. {
    3. MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//创建一个循环的队列结构体指针节点
    4. obj->a=(int*)malloc(sizeof(int)*(k+1)) ;//队列长度为k,但是要多一个空间用来判断空还是满
    5. obj->front=obj->rear=0;
    6. obj->k=k;
    7. return obj;
    8. }

        队列长度为k,但是要多一个空间用来判断空还是满 ,所以我们用的是第一种判空判满策略,牺牲一个存储空间

    4.入队和出队

    入队操作:    obj->a[obj->rear]=value;
                        obj->rear=(obj->rear+1)%(obj->k+1);//  先赋值再移动指针

    出队操作:   obj->front=(obj->front+1)%(obj->k+1);// 直接移动指针

    • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
    • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
    1. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    2. assert(obj);
    3. if (myCircularQueueIsFull(obj))
    4. {
    5. return false;
    6. }
    7. obj->a[obj->rear]=value;
    8. obj->rear=(obj->rear+1)%(obj->k+1);
    9. return true;
    10. }
    11. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    12. assert(obj);
    13. if (myCircularQueueIsEmpty(obj))
    14. {
    15. return false;
    16. }
    17. obj->front=(obj->front+1)%(obj->k+1);
    18. return true;
    19. }

    5. 返回队尾队首元素

    • Front: 从队首获取元素。如果队列为空,返回 -1 。
    • Rear: 获取队尾元素。如果队列为空,返回 -1 。
    1. int myCircularQueueFront(MyCircularQueue* obj) {
    2. assert(obj);
    3. if (myCircularQueueIsEmpty(obj))
    4. {
    5. return -1;
    6. }
    7. return obj->a[obj->front];
    8. }
    9. int myCircularQueueRear(MyCircularQueue* obj) {
    10. assert(obj);
    11. if (myCircularQueueIsEmpty(obj))
    12. {
    13. return -1;
    14. }
    15. else{
    16. int rear=obj->rear==0 ? obj->k : obj->rear-1;
    17. return obj->a[rear];
    18. }
    19. }

    int rear=obj->rear==0 ? obj->k : obj->rear-1;  由于队尾后面还有一个用于判空判满的空间,如果rear刚好指向这片空间,他实际上是指向的真正的队尾下标为k;如果不为0说明他指向的空间为正常的前驱结点。

     6.释放循环队列

     切记:  先释放结构体指针指向的创建的队列所在的空间,再去释放结构体指针的空间。

    1. void myCircularQueueFree(MyCircularQueue* obj) {
    2. free(obj->a);
    3. free(obj);
    4. }
  • 相关阅读:
    SpringCloud基础知识【Feign声明式系统调用】
    思维模型 留白效应
    hudi安装
    R语言dplyr包distinct函数基于dataframe数据中的所有变量移除重复行
    有限元仿真分析误差来源之边界条件,约束和point mass
    NodeRed系列—创建mqtt broker(mqtt服务器),并使用mqttx进行消息发送验证
    网络安全(黑客)-0基础小白自学
    缓冲流(字节缓冲流、字符缓冲流)----Java
    MySQL日志管理、备份与恢复
    Python数据库sqlite3详解
  • 原文地址:https://blog.csdn.net/yl1509797225/article/details/137208447