队列


队列

队列是一个有序列表,可以用数组或是链表来实现。

遵循先进先出的原则,即先存入队列的数据,要先取出,后存入的要后取出

数组模拟队列

实现的思路

  • 队列是有序列表,使用数组来存储队列的数据,则需要创建数组ArrayQueue arrayQueue = new ArrayQueue(maxSize);,其中maxSize是该队列的最大值,ArrayQueue是实现队列的类。
  • 因为队列的输入输出分别是从队列的前后端存入和取出,因此需要两个变量frontrear分别指向队列前后端的下标。front随着数据输出而向后移动,rear随着数据的输入而进行移动。初始化时,front和rear变量都定义为 -1
  • 当数据存入队列时,首先将尾指针向后移:rear + 1,判断尾指针rear是否小于队列的最大下标值 maxSize - 1,如果是则将数据存入 rear 所指的数组元素中,否则无法存入数据。当 rear == maxSize - 1 则表示队列满。
  • 当数据从队列取出时,首先判断队列是否为空,front == rear 表示队列为空,若不为空则将 front + 1,取出数组对应下标的值。

实现代码

public class ArrayQueueDemo {

    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        char key = ' ';     // 接收用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop){
            System.out.println("s(show):显示队列");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头的数据");
            System.out.println("e(exit):退出程序");
            key = scanner.next().charAt(0);     // 接收一个字符
            switch (key){
                case 's':
                    arrayQueue.showQueue();
                    break;
                case 'a':
                    System.out.print("请输入一个数字:");
                    int value = scanner.nextInt();
                    arrayQueue.addQueue(value);
                    break;
                case 'g':
                    try {
                        int result = arrayQueue.getQueue();
                        System.out.println("取出的数据是:" + result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int result = arrayQueue.getFrontData();
                        System.out.println("队列头数据是:" + result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    System.out.println("程序结束");
                    loop = false;
                default:
                    System.out.println("输入错误,请重新输入");
                    break;
            }
        }
    }
}


// 使用数组模拟队列
class ArrayQueue{
    private int maxSize;    // 数组最大容量
    private int front;      // 队列头
    private int rear;       // 队列尾
    private int[] array;    // 该数组用于存储数据,模拟队列

    // 模拟队列的构造器
    public ArrayQueue(int arraySize){
        maxSize = arraySize;
        front = -1;     // 指向队列头部,分析出front是指向队列头的前一个位置
        rear = -1;      // 指向队列尾部,指向队列尾部的数据(即队列的最后一个位置)
        array = new int[maxSize];
    }

    // 判断队列是否已满
    public Boolean isFull(){
        return rear == maxSize - 1;
    }

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

    // 添加数据到队列
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队列已满,无法添加数据");
            return;
        }
        rear++;
        array[rear] = n;  // array[++rear]
    }

    // 获取队列数据,出队列
    public int getQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,无法获取数据...");
        }
        front++;
        return array[front];
    }

    // 遍历队列数据
    public void showQueue(){
        if (isEmpty()){
            System.out.println("队列为空,没有数据...");
            return;
        }
        for (int i = 0; i < array.length; i++){
            System.out.printf("array[%d] = %d ", i ,array[i]);
        }
        System.out.println();
    }

    // 显示队列的头数据,不是取出数据
    public int getFrontData(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,头数据为空");
        }
        int i = array[++front];
        front--;
        return i;
    }
}

数组模拟环形队列

实现的思路

将数组看作一个环形,利用取模的方式来实现。具体思路如下:

  • front变量指向队列的第一个元素,即array[front]表示队列的第一个值,front的初始值定义为 0
  • rear变量指向队列的最后一个元素,并且空出一个位置作为缓冲区,rear的初始值定义为 0
  • 存入数据时,首先判断队列是否已满,判断条件是(rear + 1) % maxSize == front,如果未满则在rear所指的下标位置添加数据,并且将rear变量向后移动,由于是环形队列,考虑溢出的情况需要取模(rear + 1) % maxsize
  • 取出数据时,判断队列是否为空,判断条件是 front == rear。不为空则取出当前front下标对应的值。
  • 环形队列中有效数据个数:(rear + maxSize - front) % maxSize

实现代码

public class CircleArrayQueueDemo {
    public static void main(String[] args) {
        CircleArrayQueue arrayQueue = new CircleArrayQueue(3);
        char key = ' ';     // 接收用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop){
            System.out.println("s(show):显示队列");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头的数据");
            System.out.println("y(head):有效数据个数");
            System.out.println("e(exit):退出程序");
            key = scanner.next().charAt(0);     // 接收一个字符
            switch (key){
                case 's':
                    arrayQueue.showQueue();
                    break;
                case 'a':
                    System.out.print("请输入一个数字:");
                    int value = scanner.nextInt();
                    arrayQueue.addQueue(value);
                    break;
                case 'y':
                    int i = arrayQueue.size();
                    System.out.println("有效个数是:" + i);
                    break;
                case 'g':
                    try {
                        int result = arrayQueue.getQueue();
                        System.out.println("取出的数据是:" + result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int result = arrayQueue.getFrontData();
                        System.out.println("队列头数据是:" + result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    System.out.println("程序结束");
                    loop = false;
                default:
                    System.out.println("输入错误,请重新输入");
                    break;
            }
        }
    }
}

class CircleArrayQueue{
    private int maxSize;    // 数组最大容量
    // front 变量的含义:front指向队列的第一个元素,也就是arr[front],front的初始值为0
    private int front;      // 队列头
    // rear 变量的含义:rear指向队列的最后一个元素的最后一个位置,空出一个空间做缓冲,rear的初始值为0
    private int rear;       // 队列尾
    private int[] array;    // 该数组用于存储数据,模拟队列

    // 模拟队列的构造器
    public CircleArrayQueue(int arraySize){
        maxSize = arraySize;
        front = 0;     // 指向队列头部,分析出front是指向队列头的前一个位置
        rear = 0;      // 指向队列尾部,指向队列尾部的数据(即队列的最后一个位置)
        array = new int[maxSize];
    }

    // 判断队列是否已满
    public Boolean isFull(){
        return (rear + 1) % maxSize == front;
    }

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

    // 添加数据到队列
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队列已满,无法添加数据");
            return;
        }
        array[rear] = n;
        // 将rear后移,必须考虑取模,环形队列可以会数组越界
        rear = (rear + 1) % maxSize;
    }

