美文网首页数据结构
数据结构003之队列

数据结构003之队列

作者: 吴维 | 来源:发表于2020-08-29 01:08 被阅读0次

    什么是队列?

    队列是一个有序列表,可以用数组或链表实现
    遵循先入先出的(First in First Out)原则。即:先存入队列的数据,要先取出。后存入的要后取出
    当队列中插入元素后,此元素可以被读取
    当队列中元素被取出后,此元素就会从队列中移出

    队列初始状态图解

    image.png

    从上图可以看出数组队列中包含元素:
        1. 队列头指针,用来记录当前队列可读取的元素位置
        2. 队列尾指针,用来记录当前队列可以写入的元素位置
        3. 队列的容量大小(数组容量)
        4. 队列中的数组
        5. 队列中可读取的元素数量

    队列应该有那些方法?

    一个队列应该需要那些操作?
        1. 将元素插入队列方法 enQueue(item) 操作tail尾指针写入元素数据
        2. 获取队列元素方法 E deQeueu() 操作front头指针从队列中获取元素数据
        3. 查看队列当前头指针的元素 E showFront()
        4. 获取队列中的元素数量 int getSize()
        5. 判断队列是否为空 boolean isEmpty()

    队列实战案例一:数组实现队列

    数组实现队列思路分析:

    1. 定义队列数组,定义头指针与尾指针和size
    2. 初始化队列数组,头指针,尾指针,通过构造函数完成
    3. 编写enQueue(item)添加元素操作
      添加元素需要判断队列是否已经满,没有满才可以插入元素
      如何判断队列满了?
      如果tail==capacity表示队列满了
      如何队列满了应该怎么办?
      扩容,第一个案例我们先不使用扩容来操作,后面再进行扩容操作
    4. 编写deQueue()取出元素操作
      取出元素操作需要判断列表是否为空,为空表示没有数据
    5. 编写getSize()获取元素数量操作
    6. 编写判断队列是否为空的操作
      如何判断队列中没有元素?
      如果头指针与尾指针相等,则表示没有元素,所以tail==front就表示队列为空
    • 编写队列接口
    /**
     * @author 凡人静水
     * 注释: 此接口定义队列的接口方法
     */
    public interface Queue {
        //添加元素到队列
        int enQueue(int e);
    
        //从队列中取出元素
        int deQeueu();
    
        //查看队列头元素
        int showFront();
    
        //查看有多少元素可读
        int getSize();
    
        //判断队列是否为空
        boolean isEmpty();
    }
    
    • 编写队列实现
    /**
     * @author 凡人静水
     * 注释: 数组实现队列
     */
    public class IntArrayQueue implements Queue {
    
        //1.定义队列数组,定义头指针与尾指针和size
        private int[] arr;
        private int capacity;
        private int front;
        private int tail;
        private int size;
    
        //2.初始化队列数组,头指针,尾指针,通过构造函数完成
        public IntArrayQueue(int capacity) {
            this.arr = new int[capacity];
            this.capacity = capacity;
            this.front = 0;
            this.tail = 0;
            this.size = 0;
        }
    
        public IntArrayQueue() {
            //默认创建大小为5的数组
            this(5);
        }
    
    
        //3.编写enQueue(item)添加元素操作
        public void enQueue(int e) {
            //添加元素需要判断队列是否已经满,没有满才可以插入元素
            if (tail == capacity) {
                throw new RuntimeException("队列满了...请扩容");
            }
            //添加元素,只需要改变尾指针即可
            arr[tail] = e;
            //插入元素后,尾指针需要向前移动一位,准备好下次元素插入的位置
            tail++;
            //插入元素时需要给size++,表示队列中元素个数
            size++;
        }
    
        //4.编写deQueue()取出元素操作
        public int deQeueu() {
            //取出元素操作需要判断列表是否为空,为空表示没有数据
            if (isEmpty()) {
                throw new RuntimeException("队列中没有元素...");
            }
    
            int result = arr[front];
            //取出数据通过头指针,取出后移动到下一个读取的位置
            front++;
            //取出元素时需要给size--,表示队列中元素个数
            size--;
            return result;
        }
    
        //7.查看队列的头部
        public int showFront() {
            if (isEmpty())
                System.out.println("队列中没有元素....");
            return arr[front];
        }
    
        //5.编写getSize()获取元素数量操作
        public int getSize() {
            return size;
        }
    
        //6.编写判断队列是否为空的操作
        public boolean isEmpty() {
            return tail == front;
        }
    
    
        @Override
        public String toString() {
            StringBuilder res = new StringBuilder();
            res.append(String.format("Array: size = %d ,capacity=%d , front=%d , tail=%d\n", size, capacity, front, tail));
            res.append("[");
            for (int i = front; i < tail; i++) {
                res.append(arr[i]);
                if (i != (tail - 1) ){
                    res.append(",");
                }
            }
            res.append("]");
            return res.toString();
        }
    }
    
    • 编写测试
     public static void main(String[] args) {
            IntArrayQueue queue = new IntArrayQueue(10);
            System.out.println("添加数据:");
            for (int i = 0; i < 3; i++) {
                try {
                    queue.enQueue(i);
                } catch (Exception e) {
                    break;
                }
                System.out.println(queue);
                System.out.println("----------------------------------");
            }
            int result = queue.deQeueu();
            System.err.println("取出数据:" + result);
            System.err.println(queue);
            result = queue.deQeueu();
            System.err.println("取出数据:" + result);
            System.err.println(queue);
        }
    
    • 测试结果
    添加数据:
    Array: size = 1 ,capacity=10 , front=0 , tail=1
    [0]
    ----------------------------------
    Array: size = 2 ,capacity=10 , front=0 , tail=2
    [0,1]
    ----------------------------------
    Array: size = 3 ,capacity=10 , front=0 , tail=3
    [0,1,2]
    ----------------------------------
    取出数据:0
    Array: size = 2 ,capacity=10 , front=1 , tail=3
    [1,2]
    取出数据:1
    Array: size = 1 ,capacity=10 , front=2 , tail=3
    [2]
    

    图解队列执行流程

    第一次添加元素


    image.png

    第二次添加元素


    image.png
    第三次添加元素
    image.png

    第一次取出元素


    image.png
    第二次取出元素
    image.png

    数组队列的问题

    通过上面的测试结果,发现以下问题:

    当取出数据后,发现front的值为2,此时,队列的前两个空间没有被使用,而之后插入也都不会插入到这两个空间中,所以被浪费掉了!
    结论:只要取出数据后,空间就没办法再用了,只能通过扩容来维护新的数组,这肯定不是好的解决方案
    解决方案:通过环形(循环)队列来解决上面的问题,下一章我们看看环形队列如何实现,及其实现原理

    搜索公众号,查看更多专题文章:javastu

    相关文章

      网友评论

        本文标题:数据结构003之队列

        本文链接:https://www.haomeiwen.com/subject/hksrsktx.html