1. 程式人生 > >優先隊列原理與實現

優先隊列原理與實現

() 通過 size 大堆 默認 深入理解 -s 示例 完整

轉自:https://www.cnblogs.com/luoxn28/p/5616101.html

優先隊列是一種用來維護一組元素構成的結合S的數據結構,其中每個元素都有一個關鍵字key,元素之間的比較都是通過key來比較的。優先隊列包括最大優先隊列和最小優先隊列,優先隊列的應用比較廣泛,比如作業系統中的調度程序,當一個作業完成後,需要在所有等待調度的作業中選擇一個優先級最高的作業來執行,並且也可以添加一個新的作業到作業的優先隊列中。Java中,PriorityQueue的底層數據結構就是堆(默認是小堆),關於Java的PriorityQueue更多知識請點擊:深入理解Java PriorityQueue。

  優先隊列的實現中,我們可以選擇堆數據結構,最大優先隊列可以選用大堆,最小優先隊列可以選用小堆來實現。下面以最大優先隊列來講解其原理。最大優先隊列一般包括將一個元素插入到集合S中、返回集合S中具有最大key的元素、返回並刪除集合S中具有最大key的元素等。

插入操作

  插入操作是將一個元素插入到集合S中,首先把該元素放入所有元素的下一位置,然後執行“上浮”操作,如下圖示例(註意,下圖示例是小堆,不過原理是一樣的,圖片來自深入理解Java PriorityQueue)技術分享圖片

移除操作

  優先隊列中,在隊列非空情況下移除集合中第一個元素,也就是下標為0的元素,然後將集合中最後一個元素移到下標為0位置,在將下標為0的新元素執行“下沈”操作。如下圖示例(註意,下圖示例是小堆,不過原理是一樣的,圖片來自深入理解Java PriorityQueue)

技術分享圖片

完整代碼實現

package priorityheap;

import java.util.Arrays;

/**
 * 優先隊列類(最大優先隊列)
 */
public class PriorityHeap {

    // ------------------------------ Instance Variables

    private int[] arr;
    private int size;

    // ------------------------------ Constructors

    /**
     * 優先隊列數組默認大小為64
     */
    public PriorityHeap() {
        this(64);
    }

    public PriorityHeap(int initSize) {
        if (initSize <= 0) {
            initSize = 64;
        }
        this.arr = new int[initSize];
        this.size = 0;
    }

    // ------------------------------ Public methods

    public int max() {
        return this.arr[0];
    }

    public int maxAndRemove() {
        int t = max();

        this.arr[0] = this.arr[--size];
        sink(0, this.arr[0]);
        return t;
    }
    public void add(int data) {
        resize(1);
        this.arr[size++] = data;
        pop(size - 1, data);
    }

    // ------------------------------ Private methods

    /**
     * key下沈方法
     */
    private void sink(int i, int key) {
        while (2 * i <= this.size - 1) {
            int child = 2 * i;
            if (child < this.size - 1 && this.arr[child] < this.arr[child + 1]) {
                child++;
            }
            if (this.arr[i] >= this.arr[child]) {
                break;
            }

            swap(i, child);
            i = child;
        }
    }

    /**
     * key上浮方法
     */
    private void pop(int i, int key) {
        while (i > 0) {
            int parent = i / 2;
            if (this.arr[i] <= this.arr[parent]) {
                break;
            }
            swap(i, parent);
            i = parent;
        }
    }

    /**
     * 重新調整數組大小
     */
    private void resize(int increaseSize) {
        if ((this.size + increaseSize) > this.arr.length) {
            int newSize = (this.size + increaseSize) > 2 * this.arr.length ? (this.size + increaseSize) : 2 * this.arr.length;
            int[] t = this.arr;

            this.arr = Arrays.copyOf(t, newSize);
        }
    }

    /**
     * Swaps arr[a] with arr[b].
     */
    private void swap(int a, int b) {
        int t = this.arr[a];
        this.arr[a] = this.arr[b];
        this.arr[b] = t;
    }
}

  

優先隊列原理與實現