设计循环队列

目录

题目要求

思路

链表和数组的选择

基本变量的声明

问题:如何判满和判空

回转问题

实现

初始化

判空和判满

读取首尾

出数据和入数据

总代码


https://leetcode.cn/problems/design-circular-queue/

题目要求

class MyCircularQueue {
public:
    MyCircularQueue(int k) {
        
    }
    
    bool enQueue(int value) {
        
    }
    
    bool deQueue() {
        
    }
    
    int Front() {
        
    }
    
    int Rear() {
        
    }
    
    bool isEmpty() {
        
    }
    
    bool isFull() {
        
    }
};

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue* obj = new MyCircularQueue(k);
 * bool param_1 = obj->enQueue(value);
 * bool param_2 = obj->deQueue();
 * int param_3 = obj->Front();
 * int param_4 = obj->Rear();
 * bool param_5 = obj->isEmpty();
 * bool param_6 = obj->isFull();
 */

思路

链表和数组的选择

先读一下题,这个题要求我们实现一个“循环队列”,这个循环队列和普通队列的区别在于

1、队列的长度是一定的

2、队列中的空间是可以被重复利用的

我们这里有两种实现的思路,一种是通过数组,一种是通过链表。

好像乍一看上去是使用链表好做一点

实则不然,如果我们使用链表,链表的结点数量肯定是固定的,这时候,我们想要知道链表是否满了就是一个问题,我们怕不是得将每一个链表节点都安排一个flag来标注这个节点是不是满的,在判空和判满的时候也得将全部的节点都遍历一遍,这实际上是很浪费时间和空间的。

所以我们这里还是使用数组来完成这一道题

基本变量的声明

要实现找到头和尾的效果,我们一定得有两个“指针”(这里其实是数字)分别指向head和tail

这里又有一个问题:我们的tail应该指向那里?是下一个节点还是当前最后一个有效节点

别忘了我们这里使用的是数组,我们如果使用的是指向最后一个有效节点的话,在初始化的时候,我们就得将tail设置为-1了,显然:-1在数组中的使用是有一点难绷的

所以我们这里采用tail设置为最后一个有效元素的下一个元素的方案

我们可以看到在题目中给到的函数中并没有给我们k的接口,我们还是将k作为一个成员变量比较好

 private:
    int _head;
    int _tail;
    int _k;
    int* arr;

问题:如何判满和判空

空的时候自不必说,肯定是head==tail

但是满的情况又该如何判断呢?

此时,tail已经转了一圈回来了,这个队列肯定是满的,但是表现还是tail==head,我们没法区分到底是满的还是空的。

这里有两种方案:

1、引入一个size来记录现在的有效数据个数

2、多开一个“影子节点”,并保持数组中永远有一个节点是没有存数据的

第一种方案是很好实现的,我在此不过多讲述

我们着重讲第二种方案

因为我们数组中永远有一个空间是没有存数据的,只要tail指向的下一个节点是head就可以认为此时队列是满的

如图所示,这种情况就是满的

我们在为队列开辟空间的时候多开辟一个空间

 MyCircularQueue(int k) 
    {
        arr=(int*)malloc(sizeof(int)*(k+1));
        _k=k;
        _head=0;
        _tail=0;   
    }

那我问你:这种情况怎么办

这就引出一个回转问题了

回转问题

我们使用的head和tail在使用的过程中都会有到了结尾的位置的情况,此时如果不回转到开始的位置的话,多少是有一点棘手的。

我们这时只需要在head和tail移动时%一个(k+1)即可

因为,当移动后的数字小于(k+1)时,%(k+1)也没有什么影响

当移动后的数字大于等于(k+1)时,%(k+1)就可以将数字返回到开头的位置,从而实现数字的回转

实现

初始化

 MyCircularQueue(int k) 
    {
        arr=(int*)malloc(sizeof(int)*(k+1));
        _k=k;
        _head=0;
        _tail=0;   
    }

判空和判满

bool isEmpty() {
        return _head==_tail;
    }
    
    bool isFull() {
        return (_tail+1)%(_k+1)==_head;
    }

