数组模拟环形队列的学习心得

一、相关概念

> #### 队列

队列是一种常见的数据结构之一,最典型的、经常使用队列这种数据结构进行开发的,是叫号系统。

队列有以下几种特点:

  1. 先进先出:越早被存进队列的数据,就会越早被取出来;
  2. 属于线性结构,线性数据结构主要包括:数组、队列、链表以及栈;
  3. 队列可以通过数组和链表来表示。

二、数组模拟队列

> #### 数组模拟普通队列

  1. 首先介绍一下图片中那些单词的具体含义:

    ​ ① MaxSize: 代表着该队列的最大容量,也是数组的长度

    ​ ② Queue: 是队列这个单词的英文写法

    ​ ③ front: 指的是队列数据(图中红色部分)中的第一个数据的数组索引值再减去1

    ​ ④ rear: 指的是队列数据(图中红色部分)中的最后一个数据的数组索引值

  2. 之所以会引用front以及rear这两个变量,是因为队列中数据的输入和输入是从前后端来处理的,需要这两个值来记录该队列的前后端在数组中的位置。其中,front会随着输出数据改变,rear会随着输入数据改变。

  3. 很容易可以推算出:如果 front == rear ,那么代表着队列中没有数据;如果 rear == maxSize -1 ,代表着队列已经存放满了数据。

  4. 代码实现:

    //使用数组来模拟队列
    class ArrayQueue{
        private int maxSize; //表示数组的最大容量
        private int front; //队列头
        private int rear; //队列尾
        private int[] arr; //用于模拟队列
    
        //创建队列构造器
        public ArrayQueue(int arrMaxSize) {
            this.maxSize = arrMaxSize;
            this.front = -1;    //指向队列的头部,front指的的是队列头的前一个位置
            this.rear = -1;     //指向队列尾,指向队列尾的数据(即就是队列的最后一个数据)
            this.arr = new int[maxSize];
        }
    
        //判断队列是否是满的
        public boolean isFull(){
            return rear == maxSize - 1;
        }
    
        //判断队列是否为空
        public boolean isEmpty(){
            return rear == front;
        }
    
        //添加数据到队列
        public void addQueue(int n){
            //判断队列是否已满
            if(isFull()){
                System.out.println("队列已满,不能再次加入数据~~");
                return;
            }
            rear++; //让rear后移
            arr[rear] = n;
        }
    
        //从队列中获取数据
        public int getQueue(){
            //判断队列是否为空
            if (isEmpty()){
                //抛出异常
                throw new RuntimeException("队列是空的,没有数据~~");
            }
            front++;
            return arr[front];
        }
    
        //显示队列的所有数据
        public void showQueue(){
            //遍历
            if (isEmpty()){
                System.out.println("队列是空的,没有数据~~");
                return;
            }
    
            for (int i = 0; i < arr.length; i++) {
                System.out.printf("arr[%d]=%d\n",i,arr[i]);
            }
        }
    
        //显示队列的头数据,注意不是取数据
        public int headQueue(){
            //判断
            if (isEmpty()){
                throw new RuntimeException("队列是空的,没有数据~~");
            }
            return arr[front+1];
        }
    }
    
  5. 缺点:rear的值理论上不可超过数组的最大索引值,导致该数组只能存储一遍数据。优化的方式是把普通队列的形式改成环形队列的形式。

> #### 数组模拟环形队列

数组模拟环形队列

  1. head代表着队列的第一个数据的索引值,tail代表着队列的的最后一个数据的后一个索引值

  2. 环形数组实现时,重点需要理解取模的含义。通过取模,就避免了tail索引值的越界,也就避免了数组不能重复使用的缺点

  3. 几个变量的值:

    ① tail == head : 代表队列为空

    ② (tail + 1) % maxSize == head: 代表队列已满

    ③ (tail + maxSize - head) % maxSize : 代表队列中的数据个数

  4. 代码实现

    class CircleArray{
        private int maxSize; //表示数组的最大容量
        private int head; //队列头:指向的是队列的第一个数据,初始值为0
        private int tail; //队列尾:指向的是队列的最后一个数据的后一个位置,初始值也是为0
        private int[] arr; //用于模拟队列
    
        public CircleArray(int arrMaxSize){
            this.maxSize = arrMaxSize;
            this.arr = new int[maxSize];
        }
    
        //判断队列是否是满的
        public boolean isFull(){
            return (tail + 1) % maxSize == head;
        }
    
        //判断队列是否为空
        public boolean isEmpty(){
            return tail == head;
        }
    
        //添加数据到队列
        public void addQueue(int n){
            //判断队列是否已满
            if(isFull()){
                System.out.println("队列已满,不能再次加入数据~~");
                return;
            }
            //直接将数据加入
            arr[tail] = n;
            //将tail后移,这里必须考虑取模
            tail = (tail + 1) % maxSize;
        }
    
        //从队列中获取数据
        public int getQueue(){
            //判断队列是否为空
            if (isEmpty()){
                //抛出异常
                throw new RuntimeException("队列是空的,没有数据~~");
            }
            // 这里需要分析出head是指向队列的第一个元素
            //1.先把head对应的值保存到一个临时的变量中去
            //2.将head后移,这里需要取模,否则数组下标可能越界
            //3.将临时变量返回
            int value = arr[head];
            head = (head + 1) % maxSize;
            return value;
        }
    
        //显示队列的所有数据
        public void showQueue(){
            if (isEmpty()){
                System.out.println("队列是空的,没有数据~~");
                return;
            }
    
            //思路:从head开始遍历,遍历多少个元素
            for (int i = head; i < head + size(); i++) {
                System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
            }
        }
    
        //求出当前队列有效数据的个数
        public int size(){
            return (tail + maxSize - head) % maxSize;
        }
    
    
        //显示队列的头数据,注意不是取数据
        public int headQueue(){
            //判断
            if (isEmpty()){
                throw new RuntimeException("队列是空的,没有数据~~");
            }
            return arr[head];
        }
    }
    
posted @ 2021-05-26 21:31  Na氢氧  阅读(124)  评论(0编辑  收藏  举报