This repository was archived by the owner on Apr 5, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
145 lines (112 loc) · 4.43 KB
/
index.ts
File metadata and controls
145 lines (112 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { ArrayList } from "../array-list";
export class PriorityQueue<T> {
private _list = new ArrayList<{ value: T, priority: number }>();
/**
* Creates a new Priority Queue
* @param isMaxQueue Should items pop with larger priorities first
**/
constructor(private isMaxQueue: boolean) { }
/**
* Return the parent of the node at the specified index as
* ```typescript
* { value: T, priority: number, index: number }
* ```
* **Returns null if trying to get the parent of root**
*/
private parentOf = (i: number) => {
if (i === 0) return null;
const parentIdx = ~~((i - 1) / 2); // Double tilde is equivalent to floor()
return this._list.has(parentIdx)
? ({ ...this._list.get(parentIdx), index: parentIdx })
: null;
}
/**
* Return the right-side child of the node at the specified index as
* ```typescript
* { value: T, priority: number, index: number }
* ```
* **Returns null if a right-side child doesn't exist**
*/
private rChildOf = (i: number) => {
const childIndex = 2 * i + 2;
return this._list.has(childIndex)
? ({ ...this._list.get(childIndex), index: childIndex })
: null;
}
/**
* Return the left-side child of the node at the specified index as
* ```typescript
* { value: T, priority: number, index: number }
* ```
* **Returns null if a left-side child doesn't exist**
*/
private lChildOf = (i: number) => {
const childIndex = 2 * i + 1;
return this._list.has(childIndex)
? ({ ...this._list.get(childIndex), index: childIndex })
: null;
}
public size = () => this._list.size();
/**
* Push the given value into the queue with the specified priority.
*/
public push(value: T, priority: number) {
// A very basic min/max-heapify implementation
const list = this._list;
list.add({ value, priority });
let nodeIdx = list.getTail().index;
while (true) {
const parent = this.parentOf(nodeIdx);
if (!parent) break;
if (this.isMaxQueue && priority < parent.priority) break;
if (!this.isMaxQueue && priority > parent.priority) break;
list.swapByIndex(nodeIdx, parent.index);
nodeIdx = parent.index;
}
}
/**
* Retrieve and remove the most/least prioritised element in the queue.
*/
public pop() {
// Again very basic element removal from a min/max-heap
const list = this._list;
list.swapByIndex(0, list.getTail().index);
const { value } = list.popTail();
// The heap is either empty or has a single node left, so we can skip the rest of max/min-heapify
if (list.size() < 2) return value;
let nodeIdx = 0;
while (true) {
const { priority } = list.get(nodeIdx);
const rChild = this.rChildOf(nodeIdx);
const lChild = this.lChildOf(nodeIdx);
// If neither child exist, the node is a leaf and min/max-heapify is complete
if (!rChild && !lChild) break;
if (this.isMaxQueue) {
// - If either child doesn't exist (one must as per above),
// the one that does exist is automatically the max child
// - If both exist, the max child is the one with a higher priority
// - If both exist and have equal priority, it doesn't matter which one
// is used as the max child
const maxChild = !rChild || !lChild
? (rChild ?? lChild)!
: rChild.priority > lChild.priority
? rChild
: lChild;
if (maxChild.priority < priority) break;
list.swapByIndex(nodeIdx, maxChild.index);
nodeIdx = maxChild.index;
} else {
// Just a mirrored version of the above
const minChild = !rChild || !lChild
? (rChild ?? lChild)!
: rChild.priority < lChild.priority
? rChild
: lChild;
if (minChild.priority > priority) break;
list.swapByIndex(nodeIdx, minChild.index);
nodeIdx = minChild.index;
}
}
return value;
}
}