天天看點

java集合(十)---Queue與PriorityQueue、Deque源碼解析

一、Queue與PriorityQueue、Deque的圖如下所示:

java集合(十)---Queue與PriorityQueue、Deque源碼解析

(1)從上圖可以看出,Queue接口有兩個實作類:PriorityQueue與Deque

(2)ArrayDeque是Deque的一個典型的實作類

二、Queue:

Queue是什麼?

(1)Queue是具有隊列特性的接口

(2)Queue具有“先進先出(FIFO)”的特性

(3)Queue所有新元素都插入隊列的末尾,移除元素都移除隊列的頭部

(4)注意:隊列不允許随機通路隊列中的元素

(5)Queue接口中定義了如下幾個方法:

java集合(十)---Queue與PriorityQueue、Deque源碼解析

三、Deque:

Deque是什麼?

(1)Deque是一個雙端隊列

(2)Deque繼承自Queue

(3)Deque具有先進先出或後進先出的特點

(4)Deque支援所有元素在頭部和尾部進行插入、删除、擷取

(5)Deque中定義了如下幾個方法:

java集合(十)---Queue與PriorityQueue、Deque源碼解析
java集合(十)---Queue與PriorityQueue、Deque源碼解析

從上面可以看出,Deque不僅可以當成雙端隊列使用,而且可以被當成棧來使用,因為該類包含了pop、push兩個方法。

ArrayDeque:

Deque接口提供了一個典型的實作類:ArrayDeque。

從該名稱可以看出,它是一個基于數組實作的雙端隊列,建立Deque時同樣可以指定numElements參數,該參數用于指定Object[]數組的長度,如果不指定numElements參數,Deque底層數組長度為16.

public class ArrayDeque<E> extends AbstractCollection<E>
                       implements Deque<E>, Cloneable, Serializable{}

           

下面分别舉一下例子:

addAll©:

public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
        //将元素全部加到ArrayDeque中。其中add 方法調用了addLast 後面會對addLast源碼進行分析
    }

public boolean add(E e) {
        addLast(e);
        return true;
    }  

           

addFirst:

public void addFirst(E e) {
        if (e == null)
            throw new NullPointerException();
        //如果加入的元素為null 抛出空指針異常。    
        elements[head = (head - 1) & (elements.length - 1)] = e;
        //head值先減1,然後将元素放到head位置
        if (head == tail)
            doubleCapacity();
            //如果head == tail 将數組大小擴大一倍
    }

           

相應解釋:

①addFirst 加一個元素時,head都會先減1,然後再放元素。head初始值為 0。

② (head - 1) & (elements.length - 1) 使head的值在【0, elements.length - 1】範圍之内,同時可以循環利用數組裡面的空間,head一直圍着數組轉圈。

③如果tail==head 的時候,由上圖可知數組中的元素已經滿了,是以會将數組的擴大一倍。初始時tail=0

addLast:

public void addLast(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[tail] = e;
        //将e的值放到tail位置,然後tail+1,如果數組滿了擴容一倍。
        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
            doubleCapacity();
    }

           

addLast 時操作 tail 在tail位置加入元素,如果數組已經滿了就擴容一倍

pollFirst:

public E pollFirst() {
        int h = head;
        E result = elements[h]; //将elements[h]指派給result。
        if (result == null)
            return null;//如果result 為null 直接傳回
        elements[h] = null;     // 如果result不為null 将elements[h] 指派為null
        head = (h + 1) & (elements.length - 1);// head+1.
        return result;
    }
           

下面是一個使用pollFirst的例子:

public class DequeDemo {
    public static void main(String[] args) {
        Integer []arr={1,2,3,4,5,6,7,8};
        List<Integer> list=Arrays.asList(arr);
         ArrayDeque<Integer> aDeque=new ArrayDeque<Integer>(list);
         for(int i=0;i<3;i++)
             aDeque.addFirst(arr[i]);
             //往雙端隊列中添加元素
         while(!aDeque.isEmpty())
            aDeque.pollFirst();
        //使用pollFirst()删除。
    }

}
           

pollLast:

