在上一篇博客【教你如何使用Java手寫一個基於數組的隊列】中已經介紹了隊列,以及Java語言中對隊列的實現,對隊列不是很了解的可以我上一篇文章。那么,現在就直接進入主題吧。
這篇博客主要講解的是如何使用單鏈表實現一個簡單版的隊列。單向鏈表隊列是屬於非循環隊列,同時隊列的長度是不受限制的,也就是說添加數據的速度比拉取數據的速度快時,隊列的長度是無限增長的。單鏈隊列其本質就是一個鏈表,只不過是在獲取或添加數據的時候跟普通的鏈表有所區別,隊列在獲取數據的同時也將該節點刪除,並且每次獲取數據都是從表頭獲取,普通鏈表可以獲取任意節點的數據;隊列在增加數據時總是添加到鏈表的尾部,而普通的鏈表則是可以在鏈表的任意地方插入一個節點。
一、隊列數據結構
該隊列的結構夠多個節點構成,每個節點都有一個指向下一個節點的指針,使得所有的節點都能夠相連,形成一個鏈表。具體結構如下如:

Java實現:
static class Node{ Object item; Node next; public Node(Object item, Node next) { this.item = item; this.next = next; } }
其實就創建一個靜態內部類即可,類中item是用來存儲數據的,next是指向下一個node節點,最后一個節點的next為空。
二、屬性
head:鏈表表頭,拉取或遍歷數據都是從這里開始的。
tail:鏈表表尾,每次添加數據都添加到tail的后面,變成新的tail
size:隊列長度
//表頭 private Node head; //表尾 private Node tail; //隊列長度 private int size;
三、添加數據
public void offer(Object item){ Node n = new Node(item,null); if (tail == null){ head = tail = n; }else { tail.next = n; tail = n; } size++; }
用代碼實現隊列的添加操作看起是很簡單的,無非就是將新節點添加到表尾,然后把新節點設置成新的表尾。
四、拉取數據
public Object poll(){ if (head == null) return null; Node h = head; //將拉取的節點的下一個節點變成新的表頭 head = head.next; //把舊的表頭的下一個節點指向設置為null,讓gc回收 h.next = null; //隊列為空 if (head == null) tail = null; size--; return h.item; }
五、查看數據
public Object peek(){ return head == null ? null : head.item; }
查看數據看的是表頭的數據,但是跟poll方法的區別是該方法不會刪除表頭的數據。
六、清空列表
public void clear(){ size = 0; Node h = head; while (h != null){ Node temp = h.next; h.next = null; h = temp; } head = tail = null; }
七、基於數組的隊列和鏈表的隊列的區別
1、前者是有邊界的循環隊列,后者則是沒有邊界的非循環隊列。
2、前者在添加數據時無需創建新對象,性能消耗相對較小,后者每次添加數據都需要創建新對象。
3、后者每個節點都維護了一個鏈,所以所需內存也相對較大。
4、如果添加速度大於拉取速度,前者在達到邊界后可能會無法添加數據,后者則沒有這個問題。
八、完整代碼
/** * 基於鏈表實現的隊列 */ public class LinkQueue { //表頭 private Node head; //表尾 private Node tail; //隊列長度 private int size; public LinkQueue(){} public void offer(Object item){ Node n = new Node(item,null); if (tail == null){ head = tail = n; }else { tail.next = n; tail = n; } size++; } public Object poll(){ if (head == null) return null; Node h = head; //將拉取的節點的下一個節點變成新的表頭 head = head.next; //把舊的表頭的下一個節點指向設置為null,讓gc回收 h.next = null; //隊列為空 if (head == null) tail = null; size--; return h.item; } public Object peek(){ return head == null ? null : head.item; } public void clear(){ size = 0; Node h = head; while (h != null){ Node temp = h.next; h.next = null; h = temp; } head = tail = null; } public int size(){return size;} static class Node{ Object item; Node next; public Node(Object item, Node next) { this.item = item; this.next = next; } } @Override public String toString() { if (size == 0) return "{}"; StringBuilder builder = new StringBuilder(size + 2); Node h = head; builder.append("{"); while (h != null){ builder.append(h.item); builder.append(", "); h = h.next; } return builder.substring(0,builder.length() -2) + "}"; } }
