数据结构与算法单排日记-2020/2/29-队列

生来就可爱ヽ(ⅴ<●) 提交于 2020-03-05 06:25:27

1.队列是一个有序列表,可以用数组或者链表表示。
2.遵循先入先出的原则:先存入队列的数据,要先取出。后存入的要后取出。
在这里插入图片描述

数组模拟队列

  1. 队列本身是一个有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下。其中maxSize是该队列的最大容量
  2. 因为队列的输出、输入分别从前后端来处理,因此需要两个变量front及rear分别记录前后端的下标。
    在这里插入图片描述
    在这里插入图片描述
  3. 初始化
  • rear初始值默认为-1;
  • rear指向队列尾的位置(就是队列尾)
  • front初始值默认为-1;
  • front指向队列首的前一个位置(不是队列首)
  1. 将数据存入队列(addQueue):
  • 将尾部指针往后移,rear+1,如果front=rear,则队列为空
  • 若rear小于最大下标maxSize-1,那么将数据存入rear所指的数组元素中。否则无法存入。 rear==maxSize-1,则队列已满。
  1. 当数据出队列时:
  • 首指针往后移:front+1

代码实现:

public class DemoQueue {
    /*
    当将数据存入队列时:
    1.将尾指针往后移:rear+1,当front==rear,队列为空
    2.若尾指针rear==maxSize-1时,队列满,无法存入数据

    当数据出队列时:
    首指针往后移:front+1

    */
    private int maxSize;//数组最大容量
    private int rear;//尾指针
    private int front;//首指针

    private int[] arr;//实现队列的数组

    public DemoQueue(int arrMaxsize) {//含参构造方法,传入参数为最大容量
        maxSize = arrMaxsize;//获取最大容量
        arr = new int[maxSize];//根据最大容量,创建一个数组
        //初始化指针
        front = -1;//front指向队列首的前一个位置(不是队列首)
        rear = -1;//rear指向队列尾的位置(就是队列尾)
    }

    //2,判断 队列是否为满,若尾指针rear==maxSize-1时,队列满,无法存入数据
    public boolean isfull() {
/*        if (rear==maxSize-1){
            return true;
        }else {
            return false;
        }*/
        return rear == maxSize - 1;
    }

    //1.判断队列是否为空,当front==rear,队列为空
    public boolean isnull() {
        return rear == front;
    }

    //1.添加数据到队列,将尾指针往后移:rear+1

    public void addData(int i) {
        if (isfull()) {
            System.out.println("队列已满");
        } else {
            arr[++rear] = i;
        }
    }

    //数据出队列
    public int getData() {
        if (isnull()) {//如果队列为空,抛出一个异常
            throw new RuntimeException("队列为空");
        } else {
            return arr[++front];
        }
    }

    //显示队列所有数据
    public void showArr() {
        if (isnull()) {
            System.out.println("队列为空");
        } else {
            for (int i : arr) {
                System.out.println(i);
            }
        }
    }

    //显示队列第一个数据
    public void showFirst(){
        if (isnull()){
            System.out.println("队列为空");
        }else{
            System.out.println(arr[front+1]);
        }
    }

}

主程序验证:

import java.util.Scanner;

public class ArrayQueue {
    public static void main(String[] args) {
        //创建一个队列,最大容量为3
        DemoQueue demoQueue = new DemoQueue(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("g(get),取出数据");
            System.out.println("h(head),查看头数据");

            key = scanner.next().charAt(0);//接收键盘传过来的一个字符
            switch (key) {
                case 's':
                    demoQueue.showArr();
                    break;
                case 'a':
                    System.out.println("请输入一个数");
                    demoQueue.addData(scanner.nextInt());
                    break;
                case 'g':
                    try {
                        System.out.println("取出数据为:" + demoQueue.getData());
                    } catch (RuntimeException i) {
                        System.out.println(i.getMessage());
                    }
                    break;
                case 'h':
                    demoQueue.showFirst();
                    break;
                case 'e':
                    scanner.close();
                    loop=false;
                    break;
            }
        }
    }
}

结果:

"G:\IntelliJ IDEA 2019.2.3\jbr\bin\java.exe" "-javaagent:G:\IntelliJ IDEA 2019.2.3\lib\idea_rt.jar=33297:G:\IntelliJ IDEA 2019.2.3\bin" -Dfile.encoding=UTF-8 -classpath G:\Java\IdeaProjects\dataStruts\out\production\days0302 ArrayQueue
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
s
队列为空
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
a
请输入一个数
12
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
a
请输入一个数
6
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
h
12
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
g
取出数据为:12
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
h
6
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
e

Process finished with exit code 0

数组只能使用 而且数组还是有数据的 没有达到复用的效果
解决方案:将这个数组使用算法,改进成一个环形的队列 取模 %