    // 获取队列数据,出队列
    public int getQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,无法获取数据...");
        }
        int i = array[front];
        front = (front + 1) % maxSize;
        return i;
    }

    // 遍历队列数据
    public void showQueue(){
        if (isEmpty()){
            System.out.println("队列为空,没有数据...");
            return;
        }
        // 重要,环形队列循环查看数据
        for (int i = front; i < front + size(); i++){
            System.out.printf("array[%d] = %d\n", i % maxSize ,array[i % maxSize]);
        }
        System.out.println();
    }

    // 求出当前数组的有效数据个数
    public int size(){
        return (rear + maxSize - front) % maxSize;
    }

    // 显示队列的头数据,不是取出数据
    public int getFrontData(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,头数据为空");
        }
        return array[front];
    }
}

上述代码是存在一个空位置作为缓冲区,下面没有缓冲区并实现环形队列

public class CircleArrayQueueDemo {
    public static void main(String[] args) {
        CircleArrayQueue arrayQueue = new CircleArrayQueue(3);
        char key = ' ';     // 接收用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop){
            System.out.println("s(show):显示队列");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头的数据");
            System.out.println("y(head):有效数据个数");
            System.out.println("e(exit):退出程序");
            key = scanner.next().charAt(0);     // 接收一个字符
            switch (key){
                case 's':
                    arrayQueue.showQueue();
                    break;
                case 'a':
                    System.out.print("请输入一个数字:");
                    int value = scanner.nextInt();
                    arrayQueue.addQueue(value);
                    break;
                case 'y':
                    int i = arrayQueue.size();
                    System.out.println("有效个数是:" + i);
                    break;
                case 'g':
                    try {
                        int result = arrayQueue.getQueue();
                        System.out.println("取出的数据是:" + result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int result = arrayQueue.getFrontData();
                        System.out.println("队列头数据是:" + result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    System.out.println("程序结束");
                    loop = false;
                default:
                    System.out.println("输入错误,请重新输入");
                    break;
            }
        }
    }
}

class CircleArrayQueue{
    private int maxSize;    // 数组最大容量
    private int front;      // 队列头
    private int rear;       // 队列尾
    private int[] array;    // 该数组用于存储数据,模拟队列

    // 模拟队列的构造器
    public CircleArrayQueue(int arraySize){
        maxSize = arraySize;
        front = -1;     // 指向队列头部,分析出front是指向队列头的前一个位置
        rear = -1;      // 指向队列尾部,指向队列尾部的数据(即队列的最后一个位置)
        array = new int[maxSize];
    }

    // 标志位  0 表示 rear == front 为空,1 表示 rear == front 为满
    int i = 0;

    // 判断队列是否已满
    public Boolean isFull(){
        if (rear == -1){
            return false;
        }
        if (rear + 1 == maxSize && front == -1){
            return true;
        }
        if (i == 1 && rear == front){
            return true;
        }
        return false;
    }

    // 判断队列是否为空
    public boolean isEmpty(){
        return i == 0 && front == rear;
    }

    // 添加数据到队列
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队列已满,无法添加数据");
            return;
        }
        // 将rear后移,必须考虑取模,环形队列可以会数组越界
        if (++rear >= maxSize){
            i = 1;
            rear %= maxSize;
        }
        array[rear] = n;
    }

    // 获取队列数据,出队列
    public int getQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,无法获取数据...");
        }
        if (++front == maxSize){
            i = 0;
            front = -1;
        }
        return array[front];
    }

    // 遍历队列数据
    public void showQueue(){
        if (isEmpty()){
            System.out.println("队列为空,没有数据...");
            return;
        }
        if (front == -1){
            for (int i = front + 1; i <= rear; i++){
                System.out.printf("array[%d] = %d\n", i % maxSize ,array[i % maxSize]);
            }
        }else{
            for (int i = front + 1; i <= front + size(); i++){
                System.out.printf("array[%d] = %d\n", i % maxSize ,array[i % maxSize]);
            }
        }
        System.out.println();
    }

    // 求出当前数组的有效数据个数
    public int size(){
        if (front == -1){
            return rear+1;
        }
        if (rear == front && i == 1){
            return maxSize;
        }
        return (rear + maxSize - front) % maxSize;
    }

    // 显示队列的头数据,不是取出数据
    public int getFrontData(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,头数据为空");
        }
        int i = array[++front];
        front--;
        return i;
    }
}

文章作者: zerollone
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 zerollone !
  目录