data-structure-typed 2.6.0 → 2.6.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/.github/workflows/ci.yml +7 -2
- package/.github/workflows/release-package.yml +9 -2
- package/docs-site-docusaurus/docs/api/classes/AVLTree.md +108 -108
- package/docs-site-docusaurus/docs/api/classes/BST.md +101 -101
- package/docs-site-docusaurus/docs/api/classes/BinaryIndexedTree.md +13 -13
- package/docs-site-docusaurus/docs/api/classes/BinaryTree.md +66 -66
- package/docs-site-docusaurus/docs/api/classes/Deque.md +235 -51
- package/docs-site-docusaurus/docs/api/classes/DirectedGraph.md +21 -21
- package/docs-site-docusaurus/docs/api/classes/DoublyLinkedList.md +231 -67
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeap.md +9 -9
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeapNode.md +1 -1
- package/docs-site-docusaurus/docs/api/classes/HashMap.md +14 -14
- package/docs-site-docusaurus/docs/api/classes/Heap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/IterableElementBase.md +83 -13
- package/docs-site-docusaurus/docs/api/classes/LinearBase.md +124 -20
- package/docs-site-docusaurus/docs/api/classes/LinearLinkedBase.md +140 -32
- package/docs-site-docusaurus/docs/api/classes/LinkedHashMap.md +23 -23
- package/docs-site-docusaurus/docs/api/classes/LinkedListQueue.md +159 -51
- package/docs-site-docusaurus/docs/api/classes/MapGraph.md +20 -20
- package/docs-site-docusaurus/docs/api/classes/Matrix.md +23 -23
- package/docs-site-docusaurus/docs/api/classes/MaxHeap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MaxPriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MinHeap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MinPriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/PriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/Queue.md +142 -34
- package/docs-site-docusaurus/docs/api/classes/RedBlackTree.md +117 -117
- package/docs-site-docusaurus/docs/api/classes/SegmentTree.md +8 -8
- package/docs-site-docusaurus/docs/api/classes/SinglyLinkedList.md +158 -50
- package/docs-site-docusaurus/docs/api/classes/SkipList.md +21 -21
- package/docs-site-docusaurus/docs/api/classes/Stack.md +108 -26
- package/docs-site-docusaurus/docs/api/classes/TreeMap.md +33 -33
- package/docs-site-docusaurus/docs/api/classes/TreeMultiMap.md +75 -39
- package/docs-site-docusaurus/docs/api/classes/TreeSet.md +301 -39
- package/docs-site-docusaurus/docs/api/classes/Trie.md +110 -28
- package/docs-site-docusaurus/docs/api/classes/UndirectedGraph.md +20 -20
- package/package.json +45 -46
- package/src/common/error.ts +15 -32
- package/src/common/index.ts +0 -3
- package/src/data-structures/base/iterable-element-base.ts +0 -3
- package/src/data-structures/base/linear-base.ts +2 -36
- package/src/data-structures/binary-tree/avl-tree.ts +31 -529
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +47 -572
- package/src/data-structures/binary-tree/binary-tree.ts +326 -1311
- package/src/data-structures/binary-tree/bst.ts +158 -1082
- package/src/data-structures/binary-tree/red-black-tree.ts +451 -1290
- package/src/data-structures/binary-tree/segment-tree.ts +73 -351
- package/src/data-structures/binary-tree/tree-map.ts +462 -5124
- package/src/data-structures/binary-tree/tree-multi-map.ts +302 -4914
- package/src/data-structures/binary-tree/tree-multi-set.ts +284 -3972
- package/src/data-structures/binary-tree/tree-set.ts +338 -4836
- package/src/data-structures/graph/abstract-graph.ts +98 -167
- package/src/data-structures/graph/directed-graph.ts +137 -562
- package/src/data-structures/graph/map-graph.ts +0 -3
- package/src/data-structures/graph/undirected-graph.ts +132 -511
- package/src/data-structures/hash/hash-map.ts +154 -582
- package/src/data-structures/heap/heap.ts +200 -795
- package/src/data-structures/linked-list/doubly-linked-list.ts +121 -865
- package/src/data-structures/linked-list/singly-linked-list.ts +122 -794
- package/src/data-structures/linked-list/skip-linked-list.ts +211 -918
- package/src/data-structures/matrix/matrix.ts +179 -518
- package/src/data-structures/matrix/navigator.ts +0 -1
- package/src/data-structures/priority-queue/max-priority-queue.ts +1 -6
- package/src/data-structures/priority-queue/min-priority-queue.ts +6 -11
- package/src/data-structures/priority-queue/priority-queue.ts +1 -2
- package/src/data-structures/queue/deque.ts +214 -882
- package/src/data-structures/queue/queue.ts +102 -625
- package/src/data-structures/stack/stack.ts +76 -505
- package/src/data-structures/trie/trie.ts +98 -628
- package/src/types/common.ts +0 -10
- package/src/types/data-structures/binary-tree/bst.ts +0 -7
- package/src/types/data-structures/binary-tree/red-black-tree.ts +0 -1
- package/src/types/data-structures/graph/abstract-graph.ts +0 -2
- package/src/types/data-structures/hash/hash-map.ts +0 -3
- package/src/types/data-structures/hash/index.ts +0 -1
- package/src/types/data-structures/matrix/navigator.ts +0 -2
- package/src/types/utils/utils.ts +0 -7
- package/src/types/utils/validate-type.ts +0 -7
- package/src/utils/number.ts +0 -2
- package/src/utils/utils.ts +0 -5
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
8
|
import type { GraphOptions, TopologicalStatus, VertexKey } from '../../types';
|
|
10
9
|
import { AbstractEdge, AbstractGraph, AbstractVertex } from './abstract-graph';
|
|
11
10
|
import { IGraph } from '../../interfaces';
|
|
@@ -133,10 +132,6 @@ export class DirectedGraph<
|
|
|
133
132
|
super(options);
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
protected override get _edgeConnector(): string {
|
|
137
|
-
return '->';
|
|
138
|
-
}
|
|
139
|
-
|
|
140
135
|
protected _outEdgeMap: Map<VO, EO[]> = new Map<VO, EO[]>();
|
|
141
136
|
|
|
142
137
|
get outEdgeMap(): Map<VO, EO[]> {
|
|
@@ -157,6 +152,10 @@ export class DirectedGraph<
|
|
|
157
152
|
this._inEdgeMap = v;
|
|
158
153
|
}
|
|
159
154
|
|
|
155
|
+
protected override get _edgeConnector(): string {
|
|
156
|
+
return '->';
|
|
157
|
+
}
|
|
158
|
+
|
|
160
159
|
/**
|
|
161
160
|
* Construct a directed graph from keys with value initializer `v => v`.
|
|
162
161
|
* @template K - Vertex key type.
|
|
@@ -164,7 +163,9 @@ export class DirectedGraph<
|
|
|
164
163
|
* @returns DirectedGraph with all keys added.
|
|
165
164
|
* @remarks Time O(V), Space O(V)
|
|
166
165
|
*/
|
|
167
|
-
static fromKeys<K extends VertexKey>(
|
|
166
|
+
static fromKeys<K extends VertexKey>(
|
|
167
|
+
keys: Iterable<K>
|
|
168
|
+
): DirectedGraph<K, undefined, DirectedVertex<K>, DirectedEdge<undefined>> {
|
|
168
169
|
const g: DirectedGraph<K, undefined, DirectedVertex<K>, DirectedEdge<undefined>> = new DirectedGraph<K, undefined>({
|
|
169
170
|
vertexValueInitializer: (k: VertexKey) => k as K
|
|
170
171
|
});
|
|
@@ -182,7 +183,10 @@ export class DirectedGraph<
|
|
|
182
183
|
static fromEntries<V>(
|
|
183
184
|
entries: Iterable<[VertexKey, V]>
|
|
184
185
|
): DirectedGraph<V, undefined, DirectedVertex<V>, DirectedEdge<undefined>> {
|
|
185
|
-
const g: DirectedGraph<V, undefined, DirectedVertex<V>, DirectedEdge<undefined>> = new DirectedGraph<
|
|
186
|
+
const g: DirectedGraph<V, undefined, DirectedVertex<V>, DirectedEdge<undefined>> = new DirectedGraph<
|
|
187
|
+
V,
|
|
188
|
+
undefined
|
|
189
|
+
>();
|
|
186
190
|
for (const [k, v] of entries) g.addVertex(k, v);
|
|
187
191
|
return g;
|
|
188
192
|
}
|
|
@@ -217,61 +221,20 @@ export class DirectedGraph<
|
|
|
217
221
|
* @param destOrKey - Destination vertex or key.
|
|
218
222
|
* @returns Edge instance or `undefined`.
|
|
219
223
|
* @remarks Time O(1) avg, Space O(1)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
* @example
|
|
260
|
-
* // Get edge between vertices
|
|
261
|
-
* const g = new DirectedGraph();
|
|
262
|
-
* g.addVertex('A');
|
|
263
|
-
* g.addVertex('B');
|
|
264
|
-
* g.addEdge('A', 'B', 5);
|
|
265
|
-
* const edge = g.getEdge('A', 'B');
|
|
266
|
-
* console.log(edge?.weight); // 5;
|
|
224
|
+
* @example
|
|
225
|
+
* // Get edge between vertices
|
|
226
|
+
* const g = new DirectedGraph();
|
|
227
|
+
* g.addVertex('A');
|
|
228
|
+
* g.addVertex('B');
|
|
229
|
+
* g.addEdge('A', 'B', 5);
|
|
230
|
+
* const edge = g.getEdge('A', 'B');
|
|
231
|
+
* console.log(edge?.weight); // 5;
|
|
267
232
|
*/
|
|
268
233
|
getEdge(srcOrKey: VO | VertexKey | undefined, destOrKey: VO | VertexKey | undefined): EO | undefined {
|
|
269
234
|
let edgeMap: EO[] = [];
|
|
270
|
-
|
|
271
235
|
if (srcOrKey !== undefined && destOrKey !== undefined) {
|
|
272
236
|
const src: VO | undefined = this._getVertex(srcOrKey);
|
|
273
237
|
const dest: VO | undefined = this._getVertex(destOrKey);
|
|
274
|
-
|
|
275
238
|
if (src && dest) {
|
|
276
239
|
const srcOutEdges = this._outEdgeMap.get(src);
|
|
277
240
|
if (srcOutEdges) {
|
|
@@ -279,7 +242,6 @@ export class DirectedGraph<
|
|
|
279
242
|
}
|
|
280
243
|
}
|
|
281
244
|
}
|
|
282
|
-
|
|
283
245
|
return edgeMap[0] || undefined;
|
|
284
246
|
}
|
|
285
247
|
|
|
@@ -297,12 +259,10 @@ export class DirectedGraph<
|
|
|
297
259
|
if (!src || !dest) {
|
|
298
260
|
return undefined;
|
|
299
261
|
}
|
|
300
|
-
|
|
301
262
|
const srcOutEdges = this._outEdgeMap.get(src);
|
|
302
263
|
if (srcOutEdges) {
|
|
303
264
|
arrayRemove<EO>(srcOutEdges, (edge: EO) => edge.dest === dest.key);
|
|
304
265
|
}
|
|
305
|
-
|
|
306
266
|
const destInEdges = this._inEdgeMap.get(dest);
|
|
307
267
|
if (destInEdges) {
|
|
308
268
|
removed = arrayRemove<EO>(destInEdges, (edge: EO) => edge.src === src.key)[0] || undefined;
|
|
@@ -316,73 +276,31 @@ export class DirectedGraph<
|
|
|
316
276
|
* @param destVertexKey - Optional destination vertex/key when deleting by pair.
|
|
317
277
|
* @returns Removed edge or `undefined`.
|
|
318
278
|
* @remarks Time O(1) avg, Space O(1)
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
* @example
|
|
362
|
-
* // DirectedGraph deleteEdge and vertex operations
|
|
363
|
-
* const graph = new DirectedGraph<string>();
|
|
364
|
-
*
|
|
365
|
-
* // Build a small graph
|
|
366
|
-
* graph.addVertex('X');
|
|
367
|
-
* graph.addVertex('Y');
|
|
368
|
-
* graph.addVertex('Z');
|
|
369
|
-
* graph.addEdge('X', 'Y', 1);
|
|
370
|
-
* graph.addEdge('Y', 'Z', 2);
|
|
371
|
-
*
|
|
372
|
-
* // Delete an edge
|
|
373
|
-
* graph.deleteEdgeSrcToDest('X', 'Y');
|
|
374
|
-
* console.log(graph.hasEdge('X', 'Y')); // false;
|
|
375
|
-
*
|
|
376
|
-
* // Edge in other direction should not exist
|
|
377
|
-
* console.log(graph.hasEdge('Y', 'X')); // false;
|
|
378
|
-
*
|
|
379
|
-
* // Other edges should remain
|
|
380
|
-
* console.log(graph.hasEdge('Y', 'Z')); // true;
|
|
381
|
-
*
|
|
382
|
-
* // Delete a vertex
|
|
383
|
-
* graph.deleteVertex('Y');
|
|
384
|
-
* console.log(graph.hasVertex('Y')); // false;
|
|
385
|
-
* console.log(graph.size); // 2;
|
|
279
|
+
* @example
|
|
280
|
+
* // DirectedGraph deleteEdge and vertex operations
|
|
281
|
+
* const graph = new DirectedGraph<string>();
|
|
282
|
+
*
|
|
283
|
+
* // Build a small graph
|
|
284
|
+
* graph.addVertex('X');
|
|
285
|
+
* graph.addVertex('Y');
|
|
286
|
+
* graph.addVertex('Z');
|
|
287
|
+
* graph.addEdge('X', 'Y', 1);
|
|
288
|
+
* graph.addEdge('Y', 'Z', 2);
|
|
289
|
+
*
|
|
290
|
+
* // Delete an edge
|
|
291
|
+
* graph.deleteEdgeSrcToDest('X', 'Y');
|
|
292
|
+
* console.log(graph.hasEdge('X', 'Y')); // false;
|
|
293
|
+
*
|
|
294
|
+
* // Edge in other direction should not exist
|
|
295
|
+
* console.log(graph.hasEdge('Y', 'X')); // false;
|
|
296
|
+
*
|
|
297
|
+
* // Other edges should remain
|
|
298
|
+
* console.log(graph.hasEdge('Y', 'Z')); // true;
|
|
299
|
+
*
|
|
300
|
+
* // Delete a vertex
|
|
301
|
+
* graph.deleteVertex('Y');
|
|
302
|
+
* console.log(graph.hasVertex('Y')); // false;
|
|
303
|
+
* console.log(graph.size); // 2;
|
|
386
304
|
*/
|
|
387
305
|
deleteEdge(edgeOrSrcVertexKey: EO | VertexKey, destVertexKey?: VertexKey): EO | undefined {
|
|
388
306
|
let removed: EO | undefined = undefined;
|
|
@@ -398,72 +316,30 @@ export class DirectedGraph<
|
|
|
398
316
|
src = this._getVertex(edgeOrSrcVertexKey.src);
|
|
399
317
|
dest = this._getVertex(edgeOrSrcVertexKey.dest);
|
|
400
318
|
}
|
|
401
|
-
|
|
402
319
|
if (src && dest) {
|
|
403
320
|
const srcOutEdges = this._outEdgeMap.get(src);
|
|
404
321
|
if (srcOutEdges && srcOutEdges.length > 0) {
|
|
405
322
|
arrayRemove(srcOutEdges, (edge: EO) => edge.src === src!.key && edge.dest === dest?.key);
|
|
406
323
|
}
|
|
407
|
-
|
|
408
324
|
const destInEdges = this._inEdgeMap.get(dest);
|
|
409
325
|
if (destInEdges && destInEdges.length > 0) {
|
|
410
326
|
removed = arrayRemove(destInEdges, (edge: EO) => edge.src === src!.key && edge.dest === dest!.key)[0];
|
|
411
327
|
}
|
|
412
328
|
}
|
|
413
|
-
|
|
414
329
|
return removed;
|
|
415
330
|
}
|
|
416
331
|
|
|
417
|
-
|
|
332
|
+
/**
|
|
418
333
|
* Remove a vertex
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
* @example
|
|
459
|
-
* // Remove a vertex
|
|
460
|
-
* const g = new DirectedGraph();
|
|
461
|
-
* g.addVertex('A');
|
|
462
|
-
* g.addVertex('B');
|
|
463
|
-
* g.addEdge('A', 'B');
|
|
464
|
-
* g.deleteVertex('A');
|
|
465
|
-
* console.log(g.hasVertex('A')); // false;
|
|
466
|
-
* console.log(g.hasEdge('A', 'B')); // false;
|
|
334
|
+
* @example
|
|
335
|
+
* // Remove a vertex
|
|
336
|
+
* const g = new DirectedGraph();
|
|
337
|
+
* g.addVertex('A');
|
|
338
|
+
* g.addVertex('B');
|
|
339
|
+
* g.addEdge('A', 'B');
|
|
340
|
+
* g.deleteVertex('A');
|
|
341
|
+
* console.log(g.hasVertex('A')); // false;
|
|
342
|
+
* console.log(g.hasEdge('A', 'B')); // false;
|
|
467
343
|
*/
|
|
468
344
|
deleteVertex(vertexOrKey: VO | VertexKey): boolean {
|
|
469
345
|
let vertexKey: VertexKey;
|
|
@@ -475,7 +351,6 @@ export class DirectedGraph<
|
|
|
475
351
|
vertex = vertexOrKey;
|
|
476
352
|
vertexKey = this._getVertexKey(vertexOrKey);
|
|
477
353
|
}
|
|
478
|
-
|
|
479
354
|
if (vertex) {
|
|
480
355
|
/**
|
|
481
356
|
* One-step neighbors following outgoing edges.
|
|
@@ -490,21 +365,17 @@ export class DirectedGraph<
|
|
|
490
365
|
this._outEdgeMap.delete(vertex);
|
|
491
366
|
this._inEdgeMap.delete(vertex);
|
|
492
367
|
}
|
|
493
|
-
|
|
494
368
|
return this._vertexMap.delete(vertexKey);
|
|
495
369
|
}
|
|
496
370
|
|
|
497
371
|
deleteEdgesBetween(v1: VertexKey | VO, v2: VertexKey | VO): EO[] {
|
|
498
372
|
const removed: EO[] = [];
|
|
499
|
-
|
|
500
373
|
if (v1 && v2) {
|
|
501
374
|
const v1ToV2 = this.deleteEdgeSrcToDest(v1, v2);
|
|
502
375
|
const v2ToV1 = this.deleteEdgeSrcToDest(v2, v1);
|
|
503
|
-
|
|
504
376
|
if (v1ToV2) removed.push(v1ToV2);
|
|
505
377
|
if (v2ToV1) removed.push(v2ToV1);
|
|
506
378
|
}
|
|
507
|
-
|
|
508
379
|
return removed;
|
|
509
380
|
}
|
|
510
381
|
|
|
@@ -513,54 +384,15 @@ export class DirectedGraph<
|
|
|
513
384
|
* @param vertexOrKey - Vertex or key.
|
|
514
385
|
* @returns Array of incoming edges.
|
|
515
386
|
* @remarks Time O(deg_in), Space O(deg_in)
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
* @example
|
|
556
|
-
* // Get incoming edges
|
|
557
|
-
* const g = new DirectedGraph();
|
|
558
|
-
* g.addVertex('A');
|
|
559
|
-
* g.addVertex('B');
|
|
560
|
-
* g.addVertex('C');
|
|
561
|
-
* g.addEdge('A', 'C');
|
|
562
|
-
* g.addEdge('B', 'C');
|
|
563
|
-
* console.log(g.incomingEdgesOf('C').length); // 2;
|
|
387
|
+
* @example
|
|
388
|
+
* // Get incoming edges
|
|
389
|
+
* const g = new DirectedGraph();
|
|
390
|
+
* g.addVertex('A');
|
|
391
|
+
* g.addVertex('B');
|
|
392
|
+
* g.addVertex('C');
|
|
393
|
+
* g.addEdge('A', 'C');
|
|
394
|
+
* g.addEdge('B', 'C');
|
|
395
|
+
* console.log(g.incomingEdgesOf('C').length); // 2;
|
|
564
396
|
*/
|
|
565
397
|
incomingEdgesOf(vertexOrKey: VO | VertexKey): EO[] {
|
|
566
398
|
const target = this._getVertex(vertexOrKey);
|
|
@@ -575,54 +407,15 @@ export class DirectedGraph<
|
|
|
575
407
|
* @param vertexOrKey - Vertex or key.
|
|
576
408
|
* @returns Array of outgoing edges.
|
|
577
409
|
* @remarks Time O(deg_out), Space O(deg_out)
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
* @example
|
|
618
|
-
* // Get outgoing edges
|
|
619
|
-
* const g = new DirectedGraph();
|
|
620
|
-
* g.addVertex('A');
|
|
621
|
-
* g.addVertex('B');
|
|
622
|
-
* g.addVertex('C');
|
|
623
|
-
* g.addEdge('A', 'B');
|
|
624
|
-
* g.addEdge('A', 'C');
|
|
625
|
-
* console.log(g.outgoingEdgesOf('A').length); // 2;
|
|
410
|
+
* @example
|
|
411
|
+
* // Get outgoing edges
|
|
412
|
+
* const g = new DirectedGraph();
|
|
413
|
+
* g.addVertex('A');
|
|
414
|
+
* g.addVertex('B');
|
|
415
|
+
* g.addVertex('C');
|
|
416
|
+
* g.addEdge('A', 'B');
|
|
417
|
+
* g.addEdge('A', 'C');
|
|
418
|
+
* console.log(g.outgoingEdgesOf('A').length); // 2;
|
|
626
419
|
*/
|
|
627
420
|
outgoingEdgesOf(vertexOrKey: VO | VertexKey): EO[] {
|
|
628
421
|
const target = this._getVertex(vertexOrKey);
|
|
@@ -706,79 +499,35 @@ export class DirectedGraph<
|
|
|
706
499
|
* @param propertyName - `'key'` to map to keys; `'vertex'` to keep instances.
|
|
707
500
|
* @returns Array of keys/vertices, or `undefined` when cycle is found.
|
|
708
501
|
* @remarks Time O(V + E), Space O(V)
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
* @example
|
|
752
|
-
* // DirectedGraph topologicalSort for task scheduling
|
|
753
|
-
* const graph = new DirectedGraph<string>();
|
|
754
|
-
*
|
|
755
|
-
* // Build a DAG (Directed Acyclic Graph) for task dependencies
|
|
756
|
-
* graph.addVertex('Design');
|
|
757
|
-
* graph.addVertex('Implement');
|
|
758
|
-
* graph.addVertex('Test');
|
|
759
|
-
* graph.addVertex('Deploy');
|
|
760
|
-
*
|
|
761
|
-
* // Add dependency edges
|
|
762
|
-
* graph.addEdge('Design', 'Implement', 1); // Design must come before Implement
|
|
763
|
-
* graph.addEdge('Implement', 'Test', 1); // Implement must come before Test
|
|
764
|
-
* graph.addEdge('Test', 'Deploy', 1); // Test must come before Deploy
|
|
765
|
-
*
|
|
766
|
-
* // Topological sort gives valid execution order
|
|
767
|
-
* const executionOrder = graph.topologicalSort();
|
|
768
|
-
* console.log(executionOrder); // defined;
|
|
769
|
-
* console.log(executionOrder); // ['Design', 'Implement', 'Test', 'Deploy'];
|
|
770
|
-
*
|
|
771
|
-
* // All vertices should be included
|
|
772
|
-
* console.log(executionOrder?.length); // 4;
|
|
502
|
+
* @example
|
|
503
|
+
* // DirectedGraph topologicalSort for task scheduling
|
|
504
|
+
* const graph = new DirectedGraph<string>();
|
|
505
|
+
*
|
|
506
|
+
* // Build a DAG (Directed Acyclic Graph) for task dependencies
|
|
507
|
+
* graph.addVertex('Design');
|
|
508
|
+
* graph.addVertex('Implement');
|
|
509
|
+
* graph.addVertex('Test');
|
|
510
|
+
* graph.addVertex('Deploy');
|
|
511
|
+
*
|
|
512
|
+
* // Add dependency edges
|
|
513
|
+
* graph.addEdge('Design', 'Implement', 1); // Design must come before Implement
|
|
514
|
+
* graph.addEdge('Implement', 'Test', 1); // Implement must come before Test
|
|
515
|
+
* graph.addEdge('Test', 'Deploy', 1); // Test must come before Deploy
|
|
516
|
+
*
|
|
517
|
+
* // Topological sort gives valid execution order
|
|
518
|
+
* const executionOrder = graph.topologicalSort();
|
|
519
|
+
* console.log(executionOrder); // defined;
|
|
520
|
+
* console.log(executionOrder); // ['Design', 'Implement', 'Test', 'Deploy'];
|
|
521
|
+
*
|
|
522
|
+
* // All vertices should be included
|
|
523
|
+
* console.log(executionOrder?.length); // 4;
|
|
773
524
|
*/
|
|
774
525
|
topologicalSort(propertyName?: 'vertex' | 'key'): Array<VO | VertexKey> | undefined {
|
|
775
526
|
propertyName = propertyName ?? 'key';
|
|
776
|
-
|
|
777
527
|
const statusMap: Map<VO | VertexKey, TopologicalStatus> = new Map<VO | VertexKey, TopologicalStatus>();
|
|
778
528
|
for (const entry of this.vertexMap) {
|
|
779
529
|
statusMap.set(entry[1], 0);
|
|
780
530
|
}
|
|
781
|
-
|
|
782
531
|
let sorted: (VO | VertexKey)[] = [];
|
|
783
532
|
let hasCycle = false;
|
|
784
533
|
const dfs = (cur: VO | VertexKey) => {
|
|
@@ -795,67 +544,25 @@ export class DirectedGraph<
|
|
|
795
544
|
statusMap.set(cur, 2);
|
|
796
545
|
sorted.push(cur);
|
|
797
546
|
};
|
|
798
|
-
|
|
799
547
|
for (const entry of this.vertexMap) {
|
|
800
548
|
if (statusMap.get(entry[1]) === 0) {
|
|
801
549
|
dfs(entry[1]);
|
|
802
550
|
}
|
|
803
551
|
}
|
|
804
|
-
|
|
805
552
|
if (hasCycle) return undefined;
|
|
806
|
-
|
|
807
553
|
if (propertyName === 'key') sorted = sorted.map(vertex => (vertex instanceof DirectedVertex ? vertex.key : vertex));
|
|
808
554
|
return sorted.reverse();
|
|
809
555
|
}
|
|
810
556
|
|
|
811
|
-
|
|
557
|
+
/**
|
|
812
558
|
* Get all edges
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
* @example
|
|
853
|
-
* // Get all edges
|
|
854
|
-
* const g = new DirectedGraph();
|
|
855
|
-
* g.addVertex('A');
|
|
856
|
-
* g.addVertex('B');
|
|
857
|
-
* g.addEdge('A', 'B', 3);
|
|
858
|
-
* console.log(g.edgeSet().length); // 1;
|
|
559
|
+
* @example
|
|
560
|
+
* // Get all edges
|
|
561
|
+
* const g = new DirectedGraph();
|
|
562
|
+
* g.addVertex('A');
|
|
563
|
+
* g.addVertex('B');
|
|
564
|
+
* g.addEdge('A', 'B', 3);
|
|
565
|
+
* console.log(g.edgeSet().length); // 1;
|
|
859
566
|
*/
|
|
860
567
|
edgeSet(): EO[] {
|
|
861
568
|
let edgeMap: EO[] = [];
|
|
@@ -865,58 +572,18 @@ export class DirectedGraph<
|
|
|
865
572
|
return edgeMap;
|
|
866
573
|
}
|
|
867
574
|
|
|
868
|
-
|
|
575
|
+
/**
|
|
869
576
|
* Get outgoing neighbors
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
* @example
|
|
911
|
-
* // Get outgoing neighbors
|
|
912
|
-
* const g = new DirectedGraph();
|
|
913
|
-
* g.addVertex('A');
|
|
914
|
-
* g.addVertex('B');
|
|
915
|
-
* g.addVertex('C');
|
|
916
|
-
* g.addEdge('A', 'B');
|
|
917
|
-
* g.addEdge('A', 'C');
|
|
918
|
-
* const neighbors = g.getNeighbors('A');
|
|
919
|
-
* console.log(neighbors.map(v => v.key).sort()); // ['B', 'C'];
|
|
577
|
+
* @example
|
|
578
|
+
* // Get outgoing neighbors
|
|
579
|
+
* const g = new DirectedGraph();
|
|
580
|
+
* g.addVertex('A');
|
|
581
|
+
* g.addVertex('B');
|
|
582
|
+
* g.addVertex('C');
|
|
583
|
+
* g.addEdge('A', 'B');
|
|
584
|
+
* g.addEdge('A', 'C');
|
|
585
|
+
* const neighbors = g.getNeighbors('A');
|
|
586
|
+
* console.log(neighbors.map(v => v.key).sort()); // ['B', 'C'];
|
|
920
587
|
*/
|
|
921
588
|
getNeighbors(vertexOrKey: VO | VertexKey): VO[] {
|
|
922
589
|
const neighbors: VO[] = [];
|
|
@@ -925,7 +592,6 @@ export class DirectedGraph<
|
|
|
925
592
|
const outEdges = this.outgoingEdgesOf(vertex);
|
|
926
593
|
for (const outEdge of outEdges) {
|
|
927
594
|
const neighbor = this._getVertex(outEdge.dest);
|
|
928
|
-
|
|
929
595
|
if (neighbor) {
|
|
930
596
|
neighbors.push(neighbor);
|
|
931
597
|
}
|
|
@@ -984,77 +650,33 @@ export class DirectedGraph<
|
|
|
984
650
|
* Tarjan's algorithm for strongly connected components.
|
|
985
651
|
* @returns `{ dfnMap, lowMap, SCCs }`.
|
|
986
652
|
* @remarks Time O(V + E), Space O(V + E)
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
* @example
|
|
1027
|
-
* // Find strongly connected components
|
|
1028
|
-
* const g = new DirectedGraph();
|
|
1029
|
-
* g.addVertex('A');
|
|
1030
|
-
* g.addVertex('B');
|
|
1031
|
-
* g.addVertex('C');
|
|
1032
|
-
* g.addEdge('A', 'B');
|
|
1033
|
-
* g.addEdge('B', 'C');
|
|
1034
|
-
* g.addEdge('C', 'A');
|
|
1035
|
-
* const { SCCs } = g.tarjan();
|
|
1036
|
-
* // A→B→C→A forms one SCC with 3 members
|
|
1037
|
-
* const sccArrays = [...SCCs.values()];
|
|
1038
|
-
* console.log(sccArrays.some(scc => scc.length === 3)); // true;
|
|
653
|
+
* @example
|
|
654
|
+
* // Find strongly connected components
|
|
655
|
+
* const g = new DirectedGraph();
|
|
656
|
+
* g.addVertex('A');
|
|
657
|
+
* g.addVertex('B');
|
|
658
|
+
* g.addVertex('C');
|
|
659
|
+
* g.addEdge('A', 'B');
|
|
660
|
+
* g.addEdge('B', 'C');
|
|
661
|
+
* g.addEdge('C', 'A');
|
|
662
|
+
* const { SCCs } = g.tarjan();
|
|
663
|
+
* // A→B→C→A forms one SCC with 3 members
|
|
664
|
+
* const sccArrays = [...SCCs.values()];
|
|
665
|
+
* console.log(sccArrays.some(scc => scc.length === 3)); // true;
|
|
1039
666
|
*/
|
|
1040
667
|
tarjan(): { dfnMap: Map<VO, number>; lowMap: Map<VO, number>; SCCs: Map<number, VO[]> } {
|
|
1041
668
|
const dfnMap = new Map<VO, number>();
|
|
1042
669
|
const lowMap = new Map<VO, number>();
|
|
1043
670
|
const SCCs = new Map<number, VO[]>();
|
|
1044
|
-
|
|
1045
671
|
let time = 0;
|
|
1046
|
-
|
|
1047
672
|
const stack: VO[] = [];
|
|
1048
673
|
const inStack: Set<VO> = new Set();
|
|
1049
|
-
|
|
1050
674
|
const dfs = (vertex: VO) => {
|
|
1051
675
|
dfnMap.set(vertex, time);
|
|
1052
676
|
lowMap.set(vertex, time);
|
|
1053
677
|
time++;
|
|
1054
|
-
|
|
1055
678
|
stack.push(vertex);
|
|
1056
679
|
inStack.add(vertex);
|
|
1057
|
-
|
|
1058
680
|
const neighbors = this.getNeighbors(vertex);
|
|
1059
681
|
for (const neighbor of neighbors) {
|
|
1060
682
|
if (!dfnMap.has(neighbor)) {
|
|
@@ -1064,27 +686,22 @@ export class DirectedGraph<
|
|
|
1064
686
|
lowMap.set(vertex, Math.min(lowMap.get(vertex)!, dfnMap.get(neighbor)!));
|
|
1065
687
|
}
|
|
1066
688
|
}
|
|
1067
|
-
|
|
1068
689
|
if (dfnMap.get(vertex) === lowMap.get(vertex)) {
|
|
1069
690
|
const SCC: VO[] = [];
|
|
1070
691
|
let poppedVertex: VO | undefined;
|
|
1071
|
-
|
|
1072
692
|
do {
|
|
1073
693
|
poppedVertex = stack.pop();
|
|
1074
694
|
inStack.delete(poppedVertex!);
|
|
1075
695
|
SCC.push(poppedVertex!);
|
|
1076
696
|
} while (poppedVertex !== vertex);
|
|
1077
|
-
|
|
1078
697
|
SCCs.set(SCCs.size, SCC);
|
|
1079
698
|
}
|
|
1080
699
|
};
|
|
1081
|
-
|
|
1082
700
|
for (const vertex of this.vertexMap.values()) {
|
|
1083
701
|
if (!dfnMap.has(vertex)) {
|
|
1084
702
|
dfs(vertex);
|
|
1085
703
|
}
|
|
1086
704
|
}
|
|
1087
|
-
|
|
1088
705
|
return { dfnMap, lowMap, SCCs };
|
|
1089
706
|
}
|
|
1090
707
|
|
|
@@ -1110,56 +727,17 @@ export class DirectedGraph<
|
|
|
1110
727
|
* Strongly connected components computed by `tarjan()`.
|
|
1111
728
|
* @returns Map from SCC id to vertices.
|
|
1112
729
|
* @remarks Time O(#SCC + V), Space O(V)
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
* @example
|
|
1153
|
-
* // Get strongly connected components
|
|
1154
|
-
* const g = new DirectedGraph();
|
|
1155
|
-
* g.addVertex(1);
|
|
1156
|
-
* g.addVertex(2);
|
|
1157
|
-
* g.addVertex(3);
|
|
1158
|
-
* g.addEdge(1, 2);
|
|
1159
|
-
* g.addEdge(2, 3);
|
|
1160
|
-
* g.addEdge(3, 1);
|
|
1161
|
-
* const sccs = g.getSCCs(); // Map<number, VO[]>
|
|
1162
|
-
* console.log(sccs.size); // >= 1;
|
|
730
|
+
* @example
|
|
731
|
+
* // Get strongly connected components
|
|
732
|
+
* const g = new DirectedGraph();
|
|
733
|
+
* g.addVertex(1);
|
|
734
|
+
* g.addVertex(2);
|
|
735
|
+
* g.addVertex(3);
|
|
736
|
+
* g.addEdge(1, 2);
|
|
737
|
+
* g.addEdge(2, 3);
|
|
738
|
+
* g.addEdge(3, 1);
|
|
739
|
+
* const sccs = g.getSCCs(); // Map<number, VO[]>
|
|
740
|
+
* console.log(sccs.size); // >= 1;
|
|
1163
741
|
*/
|
|
1164
742
|
getSCCs(): Map<number, VO[]> {
|
|
1165
743
|
return this.tarjan().SCCs;
|
|
@@ -1175,10 +753,8 @@ export class DirectedGraph<
|
|
|
1175
753
|
if (!(this.hasVertex(edge.src) && this.hasVertex(edge.dest))) {
|
|
1176
754
|
return false;
|
|
1177
755
|
}
|
|
1178
|
-
|
|
1179
756
|
const srcVertex = this._getVertex(edge.src);
|
|
1180
757
|
const destVertex = this._getVertex(edge.dest);
|
|
1181
|
-
|
|
1182
758
|
if (srcVertex && destVertex) {
|
|
1183
759
|
const srcOutEdges = this._outEdgeMap.get(srcVertex);
|
|
1184
760
|
if (srcOutEdges) {
|
|
@@ -1186,7 +762,6 @@ export class DirectedGraph<
|
|
|
1186
762
|
} else {
|
|
1187
763
|
this._outEdgeMap.set(srcVertex, [edge]);
|
|
1188
764
|
}
|
|
1189
|
-
|
|
1190
765
|
const destInEdges = this._inEdgeMap.get(destVertex);
|
|
1191
766
|
if (destInEdges) {
|
|
1192
767
|
destInEdges.push(edge);
|