heap-typed 1.38.0 → 1.38.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-structures/binary-tree/avl-tree.d.ts +9 -9
- package/dist/data-structures/binary-tree/avl-tree.js +22 -22
- package/dist/data-structures/binary-tree/binary-tree.d.ts +31 -31
- package/dist/data-structures/binary-tree/binary-tree.js +32 -32
- package/dist/data-structures/binary-tree/rb-tree.d.ts +1 -1
- package/dist/data-structures/binary-tree/tree-multiset.d.ts +9 -9
- package/dist/data-structures/binary-tree/tree-multiset.js +23 -23
- package/dist/data-structures/hash/hash-map.d.ts +25 -25
- package/dist/data-structures/hash/hash-map.js +59 -59
- package/dist/data-structures/hash/hash-table.d.ts +34 -34
- package/dist/data-structures/hash/hash-table.js +99 -99
- package/dist/data-structures/heap/heap.d.ts +66 -66
- package/dist/data-structures/heap/heap.js +167 -167
- package/dist/data-structures/linked-list/doubly-linked-list.d.ts +1 -1
- package/dist/data-structures/linked-list/doubly-linked-list.js +3 -3
- package/dist/data-structures/linked-list/skip-linked-list.d.ts +17 -17
- package/dist/data-structures/linked-list/skip-linked-list.js +34 -34
- package/dist/data-structures/matrix/matrix2d.d.ts +7 -7
- package/dist/data-structures/matrix/matrix2d.js +9 -9
- package/dist/data-structures/trie/trie.d.ts +2 -2
- package/dist/data-structures/trie/trie.js +6 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/package.json +1 -4
- package/src/data-structures/binary-tree/avl-tree.ts +27 -27
- package/src/data-structures/binary-tree/binary-tree.ts +55 -55
- package/src/data-structures/binary-tree/bst.ts +4 -0
- package/src/data-structures/binary-tree/rb-tree.ts +2 -2
- package/src/data-structures/binary-tree/tree-multiset.ts +29 -29
- package/src/data-structures/hash/hash-map.ts +81 -75
- package/src/data-structures/hash/hash-table.ts +112 -109
- package/src/data-structures/heap/heap.ts +182 -181
- package/src/data-structures/linked-list/doubly-linked-list.ts +4 -4
- package/src/data-structures/linked-list/skip-linked-list.ts +45 -38
- package/src/data-structures/matrix/matrix2d.ts +10 -10
- package/src/data-structures/trie/trie.ts +9 -9
- package/src/index.ts +3 -3
- package/src/types/helpers.ts +5 -1
|
@@ -21,21 +21,17 @@ export class HashTableNode<K, V> {
|
|
|
21
21
|
import {HashFunction} from '../../types';
|
|
22
22
|
|
|
23
23
|
export class HashTable<K, V> {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
set hashFn(value: HashFunction<K>) {
|
|
29
|
-
this._hashFn = value;
|
|
30
|
-
}
|
|
24
|
+
private static readonly DEFAULT_CAPACITY = 16;
|
|
25
|
+
private static readonly LOAD_FACTOR = 0.75;
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
constructor(capacity: number = HashTable.DEFAULT_CAPACITY, hashFn?: HashFunction<K>) {
|
|
28
|
+
this._hashFn = hashFn || this._defaultHashFn;
|
|
29
|
+
this._capacity = Math.max(capacity, HashTable.DEFAULT_CAPACITY);
|
|
30
|
+
this._size = 0;
|
|
31
|
+
this._buckets = new Array<HashTableNode<K, V> | null>(this._capacity).fill(null);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
this._buckets = value;
|
|
38
|
-
}
|
|
34
|
+
private _capacity: number;
|
|
39
35
|
|
|
40
36
|
get capacity(): number {
|
|
41
37
|
return this._capacity;
|
|
@@ -45,111 +41,30 @@ export class HashTable<K, V> {
|
|
|
45
41
|
this._capacity = value;
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
private static readonly DEFAULT_CAPACITY = 16;
|
|
49
|
-
private static readonly LOAD_FACTOR = 0.75;
|
|
50
|
-
|
|
51
|
-
private _capacity: number;
|
|
52
44
|
private _size: number;
|
|
53
|
-
private _buckets: Array<HashTableNode<K, V> | null>;
|
|
54
|
-
private _hashFn: HashFunction<K>;
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this._capacity = Math.max(capacity, HashTable.DEFAULT_CAPACITY);
|
|
59
|
-
this._size = 0;
|
|
60
|
-
this._buckets = new Array<HashTableNode<K, V> | null>(this._capacity).fill(null);
|
|
46
|
+
get size(): number {
|
|
47
|
+
return this._size;
|
|
61
48
|
}
|
|
62
49
|
|
|
63
|
-
|
|
64
|
-
* The function `_defaultHashFn` calculates the hash value of a given key and returns the remainder when divided by the
|
|
65
|
-
* capacity of the data structure.
|
|
66
|
-
* @param {K} key - The `key` parameter is the input value that needs to be hashed. It can be of any type, but in this
|
|
67
|
-
* code snippet, it is checked whether the key is a string or an object. If it is a string, the `_murmurStringHashFn`
|
|
68
|
-
* function is used to
|
|
69
|
-
* @returns the hash value of the key modulo the capacity of the data structure.
|
|
70
|
-
*/
|
|
71
|
-
protected _defaultHashFn(key: K): number {
|
|
72
|
-
// Can be replaced with other hash functions as needed
|
|
73
|
-
const hashValue = typeof key === 'string' ? this._murmurStringHashFn(key) : this._objectHash(key);
|
|
74
|
-
return hashValue % this._capacity;
|
|
75
|
-
}
|
|
50
|
+
private _buckets: Array<HashTableNode<K, V> | null>;
|
|
76
51
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
* string hash function.
|
|
80
|
-
* @param {K} key - The `key` parameter is the input value for which we want to calculate the hash. It can be of any
|
|
81
|
-
* type, as it is generic (`K`). The function converts the `key` to a string using the `String()` function.
|
|
82
|
-
* @returns a number, which is the result of the multiplicative string hash function applied to the input key.
|
|
83
|
-
*/
|
|
84
|
-
protected _multiplicativeStringHashFn<K>(key: K): number {
|
|
85
|
-
const keyString = String(key);
|
|
86
|
-
let hash = 0;
|
|
87
|
-
for (let i = 0; i < keyString.length; i++) {
|
|
88
|
-
const charCode = keyString.charCodeAt(i);
|
|
89
|
-
// Some constants for adjusting the hash function
|
|
90
|
-
const A = 0.618033988749895;
|
|
91
|
-
const M = 1 << 30; // 2^30
|
|
92
|
-
hash = (hash * A + charCode) % M;
|
|
93
|
-
}
|
|
94
|
-
return Math.abs(hash); // Take absolute value to ensure non-negative numbers
|
|
52
|
+
get buckets(): Array<HashTableNode<K, V> | null> {
|
|
53
|
+
return this._buckets;
|
|
95
54
|
}
|
|
96
55
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* @param {K} key - The `key` parameter is the input value for which you want to calculate the hash. It can be of any
|
|
100
|
-
* type, but it will be converted to a string using the `String()` function before calculating the hash.
|
|
101
|
-
* @returns a number, which is the hash value calculated for the given key.
|
|
102
|
-
*/
|
|
103
|
-
protected _murmurStringHashFn<K>(key: K): number {
|
|
104
|
-
const keyString = String(key);
|
|
105
|
-
const seed = 0;
|
|
106
|
-
let hash = seed;
|
|
107
|
-
|
|
108
|
-
for (let i = 0; i < keyString.length; i++) {
|
|
109
|
-
const char = keyString.charCodeAt(i);
|
|
110
|
-
hash = (hash ^ char) * 0x5bd1e995;
|
|
111
|
-
hash = (hash ^ (hash >>> 15)) * 0x27d4eb2d;
|
|
112
|
-
hash = hash ^ (hash >>> 15);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return Math.abs(hash);
|
|
56
|
+
set buckets(value: Array<HashTableNode<K, V> | null>) {
|
|
57
|
+
this._buckets = value;
|
|
116
58
|
}
|
|
117
59
|
|
|
118
|
-
|
|
119
|
-
* The _hash function takes a key and returns a number.
|
|
120
|
-
* @param {K} key - The parameter "key" is of type K, which represents the type of the key that will be hashed.
|
|
121
|
-
* @returns The hash function is returning a number.
|
|
122
|
-
*/
|
|
123
|
-
protected _hash(key: K): number {
|
|
124
|
-
return this.hashFn(key);
|
|
125
|
-
}
|
|
60
|
+
private _hashFn: HashFunction<K>;
|
|
126
61
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
* @param {string} key - The `key` parameter in the `stringHash` function is a string value that represents the input for
|
|
130
|
-
* which we want to calculate the hash value.
|
|
131
|
-
* @returns a number, which is the hash value of the input string.
|
|
132
|
-
*/
|
|
133
|
-
protected _stringHash(key: string): number {
|
|
134
|
-
let hash = 0;
|
|
135
|
-
for (let i = 0; i < key.length; i++) {
|
|
136
|
-
hash = (hash * 31 + key.charCodeAt(i)) & 0xffffffff;
|
|
137
|
-
}
|
|
138
|
-
return hash;
|
|
62
|
+
get hashFn(): HashFunction<K> {
|
|
63
|
+
return this._hashFn;
|
|
139
64
|
}
|
|
140
65
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
* @param {K} key - The parameter "key" is of type "K", which means it can be any type. It could be a string, number,
|
|
144
|
-
* boolean, object, or any other type of value. The purpose of the objectHash function is to generate a hash value for
|
|
145
|
-
* the key, which can be used for
|
|
146
|
-
* @returns a number, which is the hash value of the key.
|
|
147
|
-
*/
|
|
148
|
-
protected _objectHash(key: K): number {
|
|
149
|
-
// If the key is an object, you can write a custom hash function
|
|
150
|
-
// For example, convert the object's properties to a string and use string hashing
|
|
151
|
-
// This is just an example; you should write a specific object hash function as needed
|
|
152
|
-
return this._stringHash(JSON.stringify(key));
|
|
66
|
+
set hashFn(value: HashFunction<K>) {
|
|
67
|
+
this._hashFn = value;
|
|
153
68
|
}
|
|
154
69
|
|
|
155
70
|
/**
|
|
@@ -240,6 +155,98 @@ export class HashTable<K, V> {
|
|
|
240
155
|
}
|
|
241
156
|
}
|
|
242
157
|
|
|
158
|
+
/**
|
|
159
|
+
* The function `_defaultHashFn` calculates the hash value of a given key and returns the remainder when divided by the
|
|
160
|
+
* capacity of the data structure.
|
|
161
|
+
* @param {K} key - The `key` parameter is the input value that needs to be hashed. It can be of any type, but in this
|
|
162
|
+
* code snippet, it is checked whether the key is a string or an object. If it is a string, the `_murmurStringHashFn`
|
|
163
|
+
* function is used to
|
|
164
|
+
* @returns the hash value of the key modulo the capacity of the data structure.
|
|
165
|
+
*/
|
|
166
|
+
protected _defaultHashFn(key: K): number {
|
|
167
|
+
// Can be replaced with other hash functions as needed
|
|
168
|
+
const hashValue = typeof key === 'string' ? this._murmurStringHashFn(key) : this._objectHash(key);
|
|
169
|
+
return hashValue % this._capacity;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* The `_multiplicativeStringHashFn` function calculates a hash value for a given string key using the multiplicative
|
|
174
|
+
* string hash function.
|
|
175
|
+
* @param {K} key - The `key` parameter is the input value for which we want to calculate the hash. It can be of any
|
|
176
|
+
* type, as it is generic (`K`). The function converts the `key` to a string using the `String()` function.
|
|
177
|
+
* @returns a number, which is the result of the multiplicative string hash function applied to the input key.
|
|
178
|
+
*/
|
|
179
|
+
protected _multiplicativeStringHashFn<K>(key: K): number {
|
|
180
|
+
const keyString = String(key);
|
|
181
|
+
let hash = 0;
|
|
182
|
+
for (let i = 0; i < keyString.length; i++) {
|
|
183
|
+
const charCode = keyString.charCodeAt(i);
|
|
184
|
+
// Some constants for adjusting the hash function
|
|
185
|
+
const A = 0.618033988749895;
|
|
186
|
+
const M = 1 << 30; // 2^30
|
|
187
|
+
hash = (hash * A + charCode) % M;
|
|
188
|
+
}
|
|
189
|
+
return Math.abs(hash); // Take absolute value to ensure non-negative numbers
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The function `_murmurStringHashFn` calculates a hash value for a given string key using the MurmurHash algorithm.
|
|
194
|
+
* @param {K} key - The `key` parameter is the input value for which you want to calculate the hash. It can be of any
|
|
195
|
+
* type, but it will be converted to a string using the `String()` function before calculating the hash.
|
|
196
|
+
* @returns a number, which is the hash value calculated for the given key.
|
|
197
|
+
*/
|
|
198
|
+
protected _murmurStringHashFn<K>(key: K): number {
|
|
199
|
+
const keyString = String(key);
|
|
200
|
+
const seed = 0;
|
|
201
|
+
let hash = seed;
|
|
202
|
+
|
|
203
|
+
for (let i = 0; i < keyString.length; i++) {
|
|
204
|
+
const char = keyString.charCodeAt(i);
|
|
205
|
+
hash = (hash ^ char) * 0x5bd1e995;
|
|
206
|
+
hash = (hash ^ (hash >>> 15)) * 0x27d4eb2d;
|
|
207
|
+
hash = hash ^ (hash >>> 15);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return Math.abs(hash);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The _hash function takes a key and returns a number.
|
|
215
|
+
* @param {K} key - The parameter "key" is of type K, which represents the type of the key that will be hashed.
|
|
216
|
+
* @returns The hash function is returning a number.
|
|
217
|
+
*/
|
|
218
|
+
protected _hash(key: K): number {
|
|
219
|
+
return this.hashFn(key);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* The function calculates a hash value for a given string using the djb2 algorithm.
|
|
224
|
+
* @param {string} key - The `key` parameter in the `stringHash` function is a string value that represents the input for
|
|
225
|
+
* which we want to calculate the hash value.
|
|
226
|
+
* @returns a number, which is the hash value of the input string.
|
|
227
|
+
*/
|
|
228
|
+
protected _stringHash(key: string): number {
|
|
229
|
+
let hash = 0;
|
|
230
|
+
for (let i = 0; i < key.length; i++) {
|
|
231
|
+
hash = (hash * 31 + key.charCodeAt(i)) & 0xffffffff;
|
|
232
|
+
}
|
|
233
|
+
return hash;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* The function `_objectHash` takes a key and returns a hash value, using a custom hash function for objects.
|
|
238
|
+
* @param {K} key - The parameter "key" is of type "K", which means it can be any type. It could be a string, number,
|
|
239
|
+
* boolean, object, or any other type of value. The purpose of the objectHash function is to generate a hash value for
|
|
240
|
+
* the key, which can be used for
|
|
241
|
+
* @returns a number, which is the hash value of the key.
|
|
242
|
+
*/
|
|
243
|
+
protected _objectHash(key: K): number {
|
|
244
|
+
// If the key is an object, you can write a custom hash function
|
|
245
|
+
// For example, convert the object's properties to a string and use string hashing
|
|
246
|
+
// This is just an example; you should write a specific object hash function as needed
|
|
247
|
+
return this._stringHash(JSON.stringify(key));
|
|
248
|
+
}
|
|
249
|
+
|
|
243
250
|
/**
|
|
244
251
|
* The `expand` function increases the capacity of a hash table by creating a new array of buckets with double the
|
|
245
252
|
* capacity and rehashing all the existing key-value pairs into the new buckets.
|
|
@@ -270,8 +277,4 @@ export class HashTable<K, V> {
|
|
|
270
277
|
this._buckets = newBuckets;
|
|
271
278
|
this._capacity = newCapacity;
|
|
272
279
|
}
|
|
273
|
-
|
|
274
|
-
get size(): number {
|
|
275
|
-
return this._size;
|
|
276
|
-
}
|
|
277
280
|
}
|
|
@@ -15,6 +15,34 @@ export class Heap<E> {
|
|
|
15
15
|
this.comparator = comparator;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Get the size (number of elements) of the heap.
|
|
20
|
+
*/
|
|
21
|
+
get size(): number {
|
|
22
|
+
return this.nodes.length;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the last element in the heap, which is not necessarily a leaf node.
|
|
27
|
+
* @returns The last element or undefined if the heap is empty.
|
|
28
|
+
*/
|
|
29
|
+
get leaf(): E | undefined {
|
|
30
|
+
return this.nodes[this.size - 1] ?? undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Static method that creates a binary heap from an array of nodes and a comparison function.
|
|
35
|
+
* @param nodes
|
|
36
|
+
* @param comparator - Comparison function.
|
|
37
|
+
* @returns A new Heap instance.
|
|
38
|
+
*/
|
|
39
|
+
static heapify<E>(nodes: E[], comparator: Comparator<E>): Heap<E> {
|
|
40
|
+
const binaryHeap = new Heap<E>(comparator);
|
|
41
|
+
binaryHeap.nodes = [...nodes];
|
|
42
|
+
binaryHeap.fix(); // Fix heap properties
|
|
43
|
+
return binaryHeap;
|
|
44
|
+
}
|
|
45
|
+
|
|
18
46
|
/**
|
|
19
47
|
* Insert an element into the heap and maintain the heap properties.
|
|
20
48
|
* @param element - The element to be inserted.
|
|
@@ -59,57 +87,6 @@ export class Heap<E> {
|
|
|
59
87
|
return this.poll();
|
|
60
88
|
}
|
|
61
89
|
|
|
62
|
-
/**
|
|
63
|
-
* Float operation to maintain heap properties after adding an element.
|
|
64
|
-
* @param index - The index of the newly added element.
|
|
65
|
-
*/
|
|
66
|
-
protected bubbleUp(index: number): void {
|
|
67
|
-
const element = this.nodes[index];
|
|
68
|
-
while (index > 0) {
|
|
69
|
-
const parentIndex = Math.floor((index - 1) / 2);
|
|
70
|
-
const parent = this.nodes[parentIndex];
|
|
71
|
-
if (this.comparator(element, parent) < 0) {
|
|
72
|
-
this.nodes[index] = parent;
|
|
73
|
-
this.nodes[parentIndex] = element;
|
|
74
|
-
index = parentIndex;
|
|
75
|
-
} else {
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Sinking operation to maintain heap properties after removing the top element.
|
|
83
|
-
* @param index - The index from which to start sinking.
|
|
84
|
-
*/
|
|
85
|
-
protected sinkDown(index: number): void {
|
|
86
|
-
const leftChildIndex = 2 * index + 1;
|
|
87
|
-
const rightChildIndex = 2 * index + 2;
|
|
88
|
-
const length = this.nodes.length;
|
|
89
|
-
let targetIndex = index;
|
|
90
|
-
|
|
91
|
-
if (leftChildIndex < length && this.comparator(this.nodes[leftChildIndex], this.nodes[targetIndex]) < 0) {
|
|
92
|
-
targetIndex = leftChildIndex;
|
|
93
|
-
}
|
|
94
|
-
if (rightChildIndex < length && this.comparator(this.nodes[rightChildIndex], this.nodes[targetIndex]) < 0) {
|
|
95
|
-
targetIndex = rightChildIndex;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (targetIndex !== index) {
|
|
99
|
-
const temp = this.nodes[index];
|
|
100
|
-
this.nodes[index] = this.nodes[targetIndex];
|
|
101
|
-
this.nodes[targetIndex] = temp;
|
|
102
|
-
this.sinkDown(targetIndex);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Fix the entire heap to maintain heap properties.
|
|
108
|
-
*/
|
|
109
|
-
protected fix() {
|
|
110
|
-
for (let i = Math.floor(this.size / 2); i >= 0; i--) this.sinkDown(i);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
90
|
/**
|
|
114
91
|
* Peek at the top element of the heap without removing it.
|
|
115
92
|
* @returns The top element or undefined if the heap is empty.
|
|
@@ -121,21 +98,6 @@ export class Heap<E> {
|
|
|
121
98
|
return this.nodes[0];
|
|
122
99
|
}
|
|
123
100
|
|
|
124
|
-
/**
|
|
125
|
-
* Get the size (number of elements) of the heap.
|
|
126
|
-
*/
|
|
127
|
-
get size(): number {
|
|
128
|
-
return this.nodes.length;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Get the last element in the heap, which is not necessarily a leaf node.
|
|
133
|
-
* @returns The last element or undefined if the heap is empty.
|
|
134
|
-
*/
|
|
135
|
-
get leaf(): E | undefined {
|
|
136
|
-
return this.nodes[this.size - 1] ?? undefined;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
101
|
/**
|
|
140
102
|
* Check if the heap is empty.
|
|
141
103
|
* @returns True if the heap is empty, otherwise false.
|
|
@@ -238,16 +200,54 @@ export class Heap<E> {
|
|
|
238
200
|
}
|
|
239
201
|
|
|
240
202
|
/**
|
|
241
|
-
*
|
|
242
|
-
* @param
|
|
243
|
-
* @param comparator - Comparison function.
|
|
244
|
-
* @returns A new Heap instance.
|
|
203
|
+
* Float operation to maintain heap properties after adding an element.
|
|
204
|
+
* @param index - The index of the newly added element.
|
|
245
205
|
*/
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
206
|
+
protected bubbleUp(index: number): void {
|
|
207
|
+
const element = this.nodes[index];
|
|
208
|
+
while (index > 0) {
|
|
209
|
+
const parentIndex = Math.floor((index - 1) / 2);
|
|
210
|
+
const parent = this.nodes[parentIndex];
|
|
211
|
+
if (this.comparator(element, parent) < 0) {
|
|
212
|
+
this.nodes[index] = parent;
|
|
213
|
+
this.nodes[parentIndex] = element;
|
|
214
|
+
index = parentIndex;
|
|
215
|
+
} else {
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Sinking operation to maintain heap properties after removing the top element.
|
|
223
|
+
* @param index - The index from which to start sinking.
|
|
224
|
+
*/
|
|
225
|
+
protected sinkDown(index: number): void {
|
|
226
|
+
const leftChildIndex = 2 * index + 1;
|
|
227
|
+
const rightChildIndex = 2 * index + 2;
|
|
228
|
+
const length = this.nodes.length;
|
|
229
|
+
let targetIndex = index;
|
|
230
|
+
|
|
231
|
+
if (leftChildIndex < length && this.comparator(this.nodes[leftChildIndex], this.nodes[targetIndex]) < 0) {
|
|
232
|
+
targetIndex = leftChildIndex;
|
|
233
|
+
}
|
|
234
|
+
if (rightChildIndex < length && this.comparator(this.nodes[rightChildIndex], this.nodes[targetIndex]) < 0) {
|
|
235
|
+
targetIndex = rightChildIndex;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (targetIndex !== index) {
|
|
239
|
+
const temp = this.nodes[index];
|
|
240
|
+
this.nodes[index] = this.nodes[targetIndex];
|
|
241
|
+
this.nodes[targetIndex] = temp;
|
|
242
|
+
this.sinkDown(targetIndex);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Fix the entire heap to maintain heap properties.
|
|
248
|
+
*/
|
|
249
|
+
protected fix() {
|
|
250
|
+
for (let i = Math.floor(this.size / 2); i >= 0; i--) this.sinkDown(i);
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
|
|
@@ -259,6 +259,7 @@ export class FibonacciHeapNode<E> {
|
|
|
259
259
|
child?: FibonacciHeapNode<E>;
|
|
260
260
|
parent?: FibonacciHeapNode<E>;
|
|
261
261
|
marked: boolean;
|
|
262
|
+
|
|
262
263
|
constructor(element: E, degree = 0) {
|
|
263
264
|
this.element = element;
|
|
264
265
|
this.degree = degree;
|
|
@@ -268,8 +269,8 @@ export class FibonacciHeapNode<E> {
|
|
|
268
269
|
|
|
269
270
|
export class FibonacciHeap<E> {
|
|
270
271
|
root?: FibonacciHeapNode<E>;
|
|
271
|
-
protected min?: FibonacciHeapNode<E>;
|
|
272
272
|
size: number = 0;
|
|
273
|
+
protected min?: FibonacciHeapNode<E>;
|
|
273
274
|
protected readonly comparator: Comparator<E>;
|
|
274
275
|
|
|
275
276
|
constructor(comparator?: Comparator<E>) {
|
|
@@ -281,18 +282,6 @@ export class FibonacciHeap<E> {
|
|
|
281
282
|
}
|
|
282
283
|
}
|
|
283
284
|
|
|
284
|
-
/**
|
|
285
|
-
* Default comparator function used by the heap.
|
|
286
|
-
* @param {E} a
|
|
287
|
-
* @param {E} b
|
|
288
|
-
* @protected
|
|
289
|
-
*/
|
|
290
|
-
protected defaultComparator(a: E, b: E): number {
|
|
291
|
-
if (a < b) return -1;
|
|
292
|
-
if (a > b) return 1;
|
|
293
|
-
return 0;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
285
|
/**
|
|
297
286
|
* Get the size (number of elements) of the heap.
|
|
298
287
|
* @returns {number} The size of the heap. Returns 0 if the heap is empty. Returns -1 if the heap is invalid.
|
|
@@ -303,30 +292,6 @@ export class FibonacciHeap<E> {
|
|
|
303
292
|
this.size = 0;
|
|
304
293
|
}
|
|
305
294
|
|
|
306
|
-
/**
|
|
307
|
-
* Create a new node.
|
|
308
|
-
* @param element
|
|
309
|
-
* @protected
|
|
310
|
-
*/
|
|
311
|
-
protected createNode(element: E): FibonacciHeapNode<E> {
|
|
312
|
-
return new FibonacciHeapNode<E>(element);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Merge the given node with the root list.
|
|
317
|
-
* @param node - The node to be merged.
|
|
318
|
-
*/
|
|
319
|
-
protected mergeWithRoot(node: FibonacciHeapNode<E>): void {
|
|
320
|
-
if (!this.root) {
|
|
321
|
-
this.root = node;
|
|
322
|
-
} else {
|
|
323
|
-
node.right = this.root.right;
|
|
324
|
-
node.left = this.root;
|
|
325
|
-
this.root.right!.left = node;
|
|
326
|
-
this.root.right = node;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
295
|
/**
|
|
331
296
|
* O(1) time operation.
|
|
332
297
|
* Insert an element into the heap and maintain the heap properties.
|
|
@@ -394,18 +359,6 @@ export class FibonacciHeap<E> {
|
|
|
394
359
|
return nodes;
|
|
395
360
|
}
|
|
396
361
|
|
|
397
|
-
/**
|
|
398
|
-
* O(log n) time operation.
|
|
399
|
-
* Remove and return the top element (smallest or largest element) from the heap.
|
|
400
|
-
* @param node - The node to be removed.
|
|
401
|
-
* @protected
|
|
402
|
-
*/
|
|
403
|
-
protected removeFromRoot(node: FibonacciHeapNode<E>): void {
|
|
404
|
-
if (this.root === node) this.root = node.right;
|
|
405
|
-
if (node.left) node.left.right = node.right;
|
|
406
|
-
if (node.right) node.right.left = node.left;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
362
|
/**
|
|
410
363
|
* O(log n) time operation.
|
|
411
364
|
* Remove and return the top element (smallest or largest element) from the heap.
|
|
@@ -423,63 +376,6 @@ export class FibonacciHeap<E> {
|
|
|
423
376
|
}
|
|
424
377
|
}
|
|
425
378
|
|
|
426
|
-
/**
|
|
427
|
-
* O(log n) time operation.
|
|
428
|
-
* Remove and return the top element (smallest or largest element) from the heap.
|
|
429
|
-
* @param y
|
|
430
|
-
* @param x
|
|
431
|
-
* @protected
|
|
432
|
-
*/
|
|
433
|
-
protected link(y: FibonacciHeapNode<E>, x: FibonacciHeapNode<E>): void {
|
|
434
|
-
this.removeFromRoot(y);
|
|
435
|
-
y.left = y;
|
|
436
|
-
y.right = y;
|
|
437
|
-
this.mergeWithChild(x, y);
|
|
438
|
-
x.degree++;
|
|
439
|
-
y.parent = x;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* O(log n) time operation.
|
|
444
|
-
* Remove and return the top element (smallest or largest element) from the heap.
|
|
445
|
-
* @protected
|
|
446
|
-
*/
|
|
447
|
-
protected consolidate(): void {
|
|
448
|
-
const A: (FibonacciHeapNode<E> | undefined)[] = new Array(this.size);
|
|
449
|
-
const nodes = this.consumeLinkedList(this.root);
|
|
450
|
-
let x: FibonacciHeapNode<E> | undefined,
|
|
451
|
-
y: FibonacciHeapNode<E> | undefined,
|
|
452
|
-
d: number,
|
|
453
|
-
t: FibonacciHeapNode<E> | undefined;
|
|
454
|
-
|
|
455
|
-
for (const node of nodes) {
|
|
456
|
-
x = node;
|
|
457
|
-
d = x.degree;
|
|
458
|
-
|
|
459
|
-
while (A[d]) {
|
|
460
|
-
y = A[d] as FibonacciHeapNode<E>;
|
|
461
|
-
|
|
462
|
-
if (this.comparator(x.element, y.element) > 0) {
|
|
463
|
-
t = x;
|
|
464
|
-
x = y;
|
|
465
|
-
y = t;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
this.link(y, x);
|
|
469
|
-
A[d] = undefined;
|
|
470
|
-
d++;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
A[d] = x;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
for (let i = 0; i < this.size; i++) {
|
|
477
|
-
if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) {
|
|
478
|
-
this.min = A[i]!;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
379
|
/**
|
|
484
380
|
* O(log n) time operation.
|
|
485
381
|
* Remove and return the top element (smallest or largest element) from the heap.
|
|
@@ -557,4 +453,109 @@ export class FibonacciHeap<E> {
|
|
|
557
453
|
// Clear the heap that was merged
|
|
558
454
|
heapToMerge.clear();
|
|
559
455
|
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Default comparator function used by the heap.
|
|
459
|
+
* @param {E} a
|
|
460
|
+
* @param {E} b
|
|
461
|
+
* @protected
|
|
462
|
+
*/
|
|
463
|
+
protected defaultComparator(a: E, b: E): number {
|
|
464
|
+
if (a < b) return -1;
|
|
465
|
+
if (a > b) return 1;
|
|
466
|
+
return 0;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Create a new node.
|
|
471
|
+
* @param element
|
|
472
|
+
* @protected
|
|
473
|
+
*/
|
|
474
|
+
protected createNode(element: E): FibonacciHeapNode<E> {
|
|
475
|
+
return new FibonacciHeapNode<E>(element);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Merge the given node with the root list.
|
|
480
|
+
* @param node - The node to be merged.
|
|
481
|
+
*/
|
|
482
|
+
protected mergeWithRoot(node: FibonacciHeapNode<E>): void {
|
|
483
|
+
if (!this.root) {
|
|
484
|
+
this.root = node;
|
|
485
|
+
} else {
|
|
486
|
+
node.right = this.root.right;
|
|
487
|
+
node.left = this.root;
|
|
488
|
+
this.root.right!.left = node;
|
|
489
|
+
this.root.right = node;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* O(log n) time operation.
|
|
495
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
496
|
+
* @param node - The node to be removed.
|
|
497
|
+
* @protected
|
|
498
|
+
*/
|
|
499
|
+
protected removeFromRoot(node: FibonacciHeapNode<E>): void {
|
|
500
|
+
if (this.root === node) this.root = node.right;
|
|
501
|
+
if (node.left) node.left.right = node.right;
|
|
502
|
+
if (node.right) node.right.left = node.left;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* O(log n) time operation.
|
|
507
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
508
|
+
* @param y
|
|
509
|
+
* @param x
|
|
510
|
+
* @protected
|
|
511
|
+
*/
|
|
512
|
+
protected link(y: FibonacciHeapNode<E>, x: FibonacciHeapNode<E>): void {
|
|
513
|
+
this.removeFromRoot(y);
|
|
514
|
+
y.left = y;
|
|
515
|
+
y.right = y;
|
|
516
|
+
this.mergeWithChild(x, y);
|
|
517
|
+
x.degree++;
|
|
518
|
+
y.parent = x;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* O(log n) time operation.
|
|
523
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
524
|
+
* @protected
|
|
525
|
+
*/
|
|
526
|
+
protected consolidate(): void {
|
|
527
|
+
const A: (FibonacciHeapNode<E> | undefined)[] = new Array(this.size);
|
|
528
|
+
const nodes = this.consumeLinkedList(this.root);
|
|
529
|
+
let x: FibonacciHeapNode<E> | undefined,
|
|
530
|
+
y: FibonacciHeapNode<E> | undefined,
|
|
531
|
+
d: number,
|
|
532
|
+
t: FibonacciHeapNode<E> | undefined;
|
|
533
|
+
|
|
534
|
+
for (const node of nodes) {
|
|
535
|
+
x = node;
|
|
536
|
+
d = x.degree;
|
|
537
|
+
|
|
538
|
+
while (A[d]) {
|
|
539
|
+
y = A[d] as FibonacciHeapNode<E>;
|
|
540
|
+
|
|
541
|
+
if (this.comparator(x.element, y.element) > 0) {
|
|
542
|
+
t = x;
|
|
543
|
+
x = y;
|
|
544
|
+
y = t;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
this.link(y, x);
|
|
548
|
+
A[d] = undefined;
|
|
549
|
+
d++;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
A[d] = x;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
for (let i = 0; i < this.size; i++) {
|
|
556
|
+
if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) {
|
|
557
|
+
this.min = A[i]!;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
560
561
|
}
|