java中堆是用
java.util.PriorityQueue
实现的,支持新增向堆中添加元素、删除元素、弹出堆顶元素、查看堆顶元素、清空堆、获取堆大小、判读元素在不在堆中等功能。
但是却不支持修改堆中的元素,并继续保持堆结构。
下面我们就用手写一个堆,实现修改堆中元素,也依然能保持堆结构的加强堆。
我们增加了反向索引表,记录每个元素在堆中的下标,这样可以在修改堆中元素后,以最小代价实现堆结构调整。
/**
* Description:加强堆:
* 普通堆:支持元素弹出、压入,获取对大小;,但是不能支持当堆内元素改变后,自动调整结构
* 加强堆:支持:1)堆内元素改变后,自动调整结构;2)删除指定元素;
*
* @author LiuLei
* @version 1.0
* @date 2024/1/4 9:45
*/
public class HeapGreater<E> {
private ArrayList<E> heapList;
// 反向索引表,记录每个元素在数组中的下标,方便,元素变化,删除后,调整时以O(1)时间复杂度定位到元素
private HashMap<E, Integer> hashMap;
private Comparator<? super E> comparator;
private int heapSize;
public HeapGreater(Comparator<? super E> comparator) {
this.heapSize = 0;
this.heapList = new ArrayList<>();
this.hashMap = new HashMap<>(heapSize);
this.comparator = comparator;
}
public ArrayList<E> getHeapList() {
ArrayList<E> list = new ArrayList<>(heapSize - 1);
for (E e : heapList){
list.add(e);
}
return list;
}
public int size(){
return heapSize;
}
public boolean isEmpty(){
return heapSize == 0;
}
// 弹出堆顶元素
public E pop(){
E first = heapList.get(0);
swap(0, heapSize - 1);
heapList.remove(-- heapSize);
hashMap.remove(first);
heapify(0);
return first;
}
public E peak(){
return heapList.get(0);
}
// 压入元素
public void add(E t){
heapList.add(t);
hashMap.put(t, heapSize);
heapInsert(heapSize++);
}
// 删除指定元素
public void remove(E t){
// 末尾元素和要删除的指定元素互换,互换后,删除末尾
Integer dIndex = hashMap.get(t);
E last = heapList.get(heapSize - 1);
// 移除被删除的元素
heapList.remove(--heapSize);
hashMap.remove(t);
if(last != t){
heapList.set(dIndex, last);
hashMap.put(last, dIndex);
resign(last);
}
}
/**
* 加强堆特有方法:对象改变后,自动实现堆结构调整
*/
public void resign(E e){
Integer index = hashMap.get(e);
heapInsert(index);
heapify(index);
}
// 向上找父节点PK,替换,直到顶部-pk对象是同一个节点
public void heapInsert(int index){
// 此处无须判断 index > 0,因为当index = 0时, (index - 1) / 2 = 0;
while (comparator.compare(heapList.get(index), heapList.get((index - 1) / 2))< 0){
swap(index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
// 向下找子节点大的Pk, 替换,直到底部——无子节点
public <E> void heapify(int index){
int lChild = index * 2 + 1;
int rChild = index * 2 + 2;
while (lChild < heapSize || rChild < heapSize){
int maxChildIndex;
if( lChild < heapSize && rChild < heapSize){
maxChildIndex = comparator.compare(heapList.get(lChild), heapList.get(rChild)) > 0? lChild : rChild;
} else if(lChild < heapSize){
maxChildIndex = lChild;
} else {
maxChildIndex = rChild;
}
if(comparator.compare(heapList.get(maxChildIndex), heapList.get(index)) <0){
swap(index, maxChildIndex);
index = maxChildIndex;
lChild = index * 2 + 1;
rChild = index * 2 + 2;
} else {
break;
}
}
}
private void swap(int index, int fatherIndex) {
E temp1 = heapList.get(index);
E temp2 = heapList.get(fatherIndex);
heapList.set(index, temp2);
heapList.set(fatherIndex, temp1);
// 反向索引表,记录index的变换
hashMap.put(temp1, fatherIndex);
hashMap.put(temp2, index);
}