public E pollLast() {
        int t = (tail - 1) & (elements.length - 1);
        E result = elements[t];
        //tail 先減1然後擷取tail中的内容。
        if (result == null)
            return null;//如果result 為null 直接傳回
        elements[t] = null;//否則将t位置的元素清空再傳回result
        tail = t;
        return result;
    }
           

下面是一個使用pollLast的例子:

public class DequeDemo {
    public static void main(String[] args) {
        Integer []arr={1,2,3,4,5,6,7,8};
        List<Integer> list=Arrays.asList(arr);
         ArrayDeque<Integer> aDeque=new ArrayDeque<Integer>(list);
         for(int i=0;i<3;i++)
             aDeque.addFirst(arr[i]);
             //添加元素
         while(!aDeque.isEmpty())
            aDeque.pollLast();
        //删除元素
    }

}
           

removeFirst():

public E removeFirst() {
        E x = pollFirst();
        //調用pollFirst()
        if (x == null)
            throw new NoSuchElementException();
            //當pollFirst()傳回null抛出null 元素異常。
        return x;
    }
           

由上面代碼可知其實removeFirst() 就是調用pollFirst() 不同之處在于在當pollFirst()傳回null removeFirst() 抛出 null 元素異常。

removeLast():

public E removeLast() {
        E x = pollLast();
        //調用 pollLast() 當pollLast()傳回null抛出null 元素異常。
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }
           

由上面代碼可知其實removeLast() 就是調用pollLast() 不同之處在于在當pollLast()傳回null removeLast() 抛出 null 元素異常

add(E e):

public boolean add(E e) {
 //調用 addLast(e); 添加成功傳回 true。
        addLast(e);
        return true;
    }

           

remove():

public E remove() {
        return removeFirst();
    }
           

四、PriorityQueue:

(1)PriorityQueue是一個比較标準的隊列實作類。是因為:PriorityQueue儲存隊列元素的順序并不是按照加入隊列的順序,而是按照隊列元素的大小進行重新排列。

(2)PriorityQueue不允許插入null元素,它還需要對隊列元素進行排序。

(3)PriorityQueue有兩種排序方式:自然排序 和 定制排序。

(4)自然排序:其必須實作Comparable接口,而且應該是同一個類的多個執行個體,否則會導緻ClassCaseException異常

(5)定制排序:要傳入一個Comparator對象,該對象負責對隊列的所有元素進行排序,采用定制排序時不要求隊列元素實作Comparable接口

(6)PriorityQueue與TreeSet對元素的要求基本一緻,可以參考TreeSet。

(7)優先隊列PriorityQueue具有小根堆性質,該類在邏輯上是使用堆實作的,即完全二叉樹;該類在存儲記憶體時,是将其轉換為數組存儲的

(8)完全二叉樹是指:葉節點隻能出現在最下層和次下層,并且最下面一層的結點都集中在該層最左邊的若幹位置的二叉樹。下圖顯示一棵完全二叉樹和一棵非完全二叉樹。如下圖:(左邊是一顆完全二叉樹,右邊是一顆不完全二叉樹)

java集合(十)---Queue與PriorityQueue、Deque源碼解析
java集合(十)---Queue與PriorityQueue、Deque源碼解析

(9)PriorityQueue總是先輸出根節點的值,然後調整樹使之繼續成為一棵完全二叉樹,保證每次輸出的根節點總是整棵樹優先級最高的,要麼數值最小要麼數值最大

成員方法源碼解析:

1. public PriorityQueue()無參構造方法:

public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }
           

源碼解析:

  • 功能:建立一個初始容量為11(DEFAULT_INITIAL_CAPACITY)的PriorityQueue,其中隊列中元素的比較方式是按照自然排序的方式進行比較
  • 源碼思路:
    • 調用該類的帶有兩個參數的構造方法實作建立對象

2. public PriorityQueue(int initialCapacity)方法

public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }
           

源碼解析:

  • 功能:建立一個帶有初始容量的優先隊列,其中隊列中元素的比較方式是按照自然排序的方式進行比較
  • 源碼思路:
    • 調用該類的帶有兩個參數的構造方法實作建立對象

3. public PriorityQueue(Comparator<? super E> comparator)方法

public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }
           