优化:使用数组模拟环形队列的思路分析

  1. 初始化
  • front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素
  • front 的初始值 = 0
  • rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
  • rear 的初始值 = 0
  1. 添加和取出数据
  • 当队列满时,条件是(rear + 1) % maxSize == front 【满】
  • 对队列为空的条件, rear == front
  • 队列中有效的数据的个数 (rear + maxSize - front) % maxSize

队列满条件是(rear + 1) % maxSize == front 解释:

1.为什么取模:
%运算是一个神奇的运算,它是一个哈希运算
因为取模%操作可以把任意数压缩到一定区间内,比如,你想知道一年中第 122 天是星期几,那么你就用【121%7】,结果为二。诸如此类。就拿这个例子里的maxsize = 8 来说, 一定会有(任意数 % 8)的结果小于8。
尾指针rear在一直不断增加,到最后比maxsize还大,所以取模以后可以将rear固定在0到maxsize的范围内

2.为什么rear+1
在这里插入图片描述
实际上,(rear + 1) % maxSize == front时候,数组中还要一个空余,但是如果不浪费这个空间的话,此条件将会和队列为空的条件一致,会导致无法区分队列是满还是空

队列中有效的数据的个数 (rear + maxSize - front) % maxSize解释:
(rear -front+ maxSize)% maxSize:相当于|rear-front|


class CircleArrayQueue {
    //数组的最大容量
    private int maxSize;
    //队列头部
    //front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素
    private int front;
    //队列尾部
    //rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
    private int rear;
    //模拟队列的数组
    private int[] arr;

    //创建队列的构造器

    public CircleArrayQueue(int maxSize) {
        this.maxSize = maxSize;
        arr = new int[maxSize];
        //队列头 前一个位置
        front = 0;
        //队列尾 就是尾部(包含)
        rear = 0;
    }

    //判断队列是不是满了
    public boolean isFull() {
        return (rear + 1) % maxSize == front;
    }

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

    //添加数据到队列
    public void addQueue(int n) {
        //判断队列是不是已经满了
        if (this.isFull()) {
            System.out.println("队列已经满了,不能再加入");
        } else {
            //直接放到数据
            arr[rear] = n;
            //把 rear 后移 这里必须考虑取模
            rear = (rear + 1) % maxSize;
        }
    }

    //获取数据
    public int getQueue() {
        //判断队列是否为空
        if (this.isEmpty()) {
            throw new RuntimeException("队列为空,不能取出数据");
        } else {
            //这里需要分析front是指向队列的第一个元素
            //1.先把front对应的值保留到一个临时变量
            //2.front后移考虑取模
            //将保存的数据返回
            int value = arr[front];
            front = (front + 1) % maxSize;
            return value;
        }
    }

    //显示数据所有的数据
    public void showQueue() {
        //遍历
        if (this.isEmpty()) {
            System.out.println("队列为空");
        } else {
            //思路 从 front进行遍历 遍历多少个元素
            //元素有效个数为(rear-front+maxsize)%maxsize
            for (int i = front; i <front+(rear-front+Maxsize)%Maxsize; i++) {
                System.out.println("arr["+i%Maxsize+"]"+":"+arr[i%Maxsize]);
                //front可能会超界,i=front,所以i%maxsize防止超界
            }
        }
    }
    //显示队列头数据
    public void showQueueFront() {
        if (this.isEmpty()) {
            System.out.println("队列为空");
        } else {
            System.out.println(arr[front]);
        }
    }
}
import java.io.IOException;
import java.util.Scanner;

public class DemoQueue {
    public static void main(String[] args) {

        ArrayQueue arrayQueue = new ArrayQueue(3);
        Scanner scanner = new Scanner(System.in);

        boolean loop = true;
        char key = ' ';
        while (loop) {
            System.out.println("e(exit),退出");
            System.out.println("s(show),显示队列内数据");
            System.out.println("f(first),显示队列第首数据");
            System.out.println("a(add),添加数据");
            System.out.println("g(get),取出数据");

            key = scanner.next().charAt(0);

            switch (key) {
                case 'e':
                    scanner.close();
                    loop = false;
                    break;

                case 's':
                    try {
                        arrayQueue.showArray();
                    } catch (RuntimeException e) {
                        System.out.println(e.getMessage());
                    } finally {
                        break;
                    }

                case 'f':
                    try {
                        arrayQueue.showFirst();
                    } catch (RuntimeException e) {
                        System.out.println(e.getMessage());
                    } finally {
                        break;
                    }

                case 'a':
                    try {
                        arrayQueue.addData(scanner.nextInt());
                    } catch (RuntimeException e) {
                        System.out.println(e.getMessage());
                    } finally {
                        break;
                    }

                case 'g':
                    try {
                        arrayQueue.getData();
                    } catch (RuntimeException e) {
                        System.out.println(e.getMessage());
                    } finally {
                        break;
                    }
            }
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!