zoukankan      html  css  js  c++  java
  • 03-队列

    1. 简单介绍

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

    2. 数组模拟队列

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

    3. 代码实现

    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
    ", i, arr[i]);
        }
    
        // 显示首有效元素(不是取)
        public int headQueue() {
            if (isEmpty()) throw new RuntimeException("队列空");
            return arr[front + 1];
        }
    }
    

    4. 进阶:循环队列

    上面的代码还有些问题,数组不能复用,造成内存浪费。使用传统数组来构造队列,无论是出队还是入队都是指针在往后移;那么,之前的出队元素所在的数组元素空间就全被浪费了,所以必须让它成个"⚪"。即 当指针指向「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 ,就正好是 {有效元素个数} ,再取余,还是 {有效元素个数}

    5. 代码优化

    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
    ", i%maxSize, arr[i%maxSize]);
        }
    
        // 显示首有效元素(不是取)
        public int headQueue() {
            if(isEmpty()) throw new RuntimeException("队列空");
            return arr[front];
        }
    }
    
  • 相关阅读:
    开涛spring3(6.5)
    开涛spring3(6.4)
    开涛spring3(6.3)
    开涛spring3(6.2)
    开涛spring3(6.1)
    开涛spring3(5.4)
    开涛spring3(5.3)
    开涛spring3(5.1&5.2)
    开涛spring3(4.4)
    开涛spring3(4.3)
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/12214382.html
Copyright © 2011-2022 走看看