源碼解析:

  • 功能:建立一個帶有比較器的優先隊列,其中隊列的容量為預設的初始容量DEFAULT_INITIAL_CAPACITY(11)
  • 源碼思路:
    • 調用該類的帶有兩個參數的構造方法實作建立對象

4. public PriorityQueue(int initialCapacity,Comparator<? super E> comparator)方法

public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }
           

源碼解析:

  • 功能:建立一個帶有比較器,帶有自定義隊列容量的優先隊列
  • 源碼思路:
    • (1)首先判斷自定義隊列容量是否小于1,小于1時抛出異常
    • (2)給隊列的數組queue建立容量為initialCapacity的記憶體空間
    • (3)将比較器傳遞給目前對象

5. public PriorityQueue(Collection<? extends E> c)方法

@SuppressWarnings("unchecked")
    public PriorityQueue(Collection<? extends E> c) {
        if (c instanceof SortedSet<?>) {
            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
            this.comparator = (Comparator<? super E>) ss.comparator();
            initElementsFromCollection(ss);
        }
        else if (c instanceof PriorityQueue<?>) {
            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
            this.comparator = (Comparator<? super E>) pq.comparator();
            initFromPriorityQueue(pq);
        }
        else {
            this.comparator = null;
            initFromCollection(c);
        }
    }
           

源碼解析:

  • 功能:建立一個優先隊列,隊列中包含集合c中的元素,如果集合c的類型是SortedSet或者是PriorityQueue類型,那麼建立的優先隊列中元素的比較方法按照集合c的比較方法進行比較,否則按照自然順序進行比較
  • 源碼思路:
    • (1)判斷如果集合c屬于SortedSet類型,則将集合c強制轉換為SortedSet類型,将c的比較器指派給目前優先隊列對象的比較器,然後調用initElementsFromCollection()方法,建立優先隊列
    • (2)如果集合c不屬于SortedSet類型,而屬于PriorityQueue類型,則将集合c強制轉換為PriorityQueue類型,将c的比較器指派給目前優先隊列對象的比較器,然後調用initFromPriorityQueue()方法,建立優先隊列
    • (3)如果(1)和(2)中的判斷條件都不滿足,則将目前優先隊列的比較器設定為空,調用initFromCollection()方法,建立優先隊列

6. public PriorityQueue(PriorityQueue<? extends E> c)方法

@SuppressWarnings("unchecked")
    public PriorityQueue(PriorityQueue<? extends E> c) {
        this.comparator = (Comparator<? super E>) c.comparator();
        initFromPriorityQueue(c);
    }
           

源碼解析:

  • 功能:建立一個優先隊列,隊列中包含優先隊列c中的元素
  • 源碼思路:
    • (1)将c的比較器指派給目前隊列的比較器
    • (2)調用initFromPriorityQueue()方法,建立優先隊列

7. public PriorityQueue(SortedSet<? extends E> c)方法

@SuppressWarnings("unchecked")
    public PriorityQueue(SortedSet<? extends E> c) {
        this.comparator = (Comparator<? super E>) c.comparator();
        initElementsFromCollection(c);
    }
           

源碼解析:

  • 功能:建立一個優先隊列,隊列中包含SortedSet類型對象c中的元素
  • 源碼思路:
    • (1)将c的比較器指派給目前對象的比較器中
    • (2)調用initElementsFromCollection方法,建立優先隊列

8. private void initFromPriorityQueue(PriorityQueue<? extends E> c)方法

private void initFromPriorityQueue(PriorityQueue<? extends E> c) {
        if (c.getClass() == PriorityQueue.class) {
            this.queue = c.toArray();
            this.size = c.size();
        } else {
            initFromCollection(c);
        }
    }
           

源碼解析:

  • 功能:這是一個子方法,實作的功能是将優先隊列c中的數組和數組大小指派給目前優先隊列對象中
  • 源碼思路:
    • (1)首先判斷c的類型是否是PriorityQueue類型,如果是則将優先隊列c中的數組和數組大小指派給目前優先隊列對象中
    • (2)如果c的類型不是PriorityQueue類型,則調用initFromCollection()方法

9. private void initElementsFromCollection(Collection<? extends E> c)方法

