死磕数据结构与算法——队列(JAVA)

1. 基本概念

队列(FIFIO):一种特殊的线性表,符合先进先出的原则, 即先进入队列的元素,要先取出,后存入队列的元素后取出。
队尾:允许插入元素的一端。(数组的前端)
队头:允许删除元素的一端。(数组的后端)

2. 数组模拟队列

队列的输入、输出与队列的两端有关系,所以我们设置两个变量来记录队列的前端和末端。front(前端)即取出元素的一端、rear(后端)即插入元素的一端。

1. 模拟示意图

2. 思路解析

  1. 首先需要对模拟的数组进行初始化。先要获得数组的大小即队列的长度,创建数组,设置两个变量front和rear分别表示队列的前端(出队列)和后端(入队列)。front指向队列的第一个元素的前一个,rear指向队列的最后一个元素。
  2. 判断队列是否为空:当出队列时,需要将front往后移动一格,再把元素取出。进队列时,需要把元素插入之后,再将rear向后移动。当front与rear相等,即front==rear时,表示front不用往后移动就到了队列的末尾,所以此时队列为空。
  3. 判断队列是否满:当rear变量指向数组的最后一个位置时,即队列已经不能再插入元素了,所以此时队列为满状态。
  4. 把数据添加都队列,首先判断队列是否满,参上。满了即插入不了了,如果未满,则把rear往后移动一格,然后把插入的数据赋值到数组的rear位置上。
  5. 出队列:首先判断队列是否为空,参上。满了即没有元素可以出来了;如果不为空,则把front往后移动一格,然后把数组中再front位置上的数据取出。
  6. 显示队列头数据:因为front指向队列头的前一个位置,所以直接取出数组[front+1]位置上的元素即是此时队列的头数据。

3. 代码实现

class ArrayQueue {
    
    
    private int maxSize; //表示数组的最大容量
    private int front; //队列头-前端
    private int rear; //队列尾-后端
    private int[] arr; //该数组用于存放数据,实现模拟队列

    //创建数组队列的构造器
    public ArrayQueue(int arrMaxSize) {
    
    
        maxSize = arrMaxSize;
        arr = new int[maxSize];  //为数组指定大小
        //front和rear的初始值都等于-1
        front = -1; //指向队列头部,分析出front是指向队列头的前一个位置
        rear = -1; //指向队列尾,指向队列尾的数据(即队列的最后一个数据)
    }

    //判断队列是否满,当rear的值指向数组的最后一个位置时,说明数组的最后一个位置有数据了,即队列满。
    public boolean isFull() {
    
    
        return rear == maxSize - 1;
    }

    //判断队列是否为空,当front和rear的值相等时,队列为空
    public boolean isEmpty(){
    
    
        return front == rear;
    }

    //添加数据到队列
    public void addQueue(int n) {
    
    
        //判断队列是否满
        if(isFull()){
    
    
            System.out.println("队列满,不允许加入数据!!");
        }
        rear++; //让rear 后移
        arr[rear] = n; //把要插入的数据赋值给arr[rear]
    }

    //获取队列的数据,即出队列。即让队列中最先进去的元素出队列
    public int getQueue() {
    
    
        //判断队列是否空
        if(isEmpty()){
    
    
            //通过抛出异常
            throw new RuntimeException( "队列空,不能取数据" );
        }
        front++; //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]; //此处是取出队头数据,不是出队列。所以不需要移动控制出队列的变量front
    }
}

4. 存在的问题

数组只能使用一次,利用率低。
优化:把数组单向队列改成一个环形的队列。

3. 数组模拟环形队列

1. 实现:以取模的方式把数组看成一个环形的。

2. 示意图:

3. 思路:

  1. front: 此时指向队列的第一个元素。front初始值为0.
  2. rear:此时指向队列的最后一个元素的后一个位置。把空出来的那个位置作为一个约定。rear
    初始值为0.
  3. 队列满:(rear+1)% maxSize == front。
  4. 队列空: rear == front
  5. 队列中有效数据的个数:(rear + maxSize - front)% maxSize 。

4. 代码实现

class CircleArray {
    
    
    private int maxSize; //表示数组的最大容量
    //front 变量含义做一个调整:front 就指向队列的第一个元素,也就是arr[front]
    //front 的初始值=0
    private int front; //队列头
    //rear 变量的含义做调整: rear 指向队列的最后一个元素的后一个位置,因为希望空出一个位置
    //rear 的初始值=0
    private int rear; //队列尾
    private int[] arr; //该数组用于存放数据,模拟队列

    //创建队列的构造器
    public CircleArray(int arrMaxSize) {
    
    
        maxSize = arrMaxSize;
        arr = new int[maxSize];
    }

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

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

    //添加数据到队列
    public void addQueue(int n) {
    
    
        //判断队列是否满
        if(isFull()){
    
    
            throw new RuntimeException( "队列满,不能加入数据" );
        }
        arr[rear] = n;
        //将rear 后移,此处必须考虑取膜
        rear = (rear + 1) % maxSize;
    }

    //获取队列的数据,出队列。
    public int getQueue() {
    
    
        //判断队列是否空
        if(isEmpty()){
    
    
            //通过抛出异常
            throw new RuntimeException( "队列空,不能取数据" );
        }
        //front 是指向队列的第一个元素
        //1. 先把front 对应的值保存到一个临时变量
        int value = arr[front];
        //2. 将front后移。
        front = (front + 1) % maxSize;
        //3. 将临时保存的变量返回
        return value;
    }

    //显示队列的所有数据
    public void showQueue(){
    
    
        //遍历
        if(isEmpty()){
    
    
            System.out.println("队列空的,没有数据");
            return;
        }
        // 从front开始遍历,遍历多少个元素
        //
        for (int i = front; i < front + size(); i++) {
    
    
            System.out.printf( "arr[%d]=%d\n", i % maxSize, arr[i % maxSize] );
        }
    }

    //求出当前队列有效数据的个数
    public int size() {
    
    
        return (rear + maxSize - front) % maxSize;
    }

    //显示队列的头数据,注意不是取出数据
    public int headQueue (){
    
    
        //判断
        if(isEmpty()){
    
    
            throw new RuntimeException( "队列空的,没有数据!" );
        }
        return arr[front];
    }
}


总结:本文通过数组的方式来实现对队列的模拟,包含了对队列的增、删、等基本操作的说明以及代码实现。实现了数组模拟基本的单向队列和使用数组模拟环形队列。

猜你喜欢

转载自blog.csdn.net/qq_41497756/article/details/108668655