Skip to content

Commit d00827c

Browse files
committed
fix: preserve heap order for infinite key priorities
1 parent 5c39e87 commit d00827c

2 files changed

Lines changed: 135 additions & 1 deletion

File tree

‎Data-Structures/Heap/KeyPriorityQueue.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class KeyPriorityQueue {
126126
let child2Priority = this._getPriorityOrInfinite(child2Pos)
127127
let currPriority = this._getPriorityOrInfinite(currPos)
128128

129-
if (currPriority === Infinity) {
129+
if (currPos >= this._heap.length) {
130130
return
131131
}
132132

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { KeyPriorityQueue } from '../KeyPriorityQueue.js'
2+
3+
describe('KeyPriorityQueue with infinite priorities', () => {
4+
const assertHeap = (queue, priorities) => {
5+
expect(queue._heap.length).toBe(priorities.size)
6+
expect(queue.priorities).toEqual(priorities)
7+
expect(new Set(queue._heap)).toEqual(new Set(priorities.keys()))
8+
expect(queue.isEmpty()).toBe(priorities.size === 0)
9+
for (const key of priorities.keys()) {
10+
expect(queue.contains(key)).toBe(true)
11+
}
12+
for (let child = 1; child < queue._heap.length; child++) {
13+
const parent = Math.floor((child - 1) / 2)
14+
const parentPriority = priorities.get(queue._heap[parent])
15+
const childPriority = priorities.get(queue._heap[child])
16+
expect(parentPriority).toBeLessThanOrEqual(childPriority)
17+
}
18+
if (priorities.size > 0) {
19+
const minimum = Math.min(...priorities.values())
20+
expect(priorities.get(queue._heap[0])).toBe(minimum)
21+
}
22+
}
23+
24+
const popMinimum = (queue, priorities) => {
25+
const minimum = Math.min(...priorities.values())
26+
const key = queue.pop()
27+
expect(priorities.has(key)).toBe(true)
28+
expect(priorities.get(key)).toBe(minimum)
29+
priorities.delete(key)
30+
expect(queue.contains(key)).toBe(false)
31+
assertHeap(queue, priorities)
32+
return key
33+
}
34+
35+
it.each([
36+
[0, 1, Infinity],
37+
[0, 2, 1, Infinity],
38+
[0, 1, 2, 3, 4, 5, Infinity]
39+
])('sinks an infinite replacement after popping %j', (...values) => {
40+
const queue = new KeyPriorityQueue()
41+
const priorities = new Map()
42+
values.forEach((priority, key) => {
43+
queue.push(key, priority)
44+
priorities.set(key, priority)
45+
})
46+
expect(popMinimum(queue, priorities)).toBe(0)
47+
while (priorities.size > 0) {
48+
popMinimum(queue, priorities)
49+
}
50+
})
51+
52+
it('sinks the root when its priority increases to Infinity', () => {
53+
const queue = new KeyPriorityQueue()
54+
queue.push('root', 0)
55+
queue.push('left', 1)
56+
queue.push('right', 2)
57+
queue.update('root', Infinity)
58+
const priorities = new Map([
59+
['root', Infinity],
60+
['left', 1],
61+
['right', 2]
62+
])
63+
assertHeap(queue, priorities)
64+
expect(popMinimum(queue, priorities)).toBe('left')
65+
expect(popMinimum(queue, priorities)).toBe('right')
66+
expect(popMinimum(queue, priorities)).toBe('root')
67+
})
68+
69+
it('sinks an internal node past finite descendants', () => {
70+
const queue = new KeyPriorityQueue()
71+
const priorities = new Map()
72+
for (let key = 0; key < 7; key++) {
73+
queue.push(key, key)
74+
priorities.set(key, key)
75+
}
76+
queue.update(1, Infinity)
77+
priorities.set(1, Infinity)
78+
assertHeap(queue, priorities)
79+
queue.update(1, -1)
80+
priorities.set(1, -1)
81+
assertHeap(queue, priorities)
82+
expect(popMinimum(queue, priorities)).toBe(1)
83+
while (priorities.size > 0) {
84+
popMinimum(queue, priorities)
85+
}
86+
})
87+
88+
it('drains equal infinite priorities and can be reused', () => {
89+
const queue = new KeyPriorityQueue()
90+
const priorities = new Map()
91+
for (const key of ['a', 'b', 'c', 'd']) {
92+
queue.push(key, Infinity)
93+
priorities.set(key, Infinity)
94+
}
95+
assertHeap(queue, priorities)
96+
while (priorities.size > 0) {
97+
popMinimum(queue, priorities)
98+
}
99+
queue.update('new', Infinity)
100+
priorities.set('new', Infinity)
101+
queue.push('finite', -3)
102+
priorities.set('finite', -3)
103+
assertHeap(queue, priorities)
104+
expect(popMinimum(queue, priorities)).toBe('finite')
105+
expect(popMinimum(queue, priorities)).toBe('new')
106+
})
107+
108+
it('matches a reference map through mixed updates and extractions', () => {
109+
const queue = new KeyPriorityQueue()
110+
const priorities = new Map()
111+
for (let key = 0; key < 24; key++) {
112+
const priority = key % 3 === 0 ? Infinity : key - 12
113+
queue.push(key, priority)
114+
priorities.set(key, priority)
115+
}
116+
assertHeap(queue, priorities)
117+
for (let step = 0; step < 12; step++) {
118+
const key = queue._heap[0]
119+
queue.update(key, Infinity)
120+
priorities.set(key, Infinity)
121+
assertHeap(queue, priorities)
122+
const leaf = queue._heap[queue._heap.length - 1]
123+
const priority = step % 2 === 0 ? -Infinity : -step
124+
queue.update(leaf, priority)
125+
priorities.set(leaf, priority)
126+
assertHeap(queue, priorities)
127+
popMinimum(queue, priorities)
128+
}
129+
while (priorities.size > 0) {
130+
popMinimum(queue, priorities)
131+
}
132+
expect(queue.priorities.size).toBe(0)
133+
})
134+
})

0 commit comments

Comments
 (0)