有兩個原始操作用於保證插入或刪除節點以后堆是一個有效的最大堆或者最小堆:
shiftUp()
: 如果一個節點比它的父節點大(最大堆)或者小(最小堆),那么需要將它同父節點交換位置。這樣是這個節點在數組的位置上升。shiftDown()
: 如果一個節點比它的子節點小(最大堆)或者大(最小堆),那么需要將它向下移動。這個操作也稱作“堆化(heapify)”。
shiftUp 或者 shiftDown 是一個遞歸的過程,所以它的時間復雜度是 O(log n)。
基於這兩個原始操作還有一些其他的操作:
insert(value)
: 在堆的尾部添加一個新的元素,然后使用shiftUp
來修復對。remove()
: 移除並返回最大值(最大堆)或者最小值(最小堆)。為了將這個節點刪除后的空位填補上,需要將最后一個元素移到根節點的位置,然后使用shiftDown
方法來修復堆。
有一個挺惡心人的地方就是JS的number數據類型會導致需要向下取整才能對heap數組進行上升操作,否則就會有小數點的情況
這里是最大堆,最小堆稍微修改一下比較方式就行
let heap = []; function swap(idx1,idx2){ let temp; temp = heap[idx1]; heap[idx1] = heap[idx2]; heap[idx2] = temp; } function shiftup(idx){ let _idx = Math.floor((idx - 1) / 2); if(idx != 0 && heap[_idx] < heap[idx]){ swap(_idx,idx); shiftup(_idx); } } function shiftDown(idx){ if(idx * 2 + 1 < heap.length && heap[idx * 2 + 1] > heap[idx]){ swap(idx * 2 + 1,idx); shiftDown(idx * 2 + 1); }else if(idx * 2 + 2 < heap.length && heap[idx * 2 + 2] > heap[idx]){ swap(idx * 2 + 2,idx); shiftDown(idx * 2 + 2); } } function insert(val){ heap.push(val); shiftup(heap.length - 1); } function remove(){ swap(0,heap.length - 1); heap.pop(); shiftDown(0); return heap[0]; } insert(1); insert(3); insert(2); insert(5); remove(); insert(4); insert(6); remove(); console.log(heap);//4