堆的删除
每次删除的一定都是堆顶的元素
具体步骤如下:
- 将堆顶的元素与堆中的最后一个元素交换;
- 将堆中的有效元素减一;
- 对堆顶的元素进项向下调整。(因为第一步交换之后可能导致对不满足大堆/小堆的性质)。
代码示例:
//每次删除的是堆顶的元素
int poll(){
int ret = array[0];
swap(0,size-1);
size--;
shiftDown(0);
return ret;
}
private void shiftDown(int parent){
//使用child标记parent的较小的孩子
//默认情况下先让其标记其左孩子,因为parent可能只有左孩子而没有右孩子
int child = parent*2+1;
while(child < size) {//保证左孩子存在
//找parent中较小的孩子
//再用左右孩子进行比较时,必须要保证右孩子存在
//if (child+1<size && array[child + 1] < array[child]) {
if(child+1<size&&compare.compare(array[child+1],array[child])<0){
child += 1;
}
//检测较小的孩子是否比parent小
//if (array[child] < array[parent]) {
if(compare.compare(array[child],array[parent])<0){
//说明parent不满足小堆的性质
swap(parent, child);
//可能会导致子树不满足小堆的性质
//继续向下调整
parent = child;
child = parent * 2 + 1;
} else {
return;
}
}
}
private void swap(int parent,int child){
int temp = array[parent];
array[parent] = array[child];
array[child] = temp;
}
堆的插入
堆的插入只需两步:
- 先将元素放入到底层空间中(如果空间不足时,需要进行扩容,参照优先级队列的扩容方式进行扩容);
- 将最后新插入的元素进行向上调整,直到所有元素满足堆的性质。
代码示例:
//堆的插入
//
boolean offer(int x){
if(size>=array.length){
grow();
}
array[size++] = x;
shiftUp(size-1);
return true;
}
//向上调整
private void shiftUp(int child){
int parent = (child-1)>>1;
while(parent > 0){
//if(array[child] > array[parent]) {
if(compare.compare(array[child],array[parent])>0){
swap(child, parent);
child = parent;
parent = (child - 1) >> 1;
}else{
break;
}
}
}
//扩容--参考顺序表
//只是模拟标准库中优先级队列扩容的一部分
private void grow(){
int oldCapacity = array.length;
int newCapacity = oldCapacity + ((oldCapacity<64)?(oldCapacity+2):(oldCapacity>>1));
array = Arrays.copyOf(array,newCapacity);
}
private void swap(int parent,int child){
int temp = array[parent];
array[parent] = array[child];
array[child] = temp;
}