03-队列

1. 简单介绍

  • 队列是一个有序列表,可以用数组或是链表来实现
  • 遵循先入先出的原则。即:先存入队列的数据,要先取出;后存入的要后取出
    一个应用场景:银行排队

2. 数组模拟队列

2.1 思路

  • 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front及 rear分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear则是随着数据输入而改变队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图, 其中 maxSize 是该队列的最大容量
  • 当我们将数据存入队列时称为"addQueue",addQueue 的处理需要有两个步骤
    1. 将尾指针往后移:rear+1,当 front == rear [队列空]
    2. 若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear 所指的数组元素中,否则无法存入数据。 rear == maxSize - 1 [队列满]

2.2 代码

public class ArrayQueue {
    // 表示数组最大容量
    private int maxSize;
    // 队列首元素之前的元素的下标
    private int front;
    // 队列尾元素下标
    private int rear;
    // 用来存放数据(模拟队列)
    private int[] arr;
    
    // 队列构造器
    public ArrayQueue(int maxSize) {
        this.maxSize = maxSize;
        arr = new int[maxSize];
        // 队列首有效元素的前一个位置的索引
        front = -1;
        // 队列尾有效元素的索引
        rear = -1;
    }
    
    // 判断队列是否满
    public boolean isFull() {
        return rear == maxSize-1;
    }
    
    // 判断队列是否空
    public boolean isEmpty() {
        return rear == front;
    }
    
    // 入列
    public void addQueue(int val) {
        // 判断是否满
        if(isFull()) {
            System.out.println("队列满");
            return;
        }
        arr[++rear] = val;
    }
    
    // 出列
    public int getQueue() {
        // 判断是否空
        if(isEmpty())
            throw new RuntimeException("队列空");
        return arr[++front];
    }
    
    // 打印队列数据
    public void showQueue() {
        if(isEmpty()) {
            System.out.println("队列空");
            return;
        }
        for(int i = 0; i < maxSize; i++) 
            System.out.printf("arr[%d] = %d\n", i, arr[i]);
    }
    
    // 显示首有效元素(不是取)
    public int headQueue() {
        if(isEmpty())
            throw new RuntimeException("队列空");
        return arr[front + 1];
    }
}

2.3 思想进阶 —— 循环队列

  • 上面的代码还有些问题,数组不能复用,造成内存浪费
  • 使用传统数组来构造队列,无论是出队还是入队都是指针在往后移;那么,之前的出队元素所在的数组元素空间就全被浪费了,所以必须让它成个"⚪"。即 当指针指向 [end元素],再往后移,就会又循环回来,指向了 [first元素]
    将数组看成环形

  • 队列初始化
    • front 和 rear 的值都是0
  • 队列非空
    • front 指向队列的第一个有效元素
    • rear 指向队列最后一个有效元素的下一个元素
  • 队列空
    • front == rear(不一定非得都等于0)
  • 队列满
    • 队列最多存放的有效数据个数:array.length - 1。即:当 (rear+1) % length == front,表示队列已满
  • 队列有效元素个数

    count = (rear - front + maxSize) % maxSize
    • 当rear > front,相减得到的就是 {有效元素个数},加 maxSize 再取余 还是它本身
    • 当rear < front,相减得到的是 [ - {空闲位置数} ],加上 maxSize ,就正好是 {有效元素个数} ,再取余,还是 {有效元素个数}

2.4 代码优化

public class CircleArrayQueue {
    // 表示数组最大容量
    private int maxSize;
    // 队列首元素下标
    private int front;
    // 队列尾元素的后一个位置的下标
    private int rear;
    // 用来存放数据(模拟队列)
    private int[] arr;
    
    // 队列构造器
    public CircleArrayQueue(int maxSize) {
        this.maxSize = maxSize + 1;
        // 因为需要保留其中一个位置作为 [标识位], 故创建的数组大小要大一个元素空间
        arr = new int[maxSize + 1];
        // 初始化
        front = 0;
        rear = 0;
    }
    
    // 判断队列是否满
    public boolean isFull() {
        return (rear + 1) % maxSize == front;
    }
    
    // 判断队列是否空
    public boolean isEmpty() {
        return rear == front;
    }
    
    // 入列
    public void addQueue(int val) {
        // 判断是否满
        if(isFull()) {
            System.out.println("队列满");
            return;
        }
        arr[rear] = val;
        // rear后移时要考虑到:rear指向的是数组末尾位置
        rear = (rear + 1) % maxSize;
    }
    
    // 出列
    public int getQueue() {
        // 判断是否空
        if(isEmpty())
            throw new RuntimeException("队列空");
        int val = arr[front];
        // front后移时要考虑到:front指向的是数组末尾位置
        front = (front + 1) % maxSize;
        return val;
    }

    // 当前队列有效元素个数
    public int getCount() {
        return (rear - front + maxSize) % maxSize;
    }
    
    // 打印队列数据
    public void showQueue() {
        if(isEmpty()) {
            System.out.println("队列空");
            return;
        }
        // 思路:从front开始遍历,遍历count个元素
        int count = getCount();
        for(int i = front; i < front + count; i++) 
            System.out.printf("arr[%d] = %d\n", i%maxSize, arr[i%maxSize]);
    }
    
    // 显示首有效元素(不是取)
    public int headQueue() {
        if(isEmpty())
            throw new RuntimeException("队列空");
        return arr[front];
    }
}

猜你喜欢

转载自www.cnblogs.com/liujiaqi1101/p/12214211.html
03-