加强堆

225 阅读1分钟

加强堆与系统给的PriorityQueue不同的是,具备反向索引表。可以用logN的时间复杂度,实现删除堆内指定元素,可以用O(1)的时间复杂度实现查找元素位置以及确定元素是否存在。除此之外,这个堆可以传入比较器确定比较规则。

public class HeapGreater<T> {

   private ArrayList<T> heap;
   private HashMap<T, Integer> indexMap;
   private int heapSize;
   // ? super T 是指存的都是T的父类,如果取出就不知道是什么类
   private Comparator<? super T> comp;

   public HeapGreater(Comparator<T> c) {
      heap = new ArrayList<>();
      indexMap = new HashMap<>();
      heapSize = 0;
      comp = c;
   }

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

   public int size() {
      return heapSize;
   }

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

   public T peek() {
      return heap.get(0);
   }

   public void push(T obj) {
      heap.add(obj);
      indexMap.put(obj, heapSize); // 就多了这一句
      heapInsert(heapSize++);
   }

   public T pop() {
      T ans = heap.get(0);
      swap(0, heapSize - 1);
      indexMap.remove(ans); // 就多了这一句
      heap.remove(--heapSize); // 不是数组了,所以不能swap时--heapSize
      heapify(0);
      return ans;
   }

   // 删除堆内指定元素
   public void remove(T obj) {
      T replace = heap.get(heapSize - 1); // 堆最后一个元素
      int index = indexMap.get(obj); // 需要删除元素的索引
      indexMap.remove(obj);  // 索引表删除
      heap.remove(--heapSize); // 记录过值了,直接删除
      if (obj != replace) { // 如果要删除的就是最后一个元素,直接结束
         heap.set(index, replace); // 把堆最后一个元素,替换掉当前元素
         indexMap.put(replace, index); // 调整替换后元素的索引
         resign(replace);
      }
   }

   // 调整元素位置正确
   public void resign(T obj) {
      heapInsert(indexMap.get(obj));
      heapify(indexMap.get(obj));
   }

   // 请返回堆上的所有元素
   public List<T> getAllElements() {
      List<T> ans = new ArrayList<>();
      for (T c : heap) {
         ans.add(c);
      }
      return ans;
   }

   private void heapInsert(int index) {
      while (comp.compare(heap.get(index), heap.get((index - 1) / 2)) < 0) {
         swap(index, (index - 1) / 2);
         index = (index - 1) / 2;
      }
   }

   private void heapify(int index) {
      int left = index * 2 + 1;
      while (left < heapSize) {
         int best = left + 1 < heapSize && comp.compare(heap.get(left + 1), heap.get(left)) < 0 ? (left + 1) : left;
         best = comp.compare(heap.get(best), heap.get(index)) < 0 ? best : index;
         if (best == index) {
            break;
         }
         swap(best, index);
         index = best;
         left = index * 2 + 1;
      }
   }

   private void swap(int i, int j) {
      T o1 = heap.get(i);
      T o2 = heap.get(j);
      heap.set(i, o2);
      heap.set(j, o1);
      indexMap.put(o2, i);
      indexMap.put(o1, j);
   }

}