private void initElementsFromCollection(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if (a.getClass() != Object[].class)
            a = Arrays.copyOf(a, a.length, Object[].class);
        int len = a.length;
        if (len == 1 || this.comparator != null)
            for (int i = 0; i < len; i++)
                if (a[i] == null)
                    throw new NullPointerException();
        this.queue = a;
        this.size = a.length;
    }
           

源碼解析:

  • 功能:将集合c中的數組值和數組大小傳遞給目前優先隊列對象中
  • 源碼思路:
    • (1)首先定義個Object類型的數組a,将c中的元素轉換到數組a中
    • (2)判斷a集合的類型是否是Object類型的數組,如果不是,通過調用Arrays類的copyOf方法,将其轉換為Object類型的數組
    • (3)定義一個整型變量len,用于存儲數組a的長度
    • (4)如果數組長度為1或者疊代器不為null時,進行循環操作,循環的内容是:判斷數組中是否有null元素,如果有則抛出異常,如果所有元素都不為null,則執行(5)
    • (5)将數組a的值指派給目前優先隊列的queue,将數組的長度指派給目前優先隊列的size

10. private void initFromCollection(Collection<? extends E> c)方法

private void initFromCollection(Collection<? extends E> c) {
        initElementsFromCollection(c);
        heapify();
    }
           

源碼解析:

  • 功能:将集合c中的元素指派給目前優先隊列
  • 源碼思路:
    • (1)調用initElementsFromCollection()方法實作指派操作
    • (2)調用heapify()方法

11. private void grow(int minCapacity)方法

private void grow(int minCapacity) {
        int oldCapacity = queue.length;
        // Double size if small; else grow by 50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                         (oldCapacity + 2) :
                                         (oldCapacity >> 1));
        // overflow-conscious code
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);
    }
           

源碼解析:

  • 功能:增加數組的容量
  • 源碼思路:
    • (1)定義整型變量newCapacity,其值為優先隊列數組的長度
    • (2)如果長度小于64,則添加到原來的2倍,如果大于64,則增加為原來的一半
    • (3)如果新增加的數組容量大于整型的最大值-8,那麼需要調用hugeCapacity()方法修改數組容量
    • (4)最後将數組和新的容量傳回給目前隊列數組

12. private static int hugeCapacity(int minCapacity)方法

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
           

源碼解析:

  • 功能:按照minCapacity對數組進行擴容
  • 源碼思路:
    • (1)如果想要添加的容量值小于0,則抛出異常
    • (2)傳回minCapacity大于MAX_ARRAY_SIZE值,則傳回整型最大值,否則傳回MAX_ARRAY_SIZE值

13. public boolean add(E e)方法

public boolean add(E e) {
        return offer(e);
    }
           

源碼解析:

  • 功能:向優先隊列中添加元素e
  • 源碼思路:
    • 調用該類的offer()方法實作該操作

14. public boolean offer(E e)方法

public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }
           

源碼解析:

  • 功能:向優先隊列中添加元素e,添加元素的核心是***siftUp()***方法
  • 源碼思路:
    • (1)首先判斷元素e是否為null,如果為null,則抛出異常,否則執行下述步驟
    • (2)因為向隊列中插入元素,修改了隊列的結構,是以modCount需要自加1
    • (3)定義變量i,用來隊列的size
    • (4)如果變量i的值大于隊列的數組長度,需要調用grow()方法,增加隊列數組的長度,對應的size值要+1
    • (5)如果i=0,說明隊列中沒有元素,那麼新插進來的元素就可以作為樹根,否則要調用siftUp()方法來實作小根堆的調整

15. public E peek()方法

public E peek() {
        return (size == 0) ? null : (E) queue[0];
    }
           

源碼解析:

  • 功能:擷取隊列中的隊頭元素,即小根堆的根結點值
  • 源碼思路:
    • 判斷如果size的值等于0,說明隊列中沒有元素,傳回null;否則傳回隊列的頭元素

16. private int indexOf(Object o)方法

private int indexOf(Object o) {
        if (o != null) {
            for (int i = 0; i < size; i++)
                if (o.equals(queue[i]))
                    return i;
        }
        return -1;
    }
           

