最大堆 和 優先隊列

最大堆

MaxHeap.java

import java.util.Random;  // 後面測試用

public class MaxHeap<E extends Comparable<E>> {
    private Array<E> data;

    public MaxHeap(int capacity){
        data = new Array<>(capacity);
    }

    public MaxHeap(){
        data = new Array<>();
    }

    /**
     * 將數組轉化爲堆
     * 一開始就把數組當成未規範的堆,
     * 然後從第一個非葉子節點開始做sift down, 一直到根結點
     * @param arr
     */
    public MaxHeap(E[] arr){
        data = new Array<>(arr);
        for(int i=parent(arr.length-1); i>=0; i--){
            siftDown(i);
        }
    }

    public int size(){
        return data.getSize();
    }

    public boolean isEmpty(){
        return data.isEmpty();
    }

    /**
     *
     * @param index
     * @return 父節點的索引
     */
    private int parent(int index){
        if(index == 0)
            throw new IllegalArgumentException("No parent");
        return (index-1)/2;
    }

    /**
     *
     * @param index
     * @return 左孩子的索引
     */
    private int leftChild(int index){
        return index * 2 + 1;
    }

    /**
     *
     * @param index
     * @return 右孩子的索引
     */
    private int rightChild(int index){
        return index * 2 + 2;
    }

    /**
     * 添加元素e
     * 思路: 把元素添加到最後一個, 然後向上浮動形成最大堆
     * @param e
     */
    public void add(E e){
        data.addLast(e);
        siftUp(data.getSize() - 1);
    }

    /**
     * 向上浮動
     * @param k
     */
    private void siftUp(int k) {
        // 一直循環, 如果k有父節點, 且比父節點大
        while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0){
            data.swap(k, parent(k));
            k = parent(k);
        }
    }

    /**
     * 看最大的元素值
     * @return
     */
    public E findMax(){
        if(data.getSize() == 0)
            throw new IllegalArgumentException();
        return data.get(0);
    }

    /**
     * 取出堆中最大的元素
     * 思路: 先保存最大元素, 然後用最後一個元素覆蓋掉最大的元素, 
     * 刪除最後一個元素, 然後向下浮動形成最大堆
     * @return
     */
    public E extractMax(){
        E ret = findMax();
        data.swap(0, data.getSize()-1);
        data.removeLast();
        siftDown(0);

        return ret;
    }

    /**
     * 向下浮動
     * @param k
     */
    private void siftDown(int k){
        // 一直循環如果 k 有孩子
        while(leftChild(k) < data.getSize()){
            // 獲得最大的孩子的索引
            int maxChildIndex = leftChild(k);
            if(maxChildIndex+1 < data.getSize() &&
                    data.get(maxChildIndex).compareTo(data.get(maxChildIndex+1)) < 0){
                maxChildIndex = rightChild(k);
            }

            // 如果根節點大於等於孩子
            if(data.get(k).compareTo(data.get(maxChildIndex)) >= 0) {
                break;
            }
            // 如果孩子比較大
            data.swap(k, maxChildIndex);
            k = maxChildIndex;
        }
    }

    /**
     * O(log n) 取出堆中最大的元素並替換成e
     * @param e
     * @return
     */
    public E replace(E e){
        E ret = findMax();
        data.set(0, e);
        siftDown(0);

        return ret;
    }

    public static void main(String[] args) {
        int n = 1000000;

        MaxHeap<Integer> maxHeap = new MaxHeap<>();
        Random random = new Random();
        for(int i=0; i<n; i++){
            maxHeap.add(random.nextInt(Integer.MAX_VALUE));
        }

        int[] arr = new int[n];
        for(int i=0; i<n; i++){
            arr[i] = maxHeap.extractMax();
        }

        for(int i=1; i<n; i++){
            if(arr[i-1] < arr[i]){
                throw new IllegalArgumentException();
            }
        }
        System.out.println("Good!");
    }
}

優先隊列

Queue.java

public interface Queue<E> {
    int getSize();
    boolean isEmpty();
    void enqueue(E e);
    E dequeue();
    E getFront();
}

PriorityQueue.java

public class PriorityQueue<E extends Comparable<E>> implements Queue<E> {

    private MaxHeap<E> maxHeap;

    public PriorityQueue(){
        maxHeap = new MaxHeap<>();
    }

    @Override
    public int getSize() {
        return maxHeap.size();
    }

    @Override
    public boolean isEmpty() {
        return maxHeap.isEmpty();
    }

    @Override
    public void enqueue(E e) {
        maxHeap.add(e);
    }

    @Override
    public E dequeue() {
        return maxHeap.extractMax();
    }

    @Override
    public E getFront() {
        return maxHeap.findMax();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章