LinkedList原始碼分析(二)

胖若倆人發表於2018-06-07

LinkedList原始碼分析(二)

這篇文章來自我的部落格

正文之前

在上一篇文章中已經講述了連結串列基於列表的基本用法,所以,這一篇文章要講述連結串列基於佇列的基本用法

主要內容

  1. 基本概念
  2. 基於單向佇列的操作
  3. 基於雙向佇列的操作

正文

1. 基本概念

既然是基於佇列的操作,就要介紹一下佇列的概念:

單向佇列(Queue)是先進先出(First-In-First-Out)的線性結構,就好比我們生活中的排隊,先來排隊的人先辦理事務,佇列只支援在隊尾新增元素,在隊首刪除元素

雙向佇列(Deque,double-ended queue),也叫做雙端佇列,是基於佇列和棧的結構,可以在佇列兩邊進行新增和刪除操作

在連結串列中使用基於佇列的方法時,其實是呼叫上一篇文章中定義的方法,只不過在不同的位置使用來達到模擬的效果

2. 基於單向佇列的操作

主要內容:

  • 新增節點 offer()
  • 刪除節點
    poll() remove()
  • 查詢元素 peek() element()

在這幾個基本的操作中,新增和刪除是針對節點而言,而查詢雖然是針對節點,但是查詢的結果是返回節點中的元素的

1. 新增節點

使用add(),在add()中又有linkLast(),結果就是在末尾新增節點:

    /**
     * Adds the specified element as the tail (last element) of this list.
     *
     * @param e the element to add
     * @return {@code true} (as specified by {@link Queue#offer})
     * @since 1.5
     */
    public boolean offer(E e) {
        return add(e);
    }
複製程式碼
2. 刪除節點

刪除元素有兩種方法,區別就是,一個先判斷元素是否為null,而另一個不進行判斷:

  • poll()

先判斷元素是否存在,然後呼叫unlinkFirst(),刪除第一個節點:

    /**
     * Retrieves and removes the head (first element) of this list.
     *
     * @return the head of this list, or {@code null} if this list is empty
     * @since 1.5
     */
    public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
複製程式碼
  • remove()

呼叫removeFirst(),最終也是呼叫unlinkFirst(),刪除第一個節點:

    /**
     * Retrieves and removes the head (first element) of this list.
     *
     * @return the head of this list
     * @throws NoSuchElementException if this list is empty
     * @since 1.5
     */
    public E remove() {
        return removeFirst();
    }
複製程式碼
3. 修改元素

在基於佇列的操作中是沒有修改元素的方法的,不管是單向還是雙向佇列:

4. 查詢元素
  • peek()

先檢查節點是否為空,若不為空就返回第一個節點的元素:

    /**
     * Retrieves, but does not remove, the head (first element) of this list.
     *
     * @return the head of this list, or {@code null} if this list is empty
     * @since 1.5
     */
    public E peek() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
複製程式碼
  • element()

直接返回第一個節點的元素,可能會丟擲異常:

    /**
     * Retrieves, but does not remove, the head (first element) of this list.
     *
     * @return the head of this list
     * @throws NoSuchElementException if this list is empty
     * @since 1.5
     */
    public E element() {
        return getFirst();
    }
複製程式碼

3. 基於雙向佇列的操作

主要內容:

  • 新增節點 offerFirst() offerLast() push()
  • 刪除節點 pollFirst() pollLast() pop() removeFirstOccurrence() removeLastOccurrence()
  • 查詢元素 peekFirst() peekLast()
1. 新增節點
  • 新增節點至隊首

呼叫addFirst(),然後是linkFirst(),新增節點至隊首:

    public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }
複製程式碼
  • 新增節點至隊尾

和上述一樣,都是連著再次呼叫其他方法來達到效果:

    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }
複製程式碼
  • 模擬棧操作的新增一個節點至隊首,最終還是呼叫linkFirst():
    public void push(E e) {
        addFirst(e);
    }
複製程式碼
2. 刪除節點
  • 刪除第一個節點,呼叫unlinkFirst():
    public E pollFirst() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
複製程式碼
  • 刪除最後一個節點, 呼叫unlinkLast():
    public E pollLast() {
        final Node<E> l = last;
        return (l == null) ? null : unlinkLast(l);
    }
複製程式碼
  • 模擬棧操作的刪除第一個節點,最終還是呼叫unlinkFirst():
    public E pop() {
        return removeFirst();
    }
複製程式碼
  • 刪除某個節點的元素,在它第一次出現的位置

remove()方法是從隊首還是進行遍歷,如果找到與指定元素相同的節點元素,就返回,所以是在元素第一次出現的位置將其刪除:

   public boolean removeFirstOccurrence(Object o) {
        return remove(o);
    }
複製程式碼
  • 刪除某個節點的元素,在它最後一次出現的位置

其實這個方法的寫法和remove()是類似的,只不過是從隊尾開始遍歷:

    public boolean removeLastOccurrence(Object o) {
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }
複製程式碼
3. 查詢元素
  • 得到隊首、隊尾的節點的元素
    public E peekFirst() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }

    public E peekLast() {
        final Node<E> l = last;
        return (l == null) ? null : l.item;
    }
複製程式碼

這一篇文章就結束了,接下來會是迭代器的分析,作為連結串列系列文章的最後一篇,然後會有一個關於ArrayListLinkedList的對比分析

相關文章