數據結構--隊列Queue的實現原理

目錄

一、what is 隊列?

1.1  現實中的隊列

1.2  代碼中的隊列

1.3  隊列分類

1.4  隊列適用範圍

二、隊列使用

二、隊列的實現


一、what is 隊列?

1.1  現實中的隊列

 隊列隊列就是要排隊啊,排隊就是要等待啊,現實中有哪些需要等待的?

你們有沒有這樣的經歷,在用電腦的時候,鼠標點什麼似乎都沒用,雙擊任何快捷方式都不動彈,處於疑似死機的狀態。但等一會後,電腦又似乎醒過來了,又把你剛纔點擊的所有操作全部按順序執行一遍。這其實是因爲操作系統中的多個程序因需要通過一個通道輸出,而按先後次序排隊等待造成的。

還有你在超市的某個收銀通道排隊付款時,也是一樣按照排隊順序來進行。

還有你給某個客服打電話時,經常遇到“人工坐席忙,請稍後再撥”的提示,那也是因爲客戶太多而客服少,只有等上一個完事才能處理你的業務

.....

還有好多隊列的例子,那我們可以概括一下這些例子的一些特點:

  • 你在排隊的時候,永遠是在隊尾加入(插隊估計要被打)
  • 隊首的人付完錢會離開
  • 排在你前面的人先離開

 

1.2  代碼中的隊列

代碼中的隊列和現實中的隊列思想上實際是一致的:

  • 隊列是一種先進先出(First in First Out)的線性表,簡稱FIFO
  • 允許插入的一端稱爲隊尾,允許刪除的一端稱爲隊頭
  • 順序插入,不允許插隊

 

1.3  隊列分類

按照存儲方式(既然是線性表,按照存儲方式那就有兩種存儲方式):

  1. 基於數組的順序存儲方式
  2. 基於鏈表的鏈式存儲方式

按照實現方式也分爲:

  1. 單向隊列(Queue):只能在一端插入數據,另一端刪除數據
  2. 雙向隊列(Deque):每一端都可以進行插入數據和刪除數據操作

 

1.4  隊列適用範圍

如果是一些及時消息的處理,並且處理時間很短的情況下是不需要使用隊列的。

如果在消息處理的時候特別費時間,這個時候如果有新的消息來了,就只能處於阻塞狀態,造成用戶等待。這個時候在項目中引入隊列是十分有必要的。當我們接受到消息後,先把消息放到隊列中,然後再用新的線程進行處理,這個時候就不會有消息的阻塞了。

 

二、隊列使用

Queue接口與List、Set同一級別,都是繼承了Collection接口。

Queue的實現有PriorityQueue、ArrayDeque、LinkedList。其中ArrayDeque、LinkedList是實現的其子接口Deque。

Queue中包含的方法如下:

  • add(E e)將指定元素加入到隊列尾部,會拋出IllegalStateException異常
  • offer(E e) 將指定元素加入到隊列尾部,會返回 false
  • remove() 返回隊列頭部元素並刪除,如果隊列爲空,會拋NoSuchElementException
  • poll() 返回隊列頭部元素並刪除,如果隊列爲空,返回null
  • element() 返回隊列頭部元素不刪除,如果隊列爲空,會拋NoSuchElementException
  • peek() 返回隊列頭部元素不刪除,如果隊列爲空,返回null
ArrayDeque和LinkedList都是Queue的實現類,實際Queue的add()方法就是調用的ArrayDeque或LinkedList的add()方法,Queue 接口中的方法在兩者中都有具體實現,儘管實現方式不同,但是因爲共同接口Queue的原因,使用方法是一樣的,這就是面向接口的好處(不管你咋實現,我對外提供的API是統一的)。
 
基於ArrayDeque:(構造時ArrayDeque可以傳入大小,不傳默認數組大小爲16)
public class Demo {
    public static void main(String[] args) {
        Queue queue = new ArrayDeque();
        queue.offer("1");
        queue.offer("2");
        queue.offer("3");
        queue.add("4");
        queue.add("5");
        queue.add("6");
        queue.stream().forEach(item ->{
            System.out.println(item);
        });
        // 返回隊首的元素
        Object firstElement = queue.element();
        System.out.println("隊首的元素:" + firstElement);
        // 移除並返回隊列頭部的元素
        System.out.println("移除並返回隊列頭部的元素:" + queue.remove());
        System.out.println("移除後:");
        queue.stream().forEach(item ->{
            System.out.println(item);
        });
    }
}

 基於LinkedList:

public class Demo {
    public static void main(String[] args) {
        Queue queue = new LinkedList();
        queue.offer("1");
        queue.offer("2");
        queue.offer("3");
        queue.add("4");
        queue.add("5");
        queue.add("6");
        queue.stream().forEach(item ->{
            System.out.println(item);
        });
        // 返回隊首的元素
        Object firstElement = queue.element();
        System.out.println("隊首的元素:" + firstElement);
        // 移除並返回隊列頭部的元素
        System.out.println("移除並返回隊列頭部的元素:" + queue.remove());
        System.out.println("移除後:");
        queue.stream().forEach(item ->{
            System.out.println(item);
        });
    }
}

 兩種結果一樣:

1
2
3
4
5
6
隊首的元素:1
移除並返回隊列頭部的元素:1
移除後:
2
3
4
5
6

LinkedList類實現了Queue接口,因此我們可以把LinkedList當成Queue來用。

 

二、隊列的實現

前面說過隊列按照存儲結構可以分爲順序隊列和鏈式隊列。順序隊列採用數組實現,鏈式隊列採用鏈表的方式實現。

順序隊列實現:

/**
 * Feng, Ge 2020/3/13 0013 16:18
 */
public class MyArrayQueue {
    private Object[] data;
    // 最大容量
    private int maxSize = 0;
    // 隊首位置
    private int head = 0;
    // 隊尾位置
    private int tail = 0;

    /**
     * 構造方法,初始化隊列大小
     */
    public MyArrayQueue(int size) {
        data = new Object[size];
        maxSize = size;
    }

    public MyArrayQueue() {
        this(6);
    }

    /**
     * 判斷隊列是否爲空
     */
    public boolean isEmpty() {
        return tail == head ? true : false;
    }

    /**
     * 判斷隊列是否已滿
     */
    public boolean isMax() {
        return tail >= maxSize ? true : false;
    }

    /**
     * 加入隊列
     */
    public boolean offer(Object obj) {
        if (isMax()) {
            System.out.println("隊列已存滿");
            return false;
        }
        // 隊尾加入元素
        data[tail] = obj;
        tail++;
        return true;
    }

    /**
     * 刪除隊首元素,並返回隊首元素
     */
    public Object poll() {
        if (isEmpty()) {
            System.out.println("隊列爲空");
        }
        Object fisrtElement = data[head];
        // 從 head+1 位置開始到tail位置的數據向前移動一位
        System.arraycopy(data, head+1, data, head, tail-1);
        tail--;
        return fisrtElement;
    }


    public static void main(String[] args) {
        MyArrayQueue myArrayQueue = new MyArrayQueue();
        myArrayQueue.offer(0);
        myArrayQueue.offer(1);
        myArrayQueue.offer(2);
        myArrayQueue.offer(3);
        myArrayQueue.offer(4);
        myArrayQueue.offer(5);
        System.out.println("添加順序:");
        for (int i = 0; i < myArrayQueue.data.length; i++) {
            System.out.println(myArrayQueue.data[i]);
        }
        System.out.println("隊首元素:" + myArrayQueue.poll());
        myArrayQueue.offer(6);
        System.out.println("刪除後再添加的順序:");
        for (int i = 0; i < myArrayQueue.data.length; i++) {
            System.out.println(myArrayQueue.data[i]);
        }
    }
}
添加順序:
0
1
2
3
4
5
隊首元素:0
刪除後再添加的順序:
1
2
3
4
5
6


鏈式隊列實現:

這個實現和之前寫過的一篇 《JAVA集合類(詳解)》裏的LinkedList幾乎一樣,可以跳過去看看,地址:https://blog.csdn.net/weixin_41231928/article/details/103413167

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章