循环队列的几种实现方式

182 阅读3分钟

​ 本文主要介绍, 基于数组来实现循环队列的几种方式, 要使用数组来实现循环队列的关键点就在于, 如何解决数组越界的问题以及如何判断数组是满还是空

下面提供了三种解决方案:

  1. 使用 usedSize
  2. 使用 标志位
  3. 空出一个位置

下面就具体来介绍下这三种方法~

方式一

最简单的办法就是使用 usedSize 来记录当前数组中有几个有效元素即可

  1. usedSize == 0 是则表示当前数组为空
  2. usedSize == 数组的长度 则表示当前数组满了

图解

此时的 usedSize == 0 队列为空

入队操作

出队操作

下图的 usedSize == 4 说明队列已满

代码

/**
 * @Author XUE_957
 * @Date 2022/6/12 21:08
 * @Version 2022.1.1
 */
public class MyCircularQueue1 {

    private int[] queue;
    // usedSize 表示有效元素个数
    private int usedSize;
    // 队列头
    private int head;
    // 队列尾
    private int tail;

    public MyCircularQueue1(int k) {
        // 调用构造方法时初始化数组
        this.queue = new int[k];
    }

    public boolean enQueue(int value) {
        if (isFull()) {
            // 这里不考虑扩容问题
            return false;
        }
        // 这种写法会导致数组越界,所以需要取余数
        //queue[tail++] = value;
        queue[tail] = value;
        tail = (tail + 1) % queue.length;
        usedSize++;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        head = (head + 1) % queue.length;
        usedSize--;
        return true;
    }

    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return queue[head];
    }

    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        if (tail == 0) {
            // 因为每次入队操作, tail 都会加 1, 因此这里要获取队尾元素要减 1
            // 而且这里要考虑数组越界的问题,这里只需针对 0 下标处理一下即可~
            return queue[queue.length - 1];
        }
        return queue[tail - 1];
    }

    public boolean isEmpty() {
        return usedSize == 0;
    }

    public boolean isFull() {
        return usedSize == queue.length;
    }

}

方式二

使用一个标记 flag 来判断当前队列是空还是满

  1. 如果 flag == false 则说明队列为空
  2. 如果 flag == true 则说明队列已满
  3. 每次的入队操作都将 flag 置为 true , 每次的出队操作都将 flag 置为 false

图解

空的情况:

满的情况:

代码

/**
 * @Author XUE_957
 * @Date 2022/6/12 22:01
 * @Version 2022.1.1
 */
public class MyCircularQueue2 {

    private int[] queue;
    // 队列头
    private int head;
    // 队列尾
    private int tail;
    // 设立标记位,默认是 false
    private boolean flag;

    public MyCircularQueue2(int k) {
        // 调用构造方法时初始化数组
        this.queue = new int[k];
    }

    public boolean enQueue(int value) {
        if (isFull()) {
            // 这里不考虑扩容问题
            return false;
        }
         flag = true;
        // 这种写法会导致数组越界,所以需要取余数
        //queue[tail++] = value;
        queue[tail] = value;
        tail = (tail + 1) % queue.length;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        flag = false;
        head = (head + 1) % queue.length;
        return true;
    }

    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return queue[head];
    }

    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        if (tail == 0) {
            // 因为每次入队操作, tail 都会加 1, 因此这里要获取队尾元素要减 1
            // 而且这里要考虑数组越界的问题,这里只需针对 0 下标处理一下即可~
            return queue[queue.length - 1];
        }
        return queue[tail - 1];
    }

    public boolean isEmpty() {
        return head == tail && flag == false;
    }

    public boolean isFull() {
        return head == tail && flag == true;
    }

}

方式三

浪费一个格子, 用来判断队列是空还是满

  1. 如果 tail + 1 == head 则说明队列满了
  2. 如果 tail == head 则说明队列为空

题目链接: 设计一个循环队列

注意:

  • 跑 oj 的时候, 在构造函数这里需要将 k 写成 k+1 因为浪费了一个格子~

图解

空的情况:

满的情况:

代码

/**
 * @Author XUE_957
 * @Date 2022/6/12 22:18
 * @Version 2022.1.1
 */
public class MyCircularQueue3 {

    private int[] queue;
    // 队列头
    private int head;
    // 队列尾
    private int tail;

    public MyCircularQueue3(int k) {
        // 调用构造方法时初始化数组
        this.queue = new int[k];
    }

    public boolean enQueue(int value) {
        if (isFull()) {
            // 这里不考虑扩容问题
            return false;
        }
        // 这种写法会导致数组越界,所以需要取余数
        //queue[tail++] = value;
        queue[tail] = value;
        tail = (tail + 1) % queue.length;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        head = (head + 1) % queue.length;
        return true;
    }

    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return queue[head];
    }

    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        if (tail == 0) {
            // 因为每次入队操作, tail 都会加 1, 因此这里要获取队尾元素要减 1
            // 而且这里要考虑数组越界的问题,这里只需针对 0 下标处理一下即可~
            return queue[queue.length - 1];
        }
        return queue[tail - 1];
    }

    public boolean isEmpty() {
        return head == tail;
    }

    public boolean isFull() {
        return (tail + 1) % queue.length == head;
    }

}