164 lines
2.7 KiB
JavaScript
164 lines
2.7 KiB
JavaScript
|
|
||
|
function create (maxLength=1000) {
|
||
|
return {
|
||
|
arr: new Array(maxLength),
|
||
|
length: 0,
|
||
|
maxLength,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
function queue (heap, item, priority) {
|
||
|
if (priority === undefined)
|
||
|
throw new Error('must include priority when queueing')
|
||
|
|
||
|
if (_findIndex(heap, item) >= 0) {
|
||
|
del(heap, item)
|
||
|
}
|
||
|
|
||
|
if (heap.length === heap.maxLength) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
heap.arr[heap.length] = { item, priority }
|
||
|
heap.length++
|
||
|
|
||
|
_upHeap(heap, heap.length-1)
|
||
|
}
|
||
|
|
||
|
|
||
|
// traverse up the heap from a starting index
|
||
|
//
|
||
|
// heap
|
||
|
// index to start at
|
||
|
function _upHeap (heap, index) {
|
||
|
|
||
|
while (index > 0) {
|
||
|
|
||
|
let parentIdx
|
||
|
|
||
|
if (index % 2 === 0)
|
||
|
parentIdx = (index - 2) / 2
|
||
|
else
|
||
|
parentIdx = (index - 1) / 2
|
||
|
|
||
|
// if the parent is greater than the current node, stop because we've corrected the heap
|
||
|
if (heap.arr[parentIdx].priority >= heap.arr[index].priority)
|
||
|
return
|
||
|
|
||
|
_swap(heap.arr, index, parentIdx)
|
||
|
|
||
|
index = parentIdx
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// get and remove highest priority item from the heap
|
||
|
function dequeue (heap) {
|
||
|
if (heap.length === 0)
|
||
|
return
|
||
|
|
||
|
const max = heap.arr[0].item
|
||
|
|
||
|
heap.length--
|
||
|
heap.arr[0] = heap.arr[heap.length]
|
||
|
|
||
|
_downHeap(heap, 0)
|
||
|
|
||
|
return max
|
||
|
}
|
||
|
|
||
|
|
||
|
// traverse down the heap from a starting index
|
||
|
//
|
||
|
// heap
|
||
|
// index to start at
|
||
|
function _downHeap (heap, index) {
|
||
|
while (index < heap.length) {
|
||
|
|
||
|
const left = index * 2 + 1
|
||
|
const right = index * 2 + 2
|
||
|
|
||
|
let largest = index
|
||
|
|
||
|
if (left < heap.length && heap.arr[left].priority > heap.arr[largest].priority)
|
||
|
largest = left
|
||
|
|
||
|
if (right < heap.length && heap.arr[right].priority > heap.arr[largest].priority)
|
||
|
largest = right
|
||
|
|
||
|
if (largest === index)
|
||
|
return
|
||
|
|
||
|
_swap(heap.arr, index, largest)
|
||
|
|
||
|
index = largest
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
function _swap (arr, i, j) {
|
||
|
const tmp = arr[i]
|
||
|
arr[i] = arr[j]
|
||
|
arr[j] = tmp
|
||
|
}
|
||
|
|
||
|
|
||
|
function clear (heap) {
|
||
|
heap.length = 0
|
||
|
}
|
||
|
|
||
|
|
||
|
function isEmpty (heap) {
|
||
|
return heap.length === 0
|
||
|
}
|
||
|
|
||
|
|
||
|
function peek (heap) {
|
||
|
if (!heap.length)
|
||
|
return
|
||
|
return heap.arr[0].item
|
||
|
}
|
||
|
|
||
|
|
||
|
function del (heap, item) {
|
||
|
const ind = _findIndex(heap, item)
|
||
|
|
||
|
if (ind < 0)
|
||
|
throw new Error('key does not exist in priority queue!')
|
||
|
|
||
|
const tmp = heap.arr[ind]
|
||
|
heap.arr[ind] = heap.arr[heap.length-1]
|
||
|
heap.arr[heap.length-1] = tmp
|
||
|
|
||
|
if (heap.arr[ind].priority > heap.arr[heap.length-1].priority)
|
||
|
_upHeap(heap, ind)
|
||
|
else if (heap.arr[ind].priority < heap.arr[heap.length-1].priority)
|
||
|
_downHeap(heap, ind)
|
||
|
|
||
|
heap.length--
|
||
|
}
|
||
|
|
||
|
|
||
|
function _findIndex (heap, item) {
|
||
|
for (let i=0; i < heap.length; i++)
|
||
|
if (heap.arr[i].item === item)
|
||
|
return i
|
||
|
return -1
|
||
|
}
|
||
|
|
||
|
|
||
|
function list (heap) {
|
||
|
if (!heap.length)
|
||
|
return [ ]
|
||
|
|
||
|
const result = [ ]
|
||
|
for (let i=0; i < heap.length; i++)
|
||
|
result[i] = heap.arr[i].item
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
|
||
|
export default { create, queue, dequeue, clear, isEmpty, peek, delete: del, list }
|