读取首尾

 int Front() {
        if(isEmpty())
        return -1;
        else
        {
            return arr[_head];
        }
    }
    
    int Rear() {
        if(isEmpty())
        return -1;
        else
        {
            return arr[(_tail+_k+1-1)%(_k+1)];
            //这里是一个非常有意思的小点
        }
    }

这里有一个需要注意的小点:

return arr[(_tail+_k+1-1)%(_k+1)];

我们的_tail指向的是最后一个有效数字的下一个节点,我们返回的一定是他的上一个节点

这里(_tail-1+k+1)%(k+1)在tail大于0的时候都是不会产生什么影响的(两个(k+1)直接约了),但是在tail等于零的时候用处就大了,可以实现跳到上一个有效数字的效果

出数据和入数据

 bool enQueue(int value) {
        if(isFull())
        return false;
        else
        {
            arr[_tail]=value;
            _tail=(_tail+1)%(_k+1);
            return true;
        }
    }
    
    bool deQueue() 
    {
        if(isEmpty())
        return false;
        else
        {
            _head=(_head+1)%(_k+1);
            return true;
        }   
    }

总代码

class MyCircularQueue {
    private:
    int _head;
    int _tail;
    int _k;
    int* arr;
public:
    MyCircularQueue(int k) 
    {
        arr=(int*)malloc(sizeof(int)*(k+1));
        _k=k;
        _head=0;
        _tail=0;   
    }
    
    bool enQueue(int value) {
        if(isFull())
        return false;
        else
        {
            arr[_tail]=value;
            _tail=(_tail+1)%(_k+1);
            return true;
        }
    }
    
    bool deQueue() 
    {
        if(isEmpty())
        return false;
        else
        {
            _head=(_head+1)%(_k+1);
            return true;
        }   
    }
    
    int Front() {
        if(isEmpty())
        return -1;
        else
        {
            return arr[_head];
        }
    }
    
    int Rear() {
        if(isEmpty())
        return -1;
        else
        {
            return arr[(_tail+_k+1-1)%(_k+1)];
            //这里是一个非常有意思的小点
        }
    }
    
    bool isEmpty() {
        return _head==_tail;
    }
    
    bool isFull() {
        return (_tail+1)%(_k+1)==_head;
    }
};

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue* obj = new MyCircularQueue(k);
 * bool param_1 = obj->enQueue(value);
 * bool param_2 = obj->deQueue();
 * int param_3 = obj->Front();
 * int param_4 = obj->Rear();
 * bool param_5 = obj->isEmpty();
 * bool param_6 = obj->isFull();
 */

在 Java 中设计循环队列可以通过数组来实现。循环队列是一种线性数据结构,它的操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。以下是一个使用 Java 实现循环队列的示例代码: ```java class MyCircularQueue { private int[] queue; private int front; private int rear; private int size; // 初始化队列 public MyCircularQueue(int k) { queue = new int[k]; front = 0; rear = -1; size = 0; } // 入队操作 public boolean enQueue(int value) { if (isFull()) { return false; } rear = (rear + 1) % queue.length; queue[rear] = value; size++; return true; } // 出队操作 public boolean deQueue() { if (isEmpty()) { return false; } front = (front + 1) % queue.length; size--; return true; } // 获取队首元素 public int Front() { if (isEmpty()) { return -1; } return queue[front]; } // 获取队尾元素 public int Rear() { if (isEmpty()) { return -1; } return queue[rear]; } // 判断队列是否为空 public boolean isEmpty() { return size == 0; } // 判断队列是否已满 public boolean isFull() { return size == queue.length; } } ``` 可以使用以下方式测试这个循环队列: ```java public class Main { public static void main(String[] args) { MyCircularQueue circularQueue = new MyCircularQueue(3); System.out.println(circularQueue.enQueue(1)); // 返回 true System.out.println(circularQueue.enQueue(2)); // 返回 true System.out.println(circularQueue.enQueue(3)); // 返回 true System.out.println(circularQueue.enQueue(4)); // 返回 false,队列已满 System.out.println(circularQueue.Rear()); // 返回 3 System.out.println(circularQueue.isFull()); // 返回 true System.out.println(circularQueue.deQueue()); // 返回 true System.out.println(circularQueue.enQueue(4)); // 返回 true System.out.println(circularQueue.Rear()); // 返回 4 } } ```
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值