教你如何使用Java手寫一個基於鏈表的隊列


  在上一篇博客【教你如何使用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) + "}";
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM