Skip to content

Commit

Permalink
chore(commit): force
Browse files Browse the repository at this point in the history
  • Loading branch information
kmamal committed Aug 1, 2023
1 parent 58a8eae commit bf0caa5
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 1 deletion.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
},
"license": "MIT",
"main": "./src/index.js",
"exports": "./src/index.js",
"exports": {
".": "./src/index.js"
},
"scripts": {
"test": "npx @kmamal/testing",
"update-exports": "node ./scripts/update-exports.mjs"
Expand Down
91 changes: 91 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const {
getParent,
getLeft,
getRight,
} = require('@kmamal/util/array/tree/binary')
const { sub } = require('@kmamal/util/operators/arithmetic/sub')

class Heap {
constructor (init = [], options = {}) {
this._array = Array.from(init, ([ prio, value ], index) => ({ prio, value, index }))
this._compare = options.compare || sub
this._heapify()
}

get size () { return this._array.length }

add (prio, value) {
const index = this._array.length
const entry = { prio, value, index }
this._array.push(entry)
this._bubbleUp(entry)
return entry
}

remove (entry) {
const last = this._array[this._array.length - 1]
this._swap(entry, last)
this._array.pop()
this._bubbleDown(last)
return entry
}

update (entry, prio) {
const oldPrio = entry.prio
entry.prio = prio
this._compare(prio, oldPrio) < 0
? this._bubbleUp(entry)
: this._bubbleDown(entry)
}

min () { return this._array[0] }
pop () {
return this._array.length !== 0
? this.remove(this._array[0])
: undefined
}

_bubbleUp (entry) {
for (;;) {
const parent = this._array[getParent(entry.index)]
if (!parent) { break }

if (this._compare(parent.prio, entry.prio) < 0) { break }

this._swap(entry, parent)
}
}

_bubbleDown (entry) {
for (;;) {
const { index } = entry
const leftChild = this._array[getLeft(index)]
if (!leftChild) { break }

const rightChild = this._array[getRight(index)]
const minChild = !rightChild || this._compare(leftChild.prio, rightChild.prio) <= 0 ? leftChild : rightChild
if (this._compare(entry.prio, minChild.prio) < 0) { break }

this._swap(entry, minChild)
}
}

_swap (a, b) {
const ai = a.index
const bi = b.index
this._array[bi] = a
this._array[ai] = b
a.index = bi
b.index = ai
}

_heapify () {
const first = getParent(this._array.length - 1)
for (let i = first; i >= 0; i--) {
const entry = this._array[i]
this._bubbleDown(entry)
}
}
}

module.exports = { Heap }
16 changes: 16 additions & 0 deletions src/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { test } = require('@kmamal/testing')
const { Heap } = require('.')

test("structs.Heap Heapsort", (t) => {
const a = [ 4, 7, 1, 3, 2, 9, 0, 5, 8, 6 ]
const expected = [ ...a ]
expected.sort()

const heap = new Heap(a.map((x) => [ x, x ]))
const result = []
while (heap.size) {
result.push(heap.pop().value)
}

t.equal(result, expected)
})

0 comments on commit bf0caa5

Please sign in to comment.