mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2026-03-13 15:21:15 +08:00
feat: Test running overhaul, switch to Prettier & reformat everything (#1407)
* chore: Switch to Node 20 + Vitest * chore: migrate to vitest mock functions * chore: code style (switch to prettier) * test: re-enable long-running test Seems the switch to Node 20 and Vitest has vastly improved the code's and / or the test's runtime! see #1193 * chore: code style * chore: fix failing tests * Updated Documentation in README.md * Update contribution guidelines to state usage of Prettier * fix: set prettier printWidth back to 80 * chore: apply updated code style automatically * fix: set prettier line endings to lf again * chore: apply updated code style automatically --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com>
This commit is contained in:
@@ -19,12 +19,12 @@
|
||||
*/
|
||||
|
||||
// Priority Queue Helper functions
|
||||
const getParentPosition = position => Math.floor((position - 1) / 2)
|
||||
const getChildrenPositions = position => [2 * position + 1, 2 * position + 2]
|
||||
const getParentPosition = (position) => Math.floor((position - 1) / 2)
|
||||
const getChildrenPositions = (position) => [2 * position + 1, 2 * position + 2]
|
||||
|
||||
class KeyPriorityQueue {
|
||||
// Priority Queue class using Minimum Binary Heap
|
||||
constructor () {
|
||||
constructor() {
|
||||
this._heap = []
|
||||
this.priorities = new Map()
|
||||
}
|
||||
@@ -33,7 +33,7 @@ class KeyPriorityQueue {
|
||||
* Checks if the heap is empty
|
||||
* @returns boolean
|
||||
*/
|
||||
isEmpty () {
|
||||
isEmpty() {
|
||||
return this._heap.length === 0
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class KeyPriorityQueue {
|
||||
* @param {*} key
|
||||
* @param {number} priority
|
||||
*/
|
||||
push (key, priority) {
|
||||
push(key, priority) {
|
||||
this._heap.push(key)
|
||||
this.priorities.set(key, priority)
|
||||
this._shiftUp(this._heap.length - 1)
|
||||
@@ -52,7 +52,7 @@ class KeyPriorityQueue {
|
||||
* Removes the element with least priority
|
||||
* @returns the key of the element with least priority
|
||||
*/
|
||||
pop () {
|
||||
pop() {
|
||||
this._swap(0, this._heap.length - 1)
|
||||
const key = this._heap.pop()
|
||||
this.priorities.delete(key)
|
||||
@@ -65,7 +65,7 @@ class KeyPriorityQueue {
|
||||
* @param {*} key
|
||||
* @returns boolean
|
||||
*/
|
||||
contains (key) {
|
||||
contains(key) {
|
||||
return this.priorities.has(key)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class KeyPriorityQueue {
|
||||
* @param {*} key the element to change
|
||||
* @param {number} priority new priority of the element
|
||||
*/
|
||||
update (key, priority) {
|
||||
update(key, priority) {
|
||||
const currPos = this._heap.indexOf(key)
|
||||
// if the key does not exist yet, add it
|
||||
if (currPos === -1) return this.push(key, priority)
|
||||
@@ -95,13 +95,14 @@ class KeyPriorityQueue {
|
||||
}
|
||||
}
|
||||
|
||||
_getPriorityOrInfinite (position) {
|
||||
_getPriorityOrInfinite(position) {
|
||||
// Helper function, returns priority of the node, or Infinite if no node corresponds to this position
|
||||
if (position >= 0 && position < this._heap.length) return this.priorities.get(this._heap[position])
|
||||
if (position >= 0 && position < this._heap.length)
|
||||
return this.priorities.get(this._heap[position])
|
||||
else return Infinity
|
||||
}
|
||||
|
||||
_shiftUp (position) {
|
||||
_shiftUp(position) {
|
||||
// Helper function to shift up a node to proper position (equivalent to bubbleUp)
|
||||
let currPos = position
|
||||
let parentPos = getParentPosition(currPos)
|
||||
@@ -117,7 +118,7 @@ class KeyPriorityQueue {
|
||||
}
|
||||
}
|
||||
|
||||
_shiftDown (position) {
|
||||
_shiftDown(position) {
|
||||
// Helper function to shift down a node to proper position (equivalent to bubbleDown)
|
||||
let currPos = position
|
||||
let [child1Pos, child2Pos] = getChildrenPositions(currPos)
|
||||
@@ -137,16 +138,19 @@ class KeyPriorityQueue {
|
||||
this._swap(child2Pos, currPos)
|
||||
currPos = child2Pos
|
||||
}
|
||||
[child1Pos, child2Pos] = getChildrenPositions(currPos)
|
||||
;[child1Pos, child2Pos] = getChildrenPositions(currPos)
|
||||
child1Priority = this._getPriorityOrInfinite(child1Pos)
|
||||
child2Priority = this._getPriorityOrInfinite(child2Pos)
|
||||
currPriority = this._getPriorityOrInfinite(currPos)
|
||||
}
|
||||
}
|
||||
|
||||
_swap (position1, position2) {
|
||||
_swap(position1, position2) {
|
||||
// Helper function to swap 2 nodes
|
||||
[this._heap[position1], this._heap[position2]] = [this._heap[position2], this._heap[position1]]
|
||||
;[this._heap[position1], this._heap[position2]] = [
|
||||
this._heap[position2],
|
||||
this._heap[position1]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,25 +4,25 @@
|
||||
*/
|
||||
|
||||
class BinaryHeap {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.heap = []
|
||||
}
|
||||
|
||||
insert (value) {
|
||||
insert(value) {
|
||||
this.heap.push(value)
|
||||
this.heapify()
|
||||
}
|
||||
|
||||
size () {
|
||||
size() {
|
||||
return this.heap.length
|
||||
}
|
||||
|
||||
empty () {
|
||||
empty() {
|
||||
return this.size() === 0
|
||||
}
|
||||
|
||||
// using iterative approach to reorder the heap after insertion
|
||||
heapify () {
|
||||
heapify() {
|
||||
let index = this.size() - 1
|
||||
|
||||
while (index > 0) {
|
||||
@@ -38,7 +38,7 @@ class BinaryHeap {
|
||||
}
|
||||
|
||||
// Extracting the maximum element from the Heap
|
||||
extractMax () {
|
||||
extractMax() {
|
||||
const max = this.heap[0]
|
||||
const tmp = this.heap.pop()
|
||||
if (!this.empty()) {
|
||||
@@ -49,7 +49,7 @@ class BinaryHeap {
|
||||
}
|
||||
|
||||
// To restore the balance of the heap after extraction.
|
||||
sinkDown (index) {
|
||||
sinkDown(index) {
|
||||
const left = 2 * index + 1
|
||||
const right = 2 * index + 2
|
||||
let largest = index
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
*/
|
||||
|
||||
class MinHeap {
|
||||
constructor (array) {
|
||||
constructor(array) {
|
||||
this.heap = this.initializeHeap(array)
|
||||
}
|
||||
|
||||
/**
|
||||
* startingParent represents the parent of the last index (=== array.length-1)
|
||||
* and iterates towards 0 with all index values below sorted to meet heap conditions
|
||||
*/
|
||||
initializeHeap (array) {
|
||||
*/
|
||||
initializeHeap(array) {
|
||||
const startingParent = Math.floor((array.length - 2) / 2)
|
||||
|
||||
for (let currIdx = startingParent; currIdx >= 0; currIdx--) {
|
||||
@@ -52,15 +52,16 @@ class MinHeap {
|
||||
* update currIdx and recalculate the new childOneIdx to check heap conditions again.
|
||||
*
|
||||
* if there is no swap, it means the children indices and the parent index satisfy heap conditions and can exit the function.
|
||||
*/
|
||||
sinkDown (currIdx, endIdx, heap) {
|
||||
*/
|
||||
sinkDown(currIdx, endIdx, heap) {
|
||||
let childOneIdx = currIdx * 2 + 1
|
||||
|
||||
while (childOneIdx <= endIdx) {
|
||||
const childTwoIdx = childOneIdx + 1 <= endIdx ? childOneIdx + 1 : -1
|
||||
const swapIdx = childTwoIdx !== -1 && heap[childTwoIdx] < heap[childOneIdx]
|
||||
? childTwoIdx
|
||||
: childOneIdx
|
||||
const swapIdx =
|
||||
childTwoIdx !== -1 && heap[childTwoIdx] < heap[childOneIdx]
|
||||
? childTwoIdx
|
||||
: childOneIdx
|
||||
|
||||
if (heap[swapIdx] < heap[currIdx]) {
|
||||
this.swap(currIdx, swapIdx, heap)
|
||||
@@ -79,8 +80,8 @@ class MinHeap {
|
||||
* update currIdx and recalculate the new parentIdx to check heap condition again.
|
||||
*
|
||||
* iteration does not end while a valid currIdx has a value smaller than its parentIdx's value
|
||||
*/
|
||||
bubbleUp (currIdx) {
|
||||
*/
|
||||
bubbleUp(currIdx) {
|
||||
let parentIdx = Math.floor((currIdx - 1) / 2)
|
||||
|
||||
while (currIdx > 0 && this.heap[currIdx] < this.heap[parentIdx]) {
|
||||
@@ -90,7 +91,7 @@ class MinHeap {
|
||||
}
|
||||
}
|
||||
|
||||
peek () {
|
||||
peek() {
|
||||
return this.heap[0]
|
||||
}
|
||||
|
||||
@@ -101,8 +102,8 @@ class MinHeap {
|
||||
* the resulting min heap value now resides at heap[heap.length-1] which is popped and later returned.
|
||||
*
|
||||
* the remaining values in the heap are re-sorted
|
||||
*/
|
||||
extractMin () {
|
||||
*/
|
||||
extractMin() {
|
||||
this.swap(0, this.heap.length - 1, this.heap)
|
||||
const min = this.heap.pop()
|
||||
this.sinkDown(0, this.heap.length - 1, this.heap)
|
||||
@@ -110,13 +111,13 @@ class MinHeap {
|
||||
}
|
||||
|
||||
// a new value is pushed to the end of the heap and sorted up
|
||||
insert (value) {
|
||||
insert(value) {
|
||||
this.heap.push(value)
|
||||
this.bubbleUp(this.heap.length - 1)
|
||||
}
|
||||
|
||||
// index-swapping helper method
|
||||
swap (idx1, idx2, heap) {
|
||||
swap(idx1, idx2, heap) {
|
||||
const temp = heap[idx1]
|
||||
heap[idx1] = heap[idx2]
|
||||
heap[idx2] = temp
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/* Minimum Priority Queue
|
||||
* It is a part of heap data structure
|
||||
* A heap is a specific tree based data structure
|
||||
* in which all the nodes of tree are in a specific order.
|
||||
* that is the children are arranged in some
|
||||
* respect of their parents, can either be greater
|
||||
* or less than the parent. This makes it a min priority queue
|
||||
* or max priority queue.
|
||||
*/
|
||||
* It is a part of heap data structure
|
||||
* A heap is a specific tree based data structure
|
||||
* in which all the nodes of tree are in a specific order.
|
||||
* that is the children are arranged in some
|
||||
* respect of their parents, can either be greater
|
||||
* or less than the parent. This makes it a min priority queue
|
||||
* or max priority queue.
|
||||
*/
|
||||
|
||||
// Functions: insert, delete, peek, isEmpty, print, heapSort, sink
|
||||
|
||||
class MinPriorityQueue {
|
||||
// calls the constructor and initializes the capacity
|
||||
constructor (c) {
|
||||
constructor(c) {
|
||||
this.heap = []
|
||||
this.capacity = c
|
||||
this.size = 0
|
||||
@@ -20,7 +20,7 @@ class MinPriorityQueue {
|
||||
|
||||
// inserts the key at the end and rearranges it
|
||||
// so that the binary heap is in appropriate order
|
||||
insert (key) {
|
||||
insert(key) {
|
||||
if (this.isFull()) return
|
||||
this.heap[this.size + 1] = key
|
||||
let k = this.size + 1
|
||||
@@ -36,33 +36,36 @@ class MinPriorityQueue {
|
||||
}
|
||||
|
||||
// returns the highest priority value
|
||||
peek () {
|
||||
peek() {
|
||||
return this.heap[1]
|
||||
}
|
||||
|
||||
// returns boolean value whether the heap is empty or not
|
||||
isEmpty () {
|
||||
isEmpty() {
|
||||
return this.size === 0
|
||||
}
|
||||
|
||||
// returns boolean value whether the heap is full or not
|
||||
isFull () {
|
||||
isFull() {
|
||||
return this.size === this.capacity
|
||||
}
|
||||
|
||||
// prints the heap
|
||||
print (output = value => console.log(value)) {
|
||||
print(output = (value) => console.log(value)) {
|
||||
output(this.heap.slice(1))
|
||||
}
|
||||
|
||||
// heap reverse can be done by performing swapping the first
|
||||
// element with the last, removing the last element to
|
||||
// new array and calling sink function.
|
||||
heapReverse () {
|
||||
heapReverse() {
|
||||
const heapSort = []
|
||||
while (this.size > 0) {
|
||||
// swap first element with last element
|
||||
[this.heap[1], this.heap[this.size]] = [this.heap[this.size], this.heap[1]]
|
||||
;[this.heap[1], this.heap[this.size]] = [
|
||||
this.heap[this.size],
|
||||
this.heap[1]
|
||||
]
|
||||
heapSort.push(this.heap.pop())
|
||||
this.size--
|
||||
this.sink()
|
||||
@@ -74,7 +77,7 @@ class MinPriorityQueue {
|
||||
}
|
||||
|
||||
// this function reorders the heap after every delete function
|
||||
sink () {
|
||||
sink() {
|
||||
let k = 1
|
||||
while (2 * k <= this.size || 2 * k + 1 <= this.size) {
|
||||
let minIndex
|
||||
@@ -92,8 +95,7 @@ class MinPriorityQueue {
|
||||
this.heap[k] > this.heap[2 * k] ||
|
||||
this.heap[k] > this.heap[2 * k + 1]
|
||||
) {
|
||||
minIndex =
|
||||
this.heap[2 * k] < this.heap[2 * k + 1] ? 2 * k : 2 * k + 1
|
||||
minIndex = this.heap[2 * k] < this.heap[2 * k + 1] ? 2 * k : 2 * k + 1
|
||||
} else {
|
||||
minIndex = k
|
||||
}
|
||||
@@ -107,7 +109,7 @@ class MinPriorityQueue {
|
||||
|
||||
// deletes the highest priority value from the heap. The last
|
||||
// element goes to ahead to first position and reorder heap
|
||||
delete () {
|
||||
delete() {
|
||||
// checks empty and one element array conditions
|
||||
if (this.isEmpty()) return
|
||||
if (this.size === 1) {
|
||||
|
||||
@@ -9,7 +9,9 @@ describe('MinHeap', () => {
|
||||
})
|
||||
|
||||
it('should initialize a heap from an input array', () => {
|
||||
expect(heap).toEqual({ 'heap': [1, 4, 2, 7, 16, 10, 39, 23, 9, 43, 85, 42, 51] }) // eslint-disable-line
|
||||
expect(heap).toEqual({
|
||||
heap: [1, 4, 2, 7, 16, 10, 39, 23, 9, 43, 85, 42, 51]
|
||||
}) // eslint-disable-line
|
||||
})
|
||||
|
||||
it('should show the top value in the heap', () => {
|
||||
@@ -22,12 +24,14 @@ describe('MinHeap', () => {
|
||||
const minValue = heap.extractMin()
|
||||
|
||||
expect(minValue).toEqual(1)
|
||||
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 42, 39, 23, 9, 43, 85, 51] }) // eslint-disable-line
|
||||
expect(heap).toEqual({ heap: [2, 4, 10, 7, 16, 42, 39, 23, 9, 43, 85, 51] }) // eslint-disable-line
|
||||
})
|
||||
|
||||
it('should insert a new value and sort until it meets heap conditions', () => {
|
||||
heap.insert(15)
|
||||
|
||||
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 15, 39, 23, 9, 43, 85, 51, 42] }) // eslint-disable-line
|
||||
expect(heap).toEqual({
|
||||
heap: [2, 4, 10, 7, 16, 15, 39, 23, 9, 43, 85, 51, 42]
|
||||
}) // eslint-disable-line
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,11 +7,11 @@ describe('MinPriorityQueue', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new MinPriorityQueue(capacity)
|
||||
values.forEach(v => queue.insert(v))
|
||||
values.forEach((v) => queue.insert(v))
|
||||
})
|
||||
|
||||
it('Check heap ordering', () => {
|
||||
const mockFn = jest.fn()
|
||||
const mockFn = vi.fn()
|
||||
queue.print(mockFn)
|
||||
|
||||
expect(mockFn.mock.calls.length).toBe(1) // Expect one call
|
||||
@@ -24,7 +24,7 @@ describe('MinPriorityQueue', () => {
|
||||
|
||||
it('heapSort() expected to reverse the heap ordering', () => {
|
||||
queue.heapReverse()
|
||||
const mockFn = jest.fn()
|
||||
const mockFn = vi.fn()
|
||||
queue.print(mockFn)
|
||||
|
||||
expect(mockFn.mock.calls.length).toBe(1)
|
||||
|
||||
Reference in New Issue
Block a user