手写堆

198 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

属性

private ArrayList<T> heap;
private HashMap<T, Integer> indexMap;
private int heapSize;
private Comparator<? super T> comp;

这个是手写堆定义的属性,

第一个属性就是放元素的堆

第二个哈希map是记住这个元素是在哪

第三个是表示这个堆有多少的元素

第四个是表示比较器

构造器


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

判断是否为空

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

这个就是看自己size是不是为0

返回堆的大小

public int size() {
   return heapSize;
}

这个就只要返回heapSize就可以了

查看这个元素是否存在

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

因为我们之前介绍过的,有个indexMap记录着每个元素在堆里面的位置,那我们只要看看indexMap里面有没有需要查询的元素就可以了。

查看堆顶的元素

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

push元素

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