一篇文章为你讲透环形队列(全文代码详解)

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

本文的数组模拟环形队列是基于上文数组模拟队列之深度解析 - 掘金 (juejin.cn)数组模拟队列(测试样例,含源码分析) - 掘金 (juejin.cn)所进行的代码深入剖析,读者可自行观看上文,再看本文效果最佳

1.4 数组模拟环形队列

1.4.1 分析说明

(1)尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意(rear + 1)% maxSize == front[满]

(2)rear == front[空]

(3)分析示意图

image.png

1.4.2 思路如下

(1)front变量的含义做一个调整:front指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素,front的初始值 = 0

(2)rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值=0

(3)当队列满时,条件是(rear + 1) % maxSize = front[满]

(4)当队列为空的条件,rear == front[空]

(5)队列中有效的数据的个数即为(rear + maxSize - front) % maxSize

1.4.3 代码实现

class CircleArray {
    private int maxSize;
    private int front;
    private int rear;
    private int[] arr;
复制代码

上方代码详解

(1)maxSize即表示数组的最大容量

(2)front指向队列的第一个元素,也就是说arr[front]队列的第一个元素

(3)rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定

(4)int[] arr用于存放数据,模拟队列

public CircleArray(int arrMaxSize) {
    maxSize = arrMaxSize;
    arr = new int[maxSize];
}
复制代码

上方代码详解

(1)此处定义一个CircleArray队列构造器,同时定义一个arrMaxSize用于存储数组最大容量

(2)将arrMaxSize赋值给ArrayQueue的最大容量值maxSize

(3)开辟一个新的内存空间用于存放数组,并将其指针指向maxSize,即数组的最大容量,然后赋值给arr[]用于存放数据,模拟队列

public boolean isFull() {
    return (rear + 1) % maxSize == front;
}
public boolean isEmpty() {
    return rear == front;
}
复制代码

上方代码详解

(1)isFull():该方法用于判断队列是否满,当队列满时(见下图),故此时return (rear + 1) % maxSize == front能够得到队列为的判断

image.png (2)isEmpty():该方法用于判断队列是否空,当队列空时,CircleArray环形队列的头尾节点 “重合” ,表明此时队列里面没有数据,队列为空

public void addQueue(int n) {
    if (isFull()) {
        System.out.println("队列满,不能添加数据");
        return;
    }
    arr[rear] = n;
    rear = (rear + 1) % maxSize;
}
复制代码

上方代码详解

(1)我们定义一个void类型的addQueue()方法,并赋值参数n用于添加数据

(2)如果环形队列已满,则System.out.println告知读者队列已满不能继续添加数据,并立即返回

(3)如果环形队列未满,则将参数n赋值给数组arrrear的位置,由于rear在环形队列中指rear后一位,故无需考虑数组arr[0]的问题

此时的rear的位置将会由(rear + 1) % maxSize所赋值过去,由于rear本身自带+1属性,故在表达式中的 “ 1 ” 是给即将添加的数据准备的,而rear本身自带的+1是为腾出一个空间准备的

public int getQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空,不能取出数据");
        }
        int value = arr[front];
        front = (front + 1) % maxSize;
        return value;
    }
复制代码

上方代码详解

(1)我们定义一个getQueue()方法用于获取队列中的数据

(2)首先得判断队列是否为空,故 if (isEmpty()),如果为空,则抛出异常告知读者该队列为空,不能取出数据

(3)如果不为空,则定义一个变量value作为用户取出的数值,同时将arr[front]赋值给value,并将其作为取出的数值。由于front自带 +1的属性,故无需考虑数组本身的特性

(4)front后移一位留出一空,符合环形队列的约定,将其用于与数组最大容量maxSize取模,得出此时环形队列front应该在的位置,最终return value

public void showQueue() {
    if (isEmpty()) {
        System.out.println("队列空,没有数据");
        return;
    }
    for (int i = 0; i < front + size(); i++) {
        System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
    }
}
复制代码

上方代码详解

(1)我们定义一个showQueue()方法用于展示队列的所有数据

(2)如果队列为空,则不能添加数据,同时通过 System.out.println()告知读者队列为空return

(3)通过for循环遍历元素,size()的作用已在上文说过,见数组模拟队列(测试样例,含源码分析) - 掘金 (juejin.cn)

(4)通过System.out.printf()打印并格式化输出arr[%d]可以用i自增时候的数值去对该环形队列进行取模,得出该数组的实际位置,同时通过arr数组锁定数值

public int size() {
    return (rear + maxSize - front) % maxSize;
}
复制代码

上方代码详解

(1)我们定义一个size()方法用于求出当前队列有效数据的个数

(2)当读者将rear看作2,front看作1,maxSize看作3即可理解第二行代码的意思

    public int headQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空,没有数据");
        }
        return arr[front];
    }
}
复制代码

上方代码详解

(1)我们定义一个headQueue()方法用于显示环形队列的头数据

(2)如果为空,则抛出异常用于告知用户环形队列空,没有数据

(3)如果不为空 ,则返回数组中arr[]中的front的位置

猜你喜欢

转载自juejin.im/post/7129508751983247390