欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据结构与算法之环形队列(以int数组为例,不包含扩容)

程序员文章站 2022-03-05 12:49:18
...
废话补不多说了, 环形队列最难理解的部分就是取模部分, 可以先看一下这个链接的大佬的讲解:
https://juejin.im/post/5c95d2515188252dab3ebfc5
如果上面这个链接的内容看懂了, 那本章的内容就不用看了, 就只当我做一个学习记录就好了:

// 代码部分
import java.util.Arrays;

public class CircleArrayQueue2 {
    private int front;
    private int tail;
    private final int capacity;
    private final int[] queue;

    public CircleArrayQueue2(int capacity) {
        this.capacity = capacity;
        queue = new int[capacity];
    }

    // 判断环形队列是否为空
    public boolean isEmpty() {
        return front == tail;
    }

    // 判断环形队列是否已满
    public boolean isFull() {
        return (tail + 1) % capacity == front;
    }

    // 存
    public void put(int n) {
        if (isFull()) {
            throw new IllegalArgumentException("queue is full !");
        }
        queue[tail] = n;
        tail = (tail + 1) % capacity;
    }

    // 取
    public int get() {
        if (isEmpty()) {
            throw new IllegalArgumentException("queue is empty !");
        }
        int n = queue[front];
        queue[front] = 0;// 此处的目的是模仿讲引用置为null的操作
        front = (front + 1) % capacity;
        return n;
    }

    // 队首
    public int catHead() {
        if (isEmpty()) {
            throw new IllegalArgumentException("queue is empty !");
        }
        return queue[front];
    }

    @Override
    public String toString() {
        return "CircleArrayQueue2{" +
                "front=" + front +
                ", tail=" + tail +
                ", capacity=" + capacity +
                ", queue=[队首]" + Arrays.toString(queue) +
                "[队尾], 队首元素: " + catHead() + "}";
    }
}

// 测试类
public class CircleArrayQueueTest2 {
    public static void main(String[] args) {
        CircleArrayQueue2 circleArrayQueue2 = new CircleArrayQueue2(8);
        for (int i = 1; i < 8; i++) {
            circleArrayQueue2.put(i);
        }
        System.out.println(circleArrayQueue2);
        circleArrayQueue2.get();
        System.out.println(circleArrayQueue2);
        circleArrayQueue2.get();
        System.out.println(circleArrayQueue2);
        circleArrayQueue2.put(8);
        System.out.println(circleArrayQueue2);
        circleArrayQueue2.put(9);
        System.out.println(circleArrayQueue2);
        circleArrayQueue2.put(10);
        System.out.println(circleArrayQueue2);
    }
}
// 测试结果
CircleArrayQueue2{front=0, tail=7, capacity=8, queue=[队首][1, 2, 3, 4, 5, 6, 7, 0][队尾], 队首元素: 1}
CircleArrayQueue2{front=1, tail=7, capacity=8, queue=[队首][0, 2, 3, 4, 5, 6, 7, 0][队尾], 队首元素: 2}
CircleArrayQueue2{front=2, tail=7, capacity=8, queue=[队首][0, 0, 3, 4, 5, 6, 7, 0][队尾], 队首元素: 3}
CircleArrayQueue2{front=2, tail=0, capacity=8, queue=[队首][0, 0, 3, 4, 5, 6, 7, 8][队尾], 队首元素: 3}
CircleArrayQueue2{front=2, tail=1, capacity=8, queue=[队首][9, 0, 3, 4, 5, 6, 7, 8][队尾], 队首元素: 3}
Exception in thread "main" java.lang.IllegalArgumentException: queue is full !
at com.sgu.data.structure.date_5_23.array.arrayqueue2.CircleArrayQueue2.put(CircleArrayQueue2.java:29)
at com.sgu.data.structure.date_5_23.array.arrayqueue2.CircleArrayQueueTest2.main(CircleArrayQueueTest2.java:18)

Process finished with exit code 1

// 分析

(tail + 1)% capacity :

我上面举的例子当中,测试结果第四个可以看到 tail 指向索引7(也就是最后一个元素)的位置,此时如果我再加一个元素tail应该指向0(环形队列嘛,索引7的下一个元素索引就是0),正好模运算就可以实现 (7 + 1)% 8 = 0,front 加 1之后和capacity取模是一个道理

capacity总是空出一个元素来判断队列是否已满:

仍然看我上面举的例子:当我添加完元素9以后,可以看到队列中索引为1的位置是空着的,当我再向队列中添加元素10时就开始报queue is full的错误了。原因是,如果加完元素10以后,tail的指针位置正好和front的指针位置重合(都在索引值为2的位置),我们说过了当front == tail时判断的是队列为空,所以为了和队列为空的条件区分开,就空出一个元素位置来作为队列已满的判断条件