加 强 堆

加强堆

// 引入:
// java系统自带的堆,如果内部某个节点的数值突然增大或是突然的减小,会导致这个堆功能失效。如果想要调整变化的节点,时间复  // 杂度是NlogN(先遍历数组找到值改变的节点,然后再向上/下调整)。
// 系统自带的堆,我们只能通过index找到value,无法通过value找到其index.所以我们对其进行改良,加上反向索引表hashmap。
// 这样我们可以通过value找到其index,使调整的时间复杂度降到log N。
// 图1

图一:

加 强 堆_第1张图片

图2:

package algorithmbasic.class8;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;

// 加强堆
public class HeapGreater<T> {
    private ArrayList<T> heap;
    private int heapSize;
    private HashMap<T, Integer> indexMap;
    private Comparator<? super T> comp;

    // 外界传入比较器,内部接收。
    public HeapGreater(Comparator<? super T> comp) {
        this.heap = new ArrayList<>();
        this.heapSize = 0;
        this.comp = comp;
    }

    public boolean isEmpty() {
        return this.heapSize == 0;
    }

    public int size() {
        return this.heapSize;
    }

    public boolean contains(T obj) {
        return this.indexMap.containsKey(obj);
    }

    public T peek() {
        if (heap.isEmpty()) {
            throw new RuntimeException("堆为空");
        } else {
            return this.heap.get(0);
        }
    }

    // logN
    public void push(T obj) {
        // ArrayList是一个动态数组会自动扩容,不存在isfull状态。
        heap.add(obj);
        indexMap.put(obj, heapSize);
        heapInsert(heapSize++);
    }

    // logN
    public void heapInsert(int index) {
        int father = (index - 1) / 2;
        // 注意比较的时候要用我们转进来的比较器比较。
        while (this.comp.compare(heap.get(father), heap.get(index)) < 0) {
            // 注意交换的时候,ArrayList中的K V需要交换,HashMap中的K V也需要交换。
            swap(father, index);
            index = father;
            father = (index - 1) / 2;
        }
    }

    // logN
    public T pop() {
        if (heap.isEmpty()) {
            throw new RuntimeException("堆为空");
        }
        T ans = heap.get(0);
        // 先交换后删除,如果先删除后交换,hashmap中还会有ans值
        swap(0, --heapSize);
        indexMap.remove(ans);
        heapFiy(0, heapSize);
        return ans;
    }

    // logN
    public void heapFiy(int index, int heapSize) {
        int l = index * 2 + 1;
        while (l < heapSize) {
            int minSonIndex = l + 1 < heapSize ? (this.comp.compare(heap.get(l), heap.get(l + 1)) < 0 ? l : l + 1) : (l);
            if(this.comp.compare(heap.get(minSonIndex), heap.get(index)) < 0) {
                swap(minSonIndex, index);
                index = minSonIndex;
                l = index * 2 + 1;
            }else {
                break;
            }
        }
    }

    // 删除堆中的某个节点  图2
    public void remove(T obj) {
        // 得到节点的位置index
        int index = indexMap.get(obj);
        // 得到末尾的数 value
        T replace = heap.get(--heapSize);
        // 将hashmap中obj值以及heap中末尾的数直接删掉
        indexMap.remove(obj);
        heap.remove(heapSize);
        // 如果末尾节点值与obj是同一个,那删除的就是末尾节点,不需要一下操作
        if (obj != replace) {
            // 将结果塞回去
            heap.set(index, replace);
            indexMap.put(replace, index);
            resign(replace);
        }
    }

    // 重构造
    // 当堆中某个节点突然的增大或是减小时,对其进行调整。
    // 只会执行其中的一个,
    // logN
    public void resign(T obj) {
        heapInsert(indexMap.get(obj));
        heapFiy(indexMap.get(obj), heapSize);
    }

    public void swap(int i, int j) {
        T value1 = heap.get(i);
        T value2 = heap.get(j);
        heap.set(i, value2);
        heap.set(j, value1);
        // HashMap新的值覆盖旧的值
        indexMap.put(value1, j);
        indexMap.put(value2, i);
    }
}

你可能感兴趣的:(算法,java,算法)