data-structure-typed 1.36.9 → 1.37.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/CHANGELOG.md +2 -1
- package/dist/data-structures/binary-tree/binary-tree.d.ts +1 -11
- package/dist/data-structures/binary-tree/binary-tree.js +8 -57
- package/dist/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/data-structures/binary-tree/bst.d.ts +6 -20
- package/dist/data-structures/binary-tree/bst.js +22 -122
- package/dist/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/data-structures/binary-tree/tree-multiset.d.ts +1 -55
- package/dist/data-structures/binary-tree/tree-multiset.js +3 -240
- package/dist/data-structures/binary-tree/tree-multiset.js.map +1 -1
- package/dist/data-structures/graph/abstract-graph.js +4 -3
- package/dist/data-structures/graph/abstract-graph.js.map +1 -1
- package/lib/data-structures/binary-tree/binary-tree.d.ts +1 -11
- package/lib/data-structures/binary-tree/binary-tree.js +8 -57
- package/lib/data-structures/binary-tree/bst.d.ts +6 -20
- package/lib/data-structures/binary-tree/bst.js +22 -122
- package/lib/data-structures/binary-tree/tree-multiset.d.ts +1 -55
- package/lib/data-structures/binary-tree/tree-multiset.js +3 -240
- package/lib/data-structures/graph/abstract-graph.js +4 -3
- package/package.json +9 -7
- package/src/data-structures/binary-tree/binary-tree.ts +100 -504
- package/src/data-structures/binary-tree/bst.ts +58 -128
- package/src/data-structures/binary-tree/tree-multiset.ts +2 -312
- package/src/data-structures/graph/abstract-graph.ts +4 -3
- package/src/data-structures/heap/heap.ts +1 -1
- package/src/types/data-structures/binary-tree.ts +4 -0
- package/src/types/data-structures/index.ts +3 -0
- package/test/unit/data-structures/binary-tree/avl-tree.test.ts +14 -9
- package/test/unit/data-structures/binary-tree/binary-tree.test.ts +1 -1
- package/test/unit/data-structures/binary-tree/bst.test.ts +85 -18
- package/test/unit/data-structures/binary-tree/overall.test.ts +3 -2
- package/test/unit/data-structures/binary-tree/rb-tree.test.ts +5 -5
- package/test/unit/data-structures/binary-tree/tree-multiset.test.ts +43 -18
- package/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +1 -1
- package/test/unit/data-structures/queue/deque.test.ts +17 -0
- package/test/unit/data-structures/queue/queue.test.ts +42 -0
- package/test/utils/big-o.ts +5 -4
- package/umd/bundle.min.js +1 -1
- package/umd/bundle.min.js.map +1 -1
|
@@ -7,14 +7,16 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type {
|
|
9
9
|
BinaryTreeNodeKey,
|
|
10
|
-
BinaryTreeNodePropertyName,
|
|
11
10
|
BSTComparator,
|
|
12
11
|
BSTNodeNested,
|
|
13
|
-
BSTOptions
|
|
12
|
+
BSTOptions,
|
|
13
|
+
MapCallback,
|
|
14
|
+
MapCallbackReturn
|
|
14
15
|
} from '../../types';
|
|
15
16
|
import {CP, LoopType} from '../../types';
|
|
16
17
|
import {BinaryTree, BinaryTreeNode} from './binary-tree';
|
|
17
18
|
import {IBinaryTree} from '../../interfaces';
|
|
19
|
+
import {Queue} from '../queue';
|
|
18
20
|
|
|
19
21
|
export class BSTNode<V = any, FAMILY extends BSTNode<V, FAMILY> = BSTNodeNested<V>> extends BinaryTreeNode<V, FAMILY> {
|
|
20
22
|
constructor(key: BinaryTreeNodeKey, val?: V) {
|
|
@@ -59,7 +61,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|
|
59
61
|
* @returns The function `add` returns the inserted node (`inserted`) which can be of type `N`, `null`, or `undefined`.
|
|
60
62
|
*/
|
|
61
63
|
override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined {
|
|
62
|
-
// TODO support node as a
|
|
64
|
+
// TODO support node as a parameter
|
|
63
65
|
let inserted: N | null = null;
|
|
64
66
|
let newNode: N | null = null;
|
|
65
67
|
if (keyOrNode instanceof BSTNode) {
|
|
@@ -137,8 +139,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|
|
137
139
|
override addMany(
|
|
138
140
|
keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[],
|
|
139
141
|
data?: N['val'][],
|
|
140
|
-
isBalanceAdd =
|
|
142
|
+
isBalanceAdd = true
|
|
141
143
|
): (N | null | undefined)[] {
|
|
144
|
+
// TODO this addMany function is inefficient, it should be optimized
|
|
142
145
|
function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] {
|
|
143
146
|
return arr.indexOf(null) === -1;
|
|
144
147
|
}
|
|
@@ -209,12 +212,12 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|
|
209
212
|
* The function returns the first node in a binary tree that matches the given property name and value.
|
|
210
213
|
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
|
|
211
214
|
* generic type `N`. It represents the property of the binary tree node that you want to search for.
|
|
212
|
-
* @param
|
|
215
|
+
* @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
|
|
213
216
|
* specifies the property name to use for searching the binary tree nodes. If not provided, it defaults to `'key'`.
|
|
214
217
|
* @returns The method is returning either a BinaryTreeNodeKey or N (generic type) or null.
|
|
215
218
|
*/
|
|
216
|
-
override get(nodeProperty: BinaryTreeNodeKey | N,
|
|
217
|
-
return this.getNodes(nodeProperty,
|
|
219
|
+
override get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback<N> = this._defaultCallbackByKey): N | null {
|
|
220
|
+
return this.getNodes(nodeProperty, callback, true)[0] ?? null;
|
|
218
221
|
}
|
|
219
222
|
|
|
220
223
|
/**
|
|
@@ -234,27 +237,34 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|
|
234
237
|
* The function `getNodes` returns an array of nodes in a binary tree that match a given property value.
|
|
235
238
|
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or an
|
|
236
239
|
* `N` type. It represents the property of the binary tree node that you want to compare with.
|
|
237
|
-
* @param
|
|
240
|
+
* @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
|
|
238
241
|
* specifies the property name to use for comparison. If not provided, it defaults to `'key'`.
|
|
239
242
|
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
|
|
240
243
|
* return only one node that matches the given `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne`
|
|
241
244
|
* is set to `true`, the function will return an array with only one node (if
|
|
245
|
+
* @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to
|
|
242
246
|
* @returns an array of nodes (type N).
|
|
243
247
|
*/
|
|
244
248
|
override getNodes(
|
|
245
249
|
nodeProperty: BinaryTreeNodeKey | N,
|
|
246
|
-
|
|
247
|
-
onlyOne = false
|
|
250
|
+
callback: MapCallback<N> = this._defaultCallbackByKey,
|
|
251
|
+
onlyOne = false,
|
|
252
|
+
beginRoot: N | null = this.root
|
|
248
253
|
): N[] {
|
|
249
|
-
if (!
|
|
250
|
-
const
|
|
254
|
+
if (!beginRoot) return [];
|
|
255
|
+
const ans: N[] = [];
|
|
251
256
|
|
|
252
257
|
if (this.loopType === LoopType.RECURSIVE) {
|
|
253
258
|
const _traverse = (cur: N) => {
|
|
254
|
-
|
|
259
|
+
const callbackResult = callback(cur);
|
|
260
|
+
if (callbackResult === nodeProperty) {
|
|
261
|
+
ans.push(cur);
|
|
262
|
+
if (onlyOne) return;
|
|
263
|
+
}
|
|
255
264
|
|
|
256
265
|
if (!cur.left && !cur.right) return;
|
|
257
|
-
|
|
266
|
+
// TODO potential bug
|
|
267
|
+
if (callback === this._defaultCallbackByKey) {
|
|
258
268
|
if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && _traverse(cur.left);
|
|
259
269
|
if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && _traverse(cur.right);
|
|
260
270
|
} else {
|
|
@@ -263,14 +273,19 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|
|
263
273
|
}
|
|
264
274
|
};
|
|
265
275
|
|
|
266
|
-
_traverse(
|
|
276
|
+
_traverse(beginRoot);
|
|
267
277
|
} else {
|
|
268
|
-
const queue
|
|
269
|
-
while (queue.
|
|
278
|
+
const queue = new Queue<N>([beginRoot]);
|
|
279
|
+
while (queue.size > 0) {
|
|
270
280
|
const cur = queue.shift();
|
|
271
281
|
if (cur) {
|
|
272
|
-
|
|
273
|
-
if (
|
|
282
|
+
const callbackResult = callback(cur);
|
|
283
|
+
if (callbackResult === nodeProperty) {
|
|
284
|
+
ans.push(cur);
|
|
285
|
+
if (onlyOne) return ans;
|
|
286
|
+
}
|
|
287
|
+
// TODO potential bug
|
|
288
|
+
if (callback === this._defaultCallbackByKey) {
|
|
274
289
|
if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && queue.push(cur.left);
|
|
275
290
|
if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && queue.push(cur.right);
|
|
276
291
|
} else {
|
|
@@ -281,140 +296,55 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|
|
281
296
|
}
|
|
282
297
|
}
|
|
283
298
|
|
|
284
|
-
return
|
|
299
|
+
return ans;
|
|
285
300
|
}
|
|
286
301
|
|
|
287
302
|
// --- start additional functions
|
|
288
|
-
/**
|
|
289
|
-
* The `lesserSum` function calculates the sum of property values in a binary tree for nodes that have a property value
|
|
290
|
-
* less than a given node.
|
|
291
|
-
* @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following:
|
|
292
|
-
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
|
|
293
|
-
* specifies the property name to use for calculating the sum. If not provided, it defaults to `'key'`.
|
|
294
|
-
* @returns The function `lesserSum` returns a number, which represents the sum of the values of the nodes in the
|
|
295
|
-
* binary tree that have a lesser value than the specified `beginNode` based on the `propertyName`.
|
|
296
|
-
*/
|
|
297
|
-
lesserSum(beginNode: N | BinaryTreeNodeKey | null, propertyName: BinaryTreeNodePropertyName = 'key'): number {
|
|
298
|
-
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key');
|
|
299
|
-
if (!beginNode) return 0;
|
|
300
|
-
if (!this.root) return 0;
|
|
301
|
-
const key = beginNode.key;
|
|
302
|
-
const getSumByPropertyName = (cur: N) => {
|
|
303
|
-
let needSum: number;
|
|
304
|
-
switch (propertyName) {
|
|
305
|
-
case 'key':
|
|
306
|
-
needSum = cur.key;
|
|
307
|
-
break;
|
|
308
|
-
default:
|
|
309
|
-
needSum = cur.key;
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
return needSum;
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
let sum = 0;
|
|
316
|
-
|
|
317
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
318
|
-
const _traverse = (cur: N): void => {
|
|
319
|
-
const compared = this._compare(cur.key, key);
|
|
320
|
-
if (compared === CP.eq) {
|
|
321
|
-
if (cur.right) sum += this.subTreeSum(cur.right, propertyName);
|
|
322
|
-
return;
|
|
323
|
-
} else if (compared === CP.lt) {
|
|
324
|
-
if (cur.left) sum += this.subTreeSum(cur.left, propertyName);
|
|
325
|
-
sum += getSumByPropertyName(cur);
|
|
326
|
-
if (cur.right) _traverse(cur.right);
|
|
327
|
-
else return;
|
|
328
|
-
} else {
|
|
329
|
-
if (cur.left) _traverse(cur.left);
|
|
330
|
-
else return;
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
_traverse(this.root);
|
|
335
|
-
} else {
|
|
336
|
-
const queue: N[] = [this.root];
|
|
337
|
-
while (queue.length > 0) {
|
|
338
|
-
const cur = queue.shift();
|
|
339
|
-
if (cur) {
|
|
340
|
-
const compared = this._compare(cur.key, key);
|
|
341
|
-
if (compared === CP.eq) {
|
|
342
|
-
if (cur.right) sum += this.subTreeSum(cur.right, propertyName);
|
|
343
|
-
return sum;
|
|
344
|
-
} else if (compared === CP.lt) {
|
|
345
|
-
// todo maybe a bug
|
|
346
|
-
if (cur.left) sum += this.subTreeSum(cur.left, propertyName);
|
|
347
|
-
sum += getSumByPropertyName(cur);
|
|
348
|
-
if (cur.right) queue.push(cur.right);
|
|
349
|
-
else return sum;
|
|
350
|
-
} else {
|
|
351
|
-
if (cur.left) queue.push(cur.left);
|
|
352
|
-
else return sum;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return sum;
|
|
359
|
-
}
|
|
360
303
|
|
|
361
304
|
/**
|
|
362
|
-
* The `
|
|
305
|
+
* The `lesserOrGreaterTraverse` function adds a delta value to the specified property of all nodes in a binary tree that
|
|
363
306
|
* have a greater value than a given node.
|
|
364
|
-
* @param
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
|
|
369
|
-
* specifies the property name of the nodes in the binary tree that you want to update. If not provided, it defaults to
|
|
370
|
-
* 'key'.
|
|
371
|
-
* @returns a boolean value.
|
|
307
|
+
* @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
|
|
308
|
+
* @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type), `BinaryTreeNodeKey`, or `null`. It
|
|
309
|
+
* represents the node in the binary tree to which the delta value will be added.
|
|
310
|
+
* @param lesserOrGreater - The `lesserOrGreater` parameter is an optional parameter that specifies whether the delta
|
|
372
311
|
*/
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
):
|
|
378
|
-
if (typeof node === 'number') node = this.get(node
|
|
379
|
-
|
|
312
|
+
lesserOrGreaterTraverse(
|
|
313
|
+
callback: MapCallback<N> = this._defaultCallbackByKey,
|
|
314
|
+
lesserOrGreater: CP = CP.lt,
|
|
315
|
+
node: N | BinaryTreeNodeKey | null
|
|
316
|
+
): MapCallbackReturn<N> {
|
|
317
|
+
if (typeof node === 'number') node = this.get(node);
|
|
318
|
+
const ans: MapCallbackReturn<N>[] = [];
|
|
319
|
+
if (!node) return [];
|
|
380
320
|
const key = node.key;
|
|
381
321
|
if (!this.root) return false;
|
|
382
322
|
|
|
383
|
-
const _sumByPropertyName = (cur: N) => {
|
|
384
|
-
switch (propertyName) {
|
|
385
|
-
case 'key':
|
|
386
|
-
cur.key += delta;
|
|
387
|
-
break;
|
|
388
|
-
default:
|
|
389
|
-
cur.key += delta;
|
|
390
|
-
break;
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
323
|
if (this.loopType === LoopType.RECURSIVE) {
|
|
394
324
|
const _traverse = (cur: N) => {
|
|
395
325
|
const compared = this._compare(cur.key, key);
|
|
396
|
-
if (compared ===
|
|
326
|
+
if (compared === lesserOrGreater) ans.push(callback(cur));
|
|
397
327
|
|
|
398
328
|
if (!cur.left && !cur.right) return;
|
|
399
|
-
if (cur.left && this._compare(cur.left.key, key) ===
|
|
400
|
-
if (cur.right && this._compare(cur.right.key, key) ===
|
|
329
|
+
if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) _traverse(cur.left);
|
|
330
|
+
if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) _traverse(cur.right);
|
|
401
331
|
};
|
|
402
332
|
|
|
403
333
|
_traverse(this.root);
|
|
404
334
|
return true;
|
|
405
335
|
} else {
|
|
406
|
-
const queue
|
|
407
|
-
while (queue.
|
|
336
|
+
const queue = new Queue<N>([this.root]);
|
|
337
|
+
while (queue.size > 0) {
|
|
408
338
|
const cur = queue.shift();
|
|
409
339
|
if (cur) {
|
|
410
340
|
const compared = this._compare(cur.key, key);
|
|
411
|
-
if (compared ===
|
|
341
|
+
if (compared === lesserOrGreater) ans.push(callback(cur));
|
|
412
342
|
|
|
413
|
-
if (cur.left && this._compare(cur.left.key, key) ===
|
|
414
|
-
if (cur.right && this._compare(cur.right.key, key) ===
|
|
343
|
+
if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) queue.push(cur.left);
|
|
344
|
+
if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) queue.push(cur.right);
|
|
415
345
|
}
|
|
416
346
|
}
|
|
417
|
-
return
|
|
347
|
+
return ans;
|
|
418
348
|
}
|
|
419
349
|
}
|
|
420
350
|
|
|
@@ -434,7 +364,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|
|
434
364
|
* @returns The function `perfectlyBalance()` returns a boolean value.
|
|
435
365
|
*/
|
|
436
366
|
perfectlyBalance(): boolean {
|
|
437
|
-
const sorted = this.dfs(
|
|
367
|
+
const sorted = this.dfs(node => node, 'in'),
|
|
438
368
|
n = sorted.length;
|
|
439
369
|
this.clear();
|
|
440
370
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
8
|
import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types';
|
|
9
|
-
import {BinaryTreeDeletedResult, CP,
|
|
9
|
+
import {BinaryTreeDeletedResult, CP, FamilyPosition, LoopType} from '../../types';
|
|
10
10
|
import {IBinaryTree} from '../../interfaces';
|
|
11
11
|
import {AVLTree, AVLTreeNode} from './avl-tree';
|
|
12
12
|
|
|
@@ -247,7 +247,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|
|
247
247
|
* @returns The function `perfectlyBalance()` returns a boolean value.
|
|
248
248
|
*/
|
|
249
249
|
override perfectlyBalance(): boolean {
|
|
250
|
-
const sorted = this.dfs(
|
|
250
|
+
const sorted = this.dfs(node => node, 'in'),
|
|
251
251
|
n = sorted.length;
|
|
252
252
|
if (sorted.length < 1) return false;
|
|
253
253
|
|
|
@@ -349,316 +349,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|
|
349
349
|
return bstDeletedResult;
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
-
/**
|
|
353
|
-
* The function `getSubTreeCount` calculates the number of nodes and the sum of their counts in a subtree, using either
|
|
354
|
-
* recursive or iterative traversal.
|
|
355
|
-
* @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree in a
|
|
356
|
-
* binary tree.
|
|
357
|
-
* @returns The function `getSubTreeCount` returns an array `[number, number]`.
|
|
358
|
-
*/
|
|
359
|
-
getSubTreeCount(subTreeRoot: N | null | undefined) {
|
|
360
|
-
const res: [number, number] = [0, 0];
|
|
361
|
-
if (!subTreeRoot) return res;
|
|
362
|
-
|
|
363
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
364
|
-
const _traverse = (cur: N) => {
|
|
365
|
-
res[0]++;
|
|
366
|
-
res[1] += cur.count;
|
|
367
|
-
cur.left && _traverse(cur.left);
|
|
368
|
-
cur.right && _traverse(cur.right);
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
_traverse(subTreeRoot);
|
|
372
|
-
return res;
|
|
373
|
-
} else {
|
|
374
|
-
const stack: N[] = [subTreeRoot];
|
|
375
|
-
|
|
376
|
-
while (stack.length > 0) {
|
|
377
|
-
const cur = stack.pop()!;
|
|
378
|
-
res[0]++;
|
|
379
|
-
res[1] += cur.count;
|
|
380
|
-
cur.right && stack.push(cur.right);
|
|
381
|
-
cur.left && stack.push(cur.left);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
return res;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* The function `subTreeSumCount` calculates the sum of the `count` property of each node in a subtree, either
|
|
390
|
-
* recursively or iteratively.
|
|
391
|
-
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
|
392
|
-
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree) or
|
|
393
|
-
* `null` if the subtree is empty.
|
|
394
|
-
* @returns the sum of the count values of all nodes in the subtree rooted at `subTreeRoot`.
|
|
395
|
-
*/
|
|
396
|
-
subTreeSumCount(subTreeRoot: N | BinaryTreeNodeKey | null): number {
|
|
397
|
-
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
|
|
398
|
-
|
|
399
|
-
if (!subTreeRoot) return 0;
|
|
400
|
-
|
|
401
|
-
let sum = 0;
|
|
402
|
-
|
|
403
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
404
|
-
const _traverse = (cur: N): void => {
|
|
405
|
-
sum += cur.count;
|
|
406
|
-
cur.left && _traverse(cur.left);
|
|
407
|
-
cur.right && _traverse(cur.right);
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
_traverse(subTreeRoot);
|
|
411
|
-
} else {
|
|
412
|
-
const stack: N[] = [subTreeRoot];
|
|
413
|
-
|
|
414
|
-
while (stack.length > 0) {
|
|
415
|
-
const cur = stack.pop()!;
|
|
416
|
-
sum += cur.count;
|
|
417
|
-
cur.right && stack.push(cur.right);
|
|
418
|
-
cur.left && stack.push(cur.left);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return sum;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* The function `subTreeAddCount` recursively or iteratively traverses a binary tree and adds a given delta value to
|
|
427
|
-
* the `count` property of each node.
|
|
428
|
-
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
|
429
|
-
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree), a
|
|
430
|
-
* `BinaryTreeNode` object, or `null` if the subtree is empty.
|
|
431
|
-
* @param {number} delta - The delta parameter is a number that represents the amount by which the count of each node
|
|
432
|
-
* in the subtree should be increased or decreased.
|
|
433
|
-
* @returns a boolean value.
|
|
434
|
-
*/
|
|
435
|
-
subTreeAddCount(subTreeRoot: N | BinaryTreeNodeKey | null, delta: number): boolean {
|
|
436
|
-
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
|
|
437
|
-
|
|
438
|
-
if (!subTreeRoot) return false;
|
|
439
|
-
|
|
440
|
-
const _addByProperty = (cur: N) => {
|
|
441
|
-
cur.count += delta;
|
|
442
|
-
this._setCount(this.count + delta);
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
446
|
-
const _traverse = (cur: N) => {
|
|
447
|
-
_addByProperty(cur);
|
|
448
|
-
cur.left && _traverse(cur.left);
|
|
449
|
-
cur.right && _traverse(cur.right);
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
_traverse(subTreeRoot);
|
|
453
|
-
} else {
|
|
454
|
-
const stack: N[] = [subTreeRoot];
|
|
455
|
-
|
|
456
|
-
while (stack.length > 0) {
|
|
457
|
-
const cur = stack.pop()!;
|
|
458
|
-
|
|
459
|
-
_addByProperty(cur);
|
|
460
|
-
cur.right && stack.push(cur.right);
|
|
461
|
-
cur.left && stack.push(cur.left);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return true;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* The function `getNodesByCount` returns an array of nodes that have a specific count property, either recursively or
|
|
469
|
-
* using a queue.
|
|
470
|
-
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
|
|
471
|
-
* `N`. It represents the property of the nodes that you want to search for.
|
|
472
|
-
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
|
|
473
|
-
* return only one node that matches the `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne` is set
|
|
474
|
-
* to `true`, the function will return only one node. If `onlyOne`
|
|
475
|
-
* @returns an array of nodes that match the given nodeProperty.
|
|
476
|
-
*/
|
|
477
|
-
getNodesByCount(nodeProperty: BinaryTreeNodeKey | N, onlyOne = false): N[] {
|
|
478
|
-
if (!this.root) return [];
|
|
479
|
-
const result: N[] = [];
|
|
480
|
-
|
|
481
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
482
|
-
const _traverse = (cur: N) => {
|
|
483
|
-
if (cur.count === nodeProperty) {
|
|
484
|
-
result.push(cur);
|
|
485
|
-
if (onlyOne) return;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
if (!cur.left && !cur.right) return;
|
|
489
|
-
cur.left && _traverse(cur.left);
|
|
490
|
-
cur.right && _traverse(cur.right);
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
_traverse(this.root);
|
|
494
|
-
} else {
|
|
495
|
-
const queue: N[] = [this.root];
|
|
496
|
-
while (queue.length > 0) {
|
|
497
|
-
const cur = queue.shift();
|
|
498
|
-
if (cur) {
|
|
499
|
-
if (cur.count === nodeProperty) {
|
|
500
|
-
result.push(cur);
|
|
501
|
-
if (onlyOne) return result;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
cur.left && queue.push(cur.left);
|
|
505
|
-
cur.right && queue.push(cur.right);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
return result;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* The BFSCount function returns an array of counts from a breadth-first search of nodes.
|
|
515
|
-
* @returns The BFSCount() function returns an array of numbers, specifically the count property of each node in the
|
|
516
|
-
* bfs traversal.
|
|
517
|
-
*/
|
|
518
|
-
bfsCount(): number[] {
|
|
519
|
-
const nodes = super.bfs('node');
|
|
520
|
-
return nodes.map(node => node.count);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* The function "listLevelsCount" takes a node and returns an array of arrays, where each inner array contains the
|
|
525
|
-
* count property of each node at that level.
|
|
526
|
-
* @param {N | null} node - The parameter `node` is of type `N | null`. This means that it can either be an instance of
|
|
527
|
-
* the class `N` or `null`.
|
|
528
|
-
* @returns a 2D array of numbers. Each inner array represents a level in the binary tree, and each number in the inner
|
|
529
|
-
* array represents the count property of a node in that level.
|
|
530
|
-
*/
|
|
531
|
-
listLevelsCount(node: N | null): number[][] {
|
|
532
|
-
const levels = super.listLevels(node, 'node');
|
|
533
|
-
return levels.map(level => level.map(node => node.count));
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
/**
|
|
537
|
-
* The `morrisCount` function returns an array of counts for each node in a binary tree, based on a specified traversal
|
|
538
|
-
* pattern.
|
|
539
|
-
* @param {'in' | 'pre' | 'post'} [pattern] - The `pattern` parameter is an optional parameter that specifies the
|
|
540
|
-
* traversal pattern for the Morris traversal algorithm. It can have one of three values: 'in', 'pre', or 'post'.
|
|
541
|
-
* @returns The function `morrisCount` returns an array of numbers.
|
|
542
|
-
*/
|
|
543
|
-
morrisCount(pattern: DFSOrderPattern = 'in'): number[] {
|
|
544
|
-
const nodes = super.morris(pattern, 'node');
|
|
545
|
-
return nodes.map(node => node.count);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
/**
|
|
549
|
-
* The function dfsCountIterative performs an iterative depth-first search and returns an array of node counts based on
|
|
550
|
-
* the specified traversal pattern.
|
|
551
|
-
* @param {'in' | 'pre' | 'post'} [pattern] - The pattern parameter is a string that specifies the traversal order for
|
|
552
|
-
* the Depth-First Search (dfs) algorithm. It can have three possible values: 'in', 'pre', or 'post'.
|
|
553
|
-
* @param loopType - The loopType parameter is a string that specifies the type of loop to use when traversing the
|
|
554
|
-
* @returns The dfsCountIterative function returns an array of numbers, which represents the count property of each node
|
|
555
|
-
* in the dfs traversal.
|
|
556
|
-
*/
|
|
557
|
-
dfsCount(pattern: DFSOrderPattern = 'in', loopType: LoopType = LoopType.ITERATIVE): number[] {
|
|
558
|
-
const nodes = super.dfs(pattern, 'node', loopType);
|
|
559
|
-
return nodes.map(node => node.count);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* The `lesserSumCount` function calculates the sum of the counts of all nodes in a binary tree that have a lesser
|
|
564
|
-
* value than a given node.
|
|
565
|
-
* @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following:
|
|
566
|
-
* @returns the sum of the counts of nodes in the binary tree that have a lesser value than the given beginNode.
|
|
567
|
-
*/
|
|
568
|
-
lesserSumCount(beginNode: N | BinaryTreeNodeKey | null): number {
|
|
569
|
-
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key');
|
|
570
|
-
if (!beginNode) return 0;
|
|
571
|
-
if (!this.root) return 0;
|
|
572
|
-
const key = beginNode.key;
|
|
573
|
-
|
|
574
|
-
let sum = 0;
|
|
575
|
-
|
|
576
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
577
|
-
const _traverse = (cur: N): void => {
|
|
578
|
-
const compared = this._compare(cur.key, key);
|
|
579
|
-
if (compared === CP.eq) {
|
|
580
|
-
if (cur.right) sum += this.subTreeSumCount(cur.right);
|
|
581
|
-
return;
|
|
582
|
-
} else if (compared === CP.lt) {
|
|
583
|
-
if (cur.left) sum += this.subTreeSumCount(cur.left);
|
|
584
|
-
sum += cur.count;
|
|
585
|
-
if (cur.right) _traverse(cur.right);
|
|
586
|
-
else return;
|
|
587
|
-
} else {
|
|
588
|
-
if (cur.left) _traverse(cur.left);
|
|
589
|
-
else return;
|
|
590
|
-
}
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
_traverse(this.root);
|
|
594
|
-
} else {
|
|
595
|
-
const queue: N[] = [this.root];
|
|
596
|
-
while (queue.length > 0) {
|
|
597
|
-
const cur = queue.shift();
|
|
598
|
-
if (cur) {
|
|
599
|
-
const compared = this._compare(cur.key, key);
|
|
600
|
-
if (compared === CP.eq) {
|
|
601
|
-
if (cur.right) sum += this.subTreeSumCount(cur.right);
|
|
602
|
-
return sum;
|
|
603
|
-
} else if (compared === CP.lt) {
|
|
604
|
-
// todo maybe a bug
|
|
605
|
-
if (cur.left) sum += this.subTreeSumCount(cur.left);
|
|
606
|
-
sum += cur.count;
|
|
607
|
-
if (cur.right) queue.push(cur.right);
|
|
608
|
-
else return sum;
|
|
609
|
-
} else {
|
|
610
|
-
if (cur.left) queue.push(cur.left);
|
|
611
|
-
else return sum;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
return sum;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
* The function `allGreaterNodesAddCount` updates the count property of all nodes in a binary tree that have an ID
|
|
622
|
-
* greater than a given ID by a specified delta value.
|
|
623
|
-
* @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be one of the following:
|
|
624
|
-
* @param {number} delta - The `delta` parameter is a number that represents the amount by which the `count` property
|
|
625
|
-
* of each node should be increased.
|
|
626
|
-
* @returns a boolean value.
|
|
627
|
-
*/
|
|
628
|
-
allGreaterNodesAddCount(node: N | BinaryTreeNodeKey | null, delta: number): boolean {
|
|
629
|
-
if (typeof node === 'number') node = this.get(node, 'key');
|
|
630
|
-
if (!node) return false;
|
|
631
|
-
const key = node.key;
|
|
632
|
-
if (!this.root) return false;
|
|
633
|
-
|
|
634
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
635
|
-
const _traverse = (cur: N) => {
|
|
636
|
-
const compared = this._compare(cur.key, key);
|
|
637
|
-
if (compared === CP.gt) cur.count += delta;
|
|
638
|
-
|
|
639
|
-
if (!cur.left && !cur.right) return;
|
|
640
|
-
if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left);
|
|
641
|
-
if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right);
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
_traverse(this.root);
|
|
645
|
-
return true;
|
|
646
|
-
} else {
|
|
647
|
-
const queue: N[] = [this.root];
|
|
648
|
-
while (queue.length > 0) {
|
|
649
|
-
const cur = queue.shift();
|
|
650
|
-
if (cur) {
|
|
651
|
-
const compared = this._compare(cur.key, key);
|
|
652
|
-
if (compared === CP.gt) cur.count += delta;
|
|
653
|
-
|
|
654
|
-
if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left);
|
|
655
|
-
if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
return true;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
352
|
/**
|
|
663
353
|
* The clear() function clears the data and sets the count to 0.
|
|
664
354
|
*/
|
|
@@ -9,6 +9,7 @@ import {arrayRemove, uuidV4} from '../../utils';
|
|
|
9
9
|
import {PriorityQueue} from '../priority-queue';
|
|
10
10
|
import type {DijkstraResult, VertexKey} from '../../types';
|
|
11
11
|
import {IGraph} from '../../interfaces';
|
|
12
|
+
import {Queue} from '../queue';
|
|
12
13
|
|
|
13
14
|
export abstract class AbstractVertex<V = any> {
|
|
14
15
|
/**
|
|
@@ -342,11 +343,11 @@ export abstract class AbstractGraph<
|
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
const visited: Map<V, boolean> = new Map();
|
|
345
|
-
const queue
|
|
346
|
+
const queue = new Queue<V>([vertex1]);
|
|
346
347
|
visited.set(vertex1, true);
|
|
347
348
|
let cost = 0;
|
|
348
|
-
while (queue.
|
|
349
|
-
for (let i = 0; i < queue.
|
|
349
|
+
while (queue.size > 0) {
|
|
350
|
+
for (let i = 0; i < queue.size; i++) {
|
|
350
351
|
const cur = queue.shift();
|
|
351
352
|
if (cur === vertex2) {
|
|
352
353
|
return cost;
|
|
@@ -172,7 +172,7 @@ export class Heap<E> {
|
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
174
|
* Depth-first search (DFS) method, different traversal orders can be selected。
|
|
175
|
-
* @param order -
|
|
175
|
+
* @param order - Traverse order parameter: 'in' (in-order), 'pre' (pre-order) or 'post' (post-order).
|
|
176
176
|
* @returns An array containing elements traversed in the specified order.
|
|
177
177
|
*/
|
|
178
178
|
dfs(order: DFSOrderPattern): E[] {
|
|
@@ -28,6 +28,10 @@ export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName;
|
|
|
28
28
|
|
|
29
29
|
export type BinaryTreeNodeKey = number;
|
|
30
30
|
|
|
31
|
+
export type BFSCallback<N> = (node: N, level?: number) => any;
|
|
32
|
+
|
|
33
|
+
export type BFSCallbackReturn<N> = ReturnType<BFSCallback<N>>;
|
|
34
|
+
|
|
31
35
|
export type BinaryTreeNodeProperty<N extends BinaryTreeNode<N['val'], N>> =
|
|
32
36
|
| N['val']
|
|
33
37
|
| N
|