数据结构——队列:应用场景和介绍

概述

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

队列遵循“先入先出”原则,先存入队列的数据先取出,后存入的数据后取出。

数组模拟队列

基于数组的队列对象:

package com.leolee.dataStructure.queue;

/**
 * @ClassName ArrayQueue
 * @Description: TODO
 * @Author LeoLee
 * @Date 2020/9/10
 * @Version V1.0
 **/
public class ArrayQueue {

    private int maxSize;

    private int front;//队列头

    private int rear;//队列尾

    private int[] array;//该数组用于模拟队列,存放数据

    public ArrayQueue (int maxSize) {

        this.maxSize = maxSize;
        array = new int[maxSize];
        front = -1; //指向头部的前一个位置
        rear = -1;//指向队列尾部(就是指向队列的最后一个数据)
    }

    //判断是否满数据
    public boolean isFull () {

        return (rear + 1) == maxSize;
    }

    //判断是否为空
    public boolean isEmpty () {

        return rear == front;
    }

    //数据入队列
    public void addQueue (int n) {

        if (isFull()) {
            System.out.println("队列已满,不能加入数据");
            return;
        }
        rear++;
        array[rear] = n;
    }

    //数据出队列
    public int outPutQueue () {

        if (isEmpty()) {
            throw new RuntimeException("队列已空,无法取到任何数据");
        }
        front++; //先入先出,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\n", i, array[i]);
        }
    }

    //获取头数据
    public int headQueue () {

        if (isEmpty()) {
            throw new RuntimeException("队列已空,无法取到任何数据");
        }
        return array[front + 1];
    }

}

测试器:

package com.leolee.dataStructure.queue;

import java.util.Scanner;

/**
 * @ClassName ArrayQueueDemo
 * @Description: 数组模拟队列
 * @Author LeoLee
 * @Date 2020/9/10
 * @Version V1.0
 **/
public class ArrayQueueDemo {