源碼解析:

  • 功能:查找隊列中元素值為o的結點的位置
  • 源碼思路:
    • (1)首先判斷查找的元素是否為null,如果是null,因為隊列中不存儲null元素,是以傳回-1,否則執行(2)步驟
    • (2)通過for循環進行周遊,每次周遊都使用equals方法來比較目前的元素是否與o元素相等,如果相等,則傳回目前元素的位置

17. public boolean remove(Object o)方法

public boolean remove(Object o) {
        int i = indexOf(o);
        if (i == -1)
            return false;
        else {
            removeAt(i);
            return true;
        }
    }
           

源碼解析:

  • 功能:移除隊列中元素為o的結點
  • 源碼思路:
    • (1)首先根據元素o調用indexOf()方法找到元素o的位置,将該位置存儲在變量i中
    • (2)判斷i的值是否為-1,-1表示隊列中不包含該元素,則傳回false
    • (3)如果隊列中包含該元素,則調用removeAt()方法,将該元素從隊列中移除

18. boolean removeEq(Object o)方法

boolean removeEq(Object o) {
        for (int i = 0; i < size; i++) {
            if (o == queue[i]) {
                removeAt(i);
                return true;
            }
        }
        return false;
    }
           

源碼解析:

  • 功能:将元素o從隊列中移除
  • 源碼思路:
    • 通過for循環周遊元素,使用==運算符判斷是否找到元素,找到後調用remove()方法将元素從隊列中移除

19. public boolean contains(Object o)方法

public boolean contains(Object o) {
        return indexOf(o) != -1;
    }
           

源碼解析:

  • 功能:判斷隊列中是否包含元素o
  • 源碼思路:
    • 調用indexOf()方法,如果有該元素,indexOf()方法會傳回元素的位置
    • 判斷元素位置是否為-1,如果為-1則說明不包含該元素,方法傳回false,否則傳回true

20. public Object[] toArray()方法

public Object[] toArray() {
        return Arrays.copyOf(queue, size);
    }
           

源碼解析:

  • 功能:将隊列的元素轉換為數組
  • 源碼思路:
    • 調用Arrays.copyOf()方法,将隊列中的數組和數組大小傳遞到方法中,傳回Object類型數組

21. public T[] toArray(T[] a)方法

public <T> T[] toArray(T[] a) {
        final int size = this.size;
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(queue, size, a.getClass());
        System.arraycopy(queue, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }
           

源碼解析:

  • 功能:将隊列中的元素存儲在數組a中
  • 源碼思路:
    • (1)首先定義一個final int類型的變量size,擷取目前隊列的size
    • (2)如果将傳回的數組大小小于目前隊列的size大小,則直接調用Arrays類的copyOf方法将隊列和隊列的大小,a的類型傳遞進去,傳回該隊列對應的數組。否則執行步驟(3)
    • (3)調用System類的arraycopy方法,将queue數組從0開始指派給數組a,指派的數組大小為size
    • (4)如果a數組的大小大于size,說明設定的初始将傳回的數組a大小太大,需要将多餘的部分的第一個元素設定為null

22. public Iterator iterator()方法

public Iterator<E> iterator() {
        return new Itr();
    }
           

源碼解析:

  • 功能:建立優先隊列的疊代器

23. public int size()方法

public int size() {
        return size;
    }
           

源碼解析:

  • 功能:傳回隊列的size元素個數

24. public void clear()方法

public void clear() {
        modCount++;
        for (int i = 0; i < size; i++)
            queue[i] = null;
        size = 0;
    }
           

源碼解析:

  • 功能:清除隊列中的所有元素
  • 源碼思路:
    • (1)因為清除操作是對隊列的結構性修改,是以需要讓modCount自加1
    • (2)使用for循環周遊隊列,每次循環都将循環到的元素值置為null
    • (3)最後将size的值變為0

25. public E poll()方法

public E poll() {
        if (size == 0)
            return null;
        int s = --size;
        modCount++;
        E result = (E) queue[0];
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);
        return result;
    }
           

