最小堆

        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;
    }
}