    public static void main(String[] args) {

        ArrayQueue arrayQueue = new ArrayQueue(4);
        char key = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop) {
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):显示队列");
            System.out.println("a(add):添加队列");
            System.out.println("o(outPut):出队列");
            System.out.println("h(head):显示队列头部数据");
            key = scanner.next().charAt(0);//接收一个输入字符
            switch (key) {
                case 's' :
                    arrayQueue.showQueue();
                    break;
                case 'e' :
                    scanner.close();
                    loop = false;
                    break;
                case 'a' :
                    System.out.println("请输入一个正整数");
                    int i = scanner.nextInt();
                    arrayQueue.addQueue(i);
                    break;
                case 'o' :
                    try {
                        int result = arrayQueue.outPutQueue();
                        System.out.printf("取出的数据是:%d\n", result);
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h' :
                    try {
                        int headValue = arrayQueue.headQueue();
                        System.out.printf("头部数据是:%d\n", headValue);
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println(e.getMessage());
                    }
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

这些代码简单的模拟了队列的“先入先出”特性,但是这是一个有问题的demo,这个模拟队列中的“出”,实质上是通过 front 的“移动”来模拟的,“入”实质上是 rear 的“自增”模拟的,并没有实现真正的“出入”。由于有 maxSize 的限制,使这个队列变成了“一次性”的。怎么解决这个问题呢,往下看!

用数组模拟环形队列

针对上面的demo,需要调整如下:

  • front 变量的含义从指向头部第一个元素的前一个位置,调整为:指向队列的第一个元素的位置(也就是说array[front]就代表队列第一个元素),所以front 初始值为0。
  • rear 变量的含义从指向尾部元素的位置,调整为:指向队列最后一个元素的后面一个位置因为希望腾出一个空间做约定使用(环形队列的最后一个元素位置腾出,不做元素的存储)rear 的初始值为0
  • 队列满的条件由 (rear + 1) == maxSize,调整为:(rear + 1)% maxSize == front
  • 队列为空的条件:rear == front
  • 队列中有效数据的个数:(rear + maxSize - front) % maxSize
  • 原先的“一段”队列变为了“环形”队列,首尾相接。

模拟环形队列:

package com.leolee.dataStructure.queue;

/**
 * @ClassName CircleArrayQueue
 * @Description: 环形队列数组
 * @Author LeoLee
 * @Date 2020/9/10
 * @Version V1.0
 **/
public class CircleArrayQueue {

    private int maxSize;

    private int front;//队列头,指向队列的第一个元素的位置(也就是说array[front]就代表队列第一个元素),所以front 初始值为0

    private int rear;//队列尾,指向队列最后一个元素的后面一个位置。因为希望腾出一个空间做约定使用。rear 的初始值为0

    private int[] array;//该数组用于模拟队列,存放数据


    public CircleArrayQueue (int maxSize) {

        this.maxSize = maxSize;
        array = new int[maxSize];
        //int默认值为0,可以不写以下两行
        front = 0;
        rear = 0;
    }

    //判断是否满数据
    public boolean isFull () {

        return (rear + 1) % maxSize == front;
    }

    //判断是否为空
    public boolean isEmpty () {

        return rear == front;
    }

    //数据入队列
    public void addQueue (int n) {

        if (isFull()) {
            System.out.println("队列已满,不能加入数据");
            return;
        }
        //直接加入数据
        array[rear] = n;
        //将rear后移
        rear = (rear + 1) % maxSize;
    }

    //数据出队列
    public int outPutQueue () {

        if (isEmpty()) {
            throw new RuntimeException("队列已空,无法取到任何数据");
        }
        //先取出front指向的第一个变量
        int resultValue = array[front];
        //front向后取一位,要考虑front是最后一位的情况,要取模
        front = (front + 1) % maxSize;
        return resultValue;
    }

    //显示环形队列
    public void showQueue () {

        if (isEmpty()) {
            System.out.println("队列已空,无数据展示");
            return;
        }
        //从front开始遍历
        for (int i = front; i < front + getCurrentSize(); i++) {
            System.out.printf("array[%d]:%d\n", i % maxSize, array[i % maxSize]);
        }
    }

    //当前有效元素的个数
    public int getCurrentSize () {

        return (rear + maxSize - front) % maxSize;
    }

    //获取头数据
    public int headQueue () {

        if (isEmpty()) {
            throw new RuntimeException("队列已空,无法取到任何数据");
        }
        return array[front];
    }

}

测试器于之前逻辑一致,修改为 CircleArrayQueue 即可:

package com.leolee.dataStructure.queue;

import java.util.Scanner;

/**
 * @ClassName CircleArrayQueueDemo
 * @Description: 数组模拟环形队列
 * @Author LeoLee
 * @Date 2020/9/10
 * @Version V1.0
 **/
public class CircleArrayQueueDemo {

    public static void main(String[] args) {

        CircleArrayQueue circleArrayQueue = new CircleArrayQueue(4);//由于环形队列最后一位元素位置腾出,所以最大有效数据为3
        char key = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop) {
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):显示队列");
            System.out.println("a(add):添加队列");
            System.out.println("o(outPut):出队列");
            System.out.println("h(head):显示队列头部数据");
            key = scanner.next().charAt(0);//接收一个输入字符
            switch (key) {
                case 's' :
                    circleArrayQueue.showQueue();
                    break;
                case 'e' :
                    scanner.close();
                    loop = false;
                    break;
                case 'a' :
                    System.out.println("请输入一个正整数");
                    int i = scanner.nextInt();
                    circleArrayQueue.addQueue(i);
                    break;
                case 'o' :
                    try {
                        int result = circleArrayQueue.outPutQueue();
                        System.out.printf("取出的数据是:%d\n", result);
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h' :
                    try {
                        int headValue = circleArrayQueue.headQueue();
                        System.out.printf("头部数据是:%d\n", headValue);
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println(e.getMessage());
                    }
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

运行程序观察结果,注意体会数组“收尾想借”的感觉,

猜你喜欢

转载自blog.csdn.net/qq_25805331/article/details/108515070