源碼解析:

  • 功能:删除堆的根結點
  • 源碼思路:
    • (1)首先判斷隊列中是否有元素,如果有元素,則傳回null
    • (2)定義變量s,其值等于隊列的size-1,同時将隊列的size值-1
    • (3)定義變量result,其值等于堆的根結點值,定義變量x,其值等于堆的最後一個元素的值
    • (4)将堆的最後一個元素值置為null,因為要删除根結點,是以滿足堆的定義,最後一個元素一定為null
    • (5)如果隊列的最後一個元素不是堆的第一個元素,就需要将堆的最後一個元素按照小根堆的規則找到它的新位置,是以調用siftDown()方法進行調整

26. private E removeAt(int i)方法

private E removeAt(int i) {
        // assert i >= 0 && i < size;
        modCount++;
        int s = --size;
        if (s == i) // removed last element
            queue[i] = null;
        else {
            E moved = (E) queue[s];
            queue[s] = null;
            siftDown(i, moved);
            if (queue[i] == moved) {
                siftUp(i, moved);
                if (queue[i] != moved)
                    return moved;
            }
        }
        return null;
    }
           

源碼解析:

  • 功能:移除隊列中位置為i的元素
  • 源碼思路:
    • (1)因為移除操作是對隊列的結構上的修改,是以需要modCount+1
    • (2)定義整型變量s,其值等于size-1,同時将隊列的size值-1
    • (3)如果要删除的元素是隊列的最後一個元素,則直接将最後一個元素置為null
    • (4)否則定義變量moved,用來存儲隊列中的最後一個元素
    • (5)因為要移除一個元素,是以隊列的最後一個元素要移動保證小根堆的性質,是以最後一個元素一定變為null,移動最後一個元素的規則是調用siftDown(i,moved)方法

27. private void siftUp(int k, E x)方法

private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }
           

源碼解析:

  • 功能: 在k位置插入元素x
  • 源碼思路:
    • (1)首先判斷疊代器是否為null,如果不為空調用siftUpUsingComparator(k, x)方法,保證隊列是小根堆
    • (2)如果疊代器尾null,調用siftUpComparable(k, x)方法

28. private void siftUpComparable(int k, E x)方法

private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }
           

源碼解析:

  • 功能:向隊列中位置為k的地方插入元素x
  • 源碼思路:
  • (1)首先擷取元素x的比較器,将其放在Comparable類型的key變量中
  • (2)循環,循環條件k>0。定義變量parent,其值等于位置為k的元素的父節點的位置
  • (3)定義變量e,其值為 位置為k的元素的父節點的位置的變量
  • (4)調用構造器判斷目前将插入的元素與插入位置的父節點的值大小,如果大于父節點的值,則滿足小根堆,直接跳出循環,将插入的元素x插入到位置k;否則,執行步驟(5)
  • (5)将位置為k的元素值變為其父節點的值,将其父節點的值變為插入元素x的值

    下面示例:

    目前隊列中有如下元素[1, 2, 8, 9, 6]

    java集合(十)---Queue與PriorityQueue、Deque源碼解析
    元素在邏輯上的存儲方式如上圖,現在想要再插入元素4,即如果執行add(4)方法,會出現的結果是
    java集合(十)---Queue與PriorityQueue、Deque源碼解析
    該過程如果用siftUpComparable()方法來講解的話,過程如下:
  • 首先k=5, parent = (5-1)/2 = 2,e = 10, 因為比較的結果是queue[parent] >queue[k],是以将8放在位置5,k = 2;
  • 目前k=2,parent = 0,e = 1,因為比較的結果是queue[parent]< queue[k],是以不執行if裡面的語句,而執行queue[0] = 1,k = 0
  • 因為 k =0,退出循環體
  • 最後執行queue[2] = 4

29. private void siftUpUsingComparator(int k, E x)方法

private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }
           

源碼解析:

  • 功能:向隊列中位置為k的地方插入元素x,與上一個方法的不同之處就是這個方法提供了自己的比較器,是以比較結點值大小的時候使用提供的比較器比較

30. private void siftDown(int k, E x)方法

private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }
           

源碼解析:

  • 功能:從堆的第一個元素往下比較,如果比左右孩子節點的最小值小則與最小值交換,交換後繼續向下比較,否則停止比較

31. private void siftDownComparable(int k, E x)方法

private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // loop while a non-leaf
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }
           

感謝:

參考:https://blog.csdn.net/u013309870/article/details/71478120

https://blog.csdn.net/xiaojie_570/article/details/79915942