最小堆

        1
      /   \
     2     3
    / \   / \
   4   5 6   7

上面的樹是 Min-Heap,因為根是樹中存在的所有節點中的最小值。樹中的所有節點都遵循相同的屬性。

最大堆

        7
      /   \
     6     5
    / \   / \
   4   3 2   1

上面的樹是 Max-Heap,因為根是樹中存在的所有節點中的最大值。樹中的所有節點都遵循相同的屬性。

Min-Heap 支援的操作

  1. getMin() - 它返回根元素。因為它是陣列中的第一個元素,我們可以檢索 O(1) 中的最小元素

  2. extractMin() - 它從 heap 中刪除最小元素。從刪除元素後,樹必須滿足 Min-Heap 屬性,因此執行操作( 堆化 )以維護樹屬性。這需要 O(logn)

  3. dereaseKey() - 它減少了 key 的值。這個操作的時間複雜度是 O(logn)

  4. insert() - 金鑰總是插在樹的末尾。如果新增的金鑰不遵循堆屬性,那麼我們需要滲透,以便樹滿足堆屬性。這一步需要花費時間 4。

  5. delete() - 此步驟需要 O(logn) 時間。要刪除鍵,我們首先需要將鍵值減小到最小值,然後提取此最小值。

堆的應用

  1. 堆排序
  2. 優先順序佇列

堆使用了許多圖形演算法,如 Dijkstra’s Shortest PathPrim’s Minimum Spanning Tree

用 Java 實現

public class MinHeap {
    
    int hArr[];
    int capacity;
    int heapSize;
    
    public MinHeap(int capacity){
        this.heapSize = 0;
        this.capacity = capacity;
        hArr = new int[capacity];
    }
    
    public int getparent(int i){
        return (i-1)/2;
    }
    
    public int getLeftChild(int i){
        return 2*i+1;
    }
    
    public int getRightChild(int i){
        return 2*i+2;
    }
    
    public void insertKey(int k){
        if(heapSize==capacity)
            return;
        
        heapSize++;
        int i = heapSize-1;
        hArr[i] = k;
        
        while(i!=0 && hArr[getparent(i)]>hArr[i]){
            swap(hArr[i],hArr[getparent(i)]);
            i = getparent(i);
        }
    }
    
    public int extractMin(){
        if(heapSize==0)
            return Integer.MAX_VALUE;
        
        if(heapSize==1){
            heapSize--;
            return hArr[0];
        }
        
        int root = hArr[0];
        hArr[0] = hArr[heapSize-1];
        heapSize--;
        MinHeapify(0);
        
        return root;
    }
    
    public void decreaseKey(int i , int newVal){
        hArr[i] = newVal;
        while(i!=0 && hArr[getparent(i)]>hArr[i]){
            swap(hArr[i],hArr[getparent(i)]);
            i = getparent(i);
        }
    }
    
    public void deleteKey(int i){
        decreaseKey(i, Integer.MIN_VALUE);
        extractMin();
    }
    
    public void MinHeapify(int i){
        int l = getLeftChild(i);
        int r = getRightChild(i);
        int smallest = i;
        if(l<heapSize && hArr[l] < hArr[i])
            smallest = l;
        if(l<heapSize && hArr[r] < hArr[smallest])
            smallest = r;
        
        if(smallest!=i){
            swap(hArr[i], hArr[smallest]);
            MinHeapify(smallest);
        }
    }
    
    public void swap(int x, int y){
        int temp = hArr[x];
        hArr[x] = hArr[y];
        hArr[y] = temp;
    }
}