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 { DijkstraResult, EntryCallback, GraphOptions, VertexKey } from '../../types';
|
|
10
9
|
import { uuidV4 } from '../../utils';
|
|
11
10
|
import { ERR, raise } from '../../common';
|
|
@@ -35,7 +34,6 @@ export abstract class AbstractEdge<E = any> {
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
protected _hashCode: string;
|
|
38
|
-
|
|
39
37
|
get hashCode(): string {
|
|
40
38
|
return this._hashCode;
|
|
41
39
|
}
|
|
@@ -71,13 +69,11 @@ export abstract class AbstractGraph<
|
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
protected _options: GraphOptions<V> = { defaultEdgeWeight: 1 };
|
|
74
|
-
|
|
75
72
|
get options(): Readonly<GraphOptions<V>> {
|
|
76
73
|
return this._options;
|
|
77
74
|
}
|
|
78
75
|
|
|
79
76
|
protected _vertexMap: Map<VertexKey, VO> = new Map<VertexKey, VO>();
|
|
80
|
-
|
|
81
77
|
get vertexMap(): Map<VertexKey, VO> {
|
|
82
78
|
return this._vertexMap;
|
|
83
79
|
}
|
|
@@ -90,6 +86,14 @@ export abstract class AbstractGraph<
|
|
|
90
86
|
return this._vertexMap.size;
|
|
91
87
|
}
|
|
92
88
|
|
|
89
|
+
/**
|
|
90
|
+
* The edge connector string used in visual output.
|
|
91
|
+
* Override in subclasses (e.g., '--' for undirected, '->' for directed).
|
|
92
|
+
*/
|
|
93
|
+
protected get _edgeConnector(): string {
|
|
94
|
+
return '--';
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
/**
|
|
94
98
|
* Create a new vertex instance (implementation specific).
|
|
95
99
|
* @param key - Vertex identifier.
|
|
@@ -275,7 +279,10 @@ export abstract class AbstractGraph<
|
|
|
275
279
|
const newEdge = this.createEdge(srcOrEdge, dest, weight, value);
|
|
276
280
|
return this._addEdge(newEdge);
|
|
277
281
|
} else {
|
|
278
|
-
raise(
|
|
282
|
+
raise(
|
|
283
|
+
TypeError,
|
|
284
|
+
ERR.invalidArgument('dest must be a Vertex or vertex key when srcOrEdge is an Edge.', 'Graph')
|
|
285
|
+
);
|
|
279
286
|
}
|
|
280
287
|
}
|
|
281
288
|
}
|
|
@@ -310,22 +317,17 @@ export abstract class AbstractGraph<
|
|
|
310
317
|
const paths: VO[][] = [];
|
|
311
318
|
const vertex1 = this._getVertex(v1);
|
|
312
319
|
const vertex2 = this._getVertex(v2);
|
|
313
|
-
|
|
314
320
|
if (!(vertex1 && vertex2)) {
|
|
315
321
|
return [];
|
|
316
322
|
}
|
|
317
|
-
|
|
318
323
|
const stack: { vertex: VO; path: VO[] }[] = [];
|
|
319
324
|
stack.push({ vertex: vertex1, path: [vertex1] });
|
|
320
|
-
|
|
321
325
|
while (stack.length > 0) {
|
|
322
326
|
const { vertex, path } = stack.pop()!;
|
|
323
|
-
|
|
324
327
|
if (vertex === vertex2) {
|
|
325
328
|
paths.push(path);
|
|
326
329
|
if (paths.length >= limit) return paths;
|
|
327
330
|
}
|
|
328
|
-
|
|
329
331
|
const neighbors = this.getNeighbors(vertex);
|
|
330
332
|
for (const neighbor of neighbors) {
|
|
331
333
|
if (!path.includes(neighbor)) {
|
|
@@ -361,7 +363,6 @@ export abstract class AbstractGraph<
|
|
|
361
363
|
*/
|
|
362
364
|
getMinCostBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): number | undefined {
|
|
363
365
|
if (isWeight === undefined) isWeight = false;
|
|
364
|
-
|
|
365
366
|
if (isWeight) {
|
|
366
367
|
const allPaths = this.getAllPathsBetween(v1, v2);
|
|
367
368
|
let min = Number.MAX_SAFE_INTEGER;
|
|
@@ -375,7 +376,6 @@ export abstract class AbstractGraph<
|
|
|
375
376
|
if (!(vertex1 && vertex2)) {
|
|
376
377
|
return undefined;
|
|
377
378
|
}
|
|
378
|
-
|
|
379
379
|
const visited: Map<VO, boolean> = new Map();
|
|
380
380
|
const queue = new Queue<VO>([vertex1]);
|
|
381
381
|
visited.set(vertex1, true);
|
|
@@ -386,7 +386,6 @@ export abstract class AbstractGraph<
|
|
|
386
386
|
if (cur === vertex2) {
|
|
387
387
|
return cost;
|
|
388
388
|
}
|
|
389
|
-
|
|
390
389
|
if (cur !== undefined) {
|
|
391
390
|
const neighbors = this.getNeighbors(cur);
|
|
392
391
|
for (const neighbor of neighbors) {
|
|
@@ -414,7 +413,6 @@ export abstract class AbstractGraph<
|
|
|
414
413
|
*/
|
|
415
414
|
getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean, isDFS = false): VO[] | undefined {
|
|
416
415
|
if (isWeight === undefined) isWeight = false;
|
|
417
|
-
|
|
418
416
|
if (isWeight) {
|
|
419
417
|
if (isDFS) {
|
|
420
418
|
const allPaths = this.getAllPathsBetween(v1, v2, 10000);
|
|
@@ -447,14 +445,12 @@ export abstract class AbstractGraph<
|
|
|
447
445
|
const vertex1 = this._getVertex(v1);
|
|
448
446
|
const vertex2 = this._getVertex(v2);
|
|
449
447
|
if (!(vertex1 && vertex2)) return [];
|
|
450
|
-
|
|
451
448
|
const dfs = (cur: VO, dest: VO, visiting: Set<VO>, path: VO[]) => {
|
|
452
449
|
visiting.add(cur);
|
|
453
450
|
if (cur === dest) {
|
|
454
451
|
minPath = [vertex1, ...path];
|
|
455
452
|
return;
|
|
456
453
|
}
|
|
457
|
-
|
|
458
454
|
const neighbors = this.getNeighbors(cur);
|
|
459
455
|
for (const neighbor of neighbors) {
|
|
460
456
|
if (!visiting.has(neighbor)) {
|
|
@@ -463,10 +459,8 @@ export abstract class AbstractGraph<
|
|
|
463
459
|
path.pop();
|
|
464
460
|
}
|
|
465
461
|
}
|
|
466
|
-
|
|
467
462
|
visiting.delete(cur);
|
|
468
463
|
};
|
|
469
|
-
|
|
470
464
|
dfs(vertex1, vertex2, new Set<VO>(), []);
|
|
471
465
|
return minPath;
|
|
472
466
|
}
|
|
@@ -491,26 +485,21 @@ export abstract class AbstractGraph<
|
|
|
491
485
|
let minDest: VO | undefined = undefined;
|
|
492
486
|
let minPath: VO[] = [];
|
|
493
487
|
const paths: VO[][] = [];
|
|
494
|
-
|
|
495
488
|
const vertexMap = this._vertexMap;
|
|
496
489
|
const distMap: Map<VO, number> = new Map();
|
|
497
490
|
const seen: Set<VO> = new Set();
|
|
498
491
|
const preMap: Map<VO, VO | undefined> = new Map();
|
|
499
492
|
const srcVertex = this._getVertex(src);
|
|
500
|
-
|
|
501
493
|
const destVertex = dest ? this._getVertex(dest) : undefined;
|
|
502
|
-
|
|
503
494
|
if (!srcVertex) {
|
|
504
495
|
return undefined;
|
|
505
496
|
}
|
|
506
|
-
|
|
507
497
|
for (const vertex of vertexMap) {
|
|
508
498
|
const vertexOrKey = vertex[1];
|
|
509
499
|
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Number.MAX_SAFE_INTEGER);
|
|
510
500
|
}
|
|
511
501
|
distMap.set(srcVertex, 0);
|
|
512
502
|
preMap.set(srcVertex, undefined);
|
|
513
|
-
|
|
514
503
|
const getMinOfNoSeen = () => {
|
|
515
504
|
let min = Number.MAX_SAFE_INTEGER;
|
|
516
505
|
let minV: VO | undefined = undefined;
|
|
@@ -524,11 +513,9 @@ export abstract class AbstractGraph<
|
|
|
524
513
|
}
|
|
525
514
|
return minV;
|
|
526
515
|
};
|
|
527
|
-
|
|
528
516
|
const getPaths = (minV: VO | undefined) => {
|
|
529
517
|
for (const vertex of vertexMap) {
|
|
530
518
|
const vertexOrKey = vertex[1];
|
|
531
|
-
|
|
532
519
|
if (vertexOrKey instanceof AbstractVertex) {
|
|
533
520
|
const path: VO[] = [vertexOrKey];
|
|
534
521
|
let parent = preMap.get(vertexOrKey);
|
|
@@ -542,7 +529,6 @@ export abstract class AbstractGraph<
|
|
|
542
529
|
}
|
|
543
530
|
}
|
|
544
531
|
};
|
|
545
|
-
|
|
546
532
|
for (let i = 1; i < vertexMap.size; i++) {
|
|
547
533
|
const cur = getMinOfNoSeen();
|
|
548
534
|
if (cur) {
|
|
@@ -563,7 +549,6 @@ export abstract class AbstractGraph<
|
|
|
563
549
|
if (edge) {
|
|
564
550
|
const curFromMap = distMap.get(cur);
|
|
565
551
|
const neighborFromMap = distMap.get(neighbor);
|
|
566
|
-
|
|
567
552
|
if (curFromMap !== undefined && neighborFromMap !== undefined) {
|
|
568
553
|
if (edge.weight + curFromMap < neighborFromMap) {
|
|
569
554
|
distMap.set(neighbor, edge.weight + curFromMap);
|
|
@@ -575,7 +560,6 @@ export abstract class AbstractGraph<
|
|
|
575
560
|
}
|
|
576
561
|
}
|
|
577
562
|
}
|
|
578
|
-
|
|
579
563
|
if (getMinDist)
|
|
580
564
|
distMap.forEach((d, v) => {
|
|
581
565
|
if (v !== srcVertex) {
|
|
@@ -585,9 +569,7 @@ export abstract class AbstractGraph<
|
|
|
585
569
|
}
|
|
586
570
|
}
|
|
587
571
|
});
|
|
588
|
-
|
|
589
572
|
if (genPaths) getPaths(minDest);
|
|
590
|
-
|
|
591
573
|
return { distMap, preMap, seen, paths, minDist, minPath };
|
|
592
574
|
}
|
|
593
575
|
|
|
@@ -605,23 +587,17 @@ export abstract class AbstractGraph<
|
|
|
605
587
|
const distMap: Map<VO, number> = new Map();
|
|
606
588
|
const seen: Set<VO> = new Set();
|
|
607
589
|
const preMap: Map<VO, VO | undefined> = new Map();
|
|
608
|
-
|
|
609
590
|
const srcVertex = this._getVertex(src);
|
|
610
591
|
const destVertex = dest ? this._getVertex(dest) : undefined;
|
|
611
|
-
|
|
612
592
|
if (!srcVertex) return undefined;
|
|
613
|
-
|
|
614
593
|
for (const vertex of vertexMap) {
|
|
615
594
|
const vertexOrKey = vertex[1];
|
|
616
595
|
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Number.MAX_SAFE_INTEGER);
|
|
617
596
|
}
|
|
618
|
-
|
|
619
597
|
const heap = new Heap<{ key: number; value: VO }>([], { comparator: (a, b) => a.key - b.key });
|
|
620
598
|
heap.add({ key: 0, value: srcVertex });
|
|
621
|
-
|
|
622
599
|
distMap.set(srcVertex, 0);
|
|
623
600
|
preMap.set(srcVertex, undefined);
|
|
624
|
-
|
|
625
601
|
const getPaths = (minV: VO | undefined) => {
|
|
626
602
|
for (const vertex of vertexMap) {
|
|
627
603
|
const vertexOrKey = vertex[1];
|
|
@@ -638,7 +614,6 @@ export abstract class AbstractGraph<
|
|
|
638
614
|
}
|
|
639
615
|
}
|
|
640
616
|
};
|
|
641
|
-
|
|
642
617
|
while (heap.size > 0) {
|
|
643
618
|
const curHeapNode = heap.poll();
|
|
644
619
|
const dist = curHeapNode?.key;
|
|
@@ -674,7 +649,6 @@ export abstract class AbstractGraph<
|
|
|
674
649
|
}
|
|
675
650
|
}
|
|
676
651
|
}
|
|
677
|
-
|
|
678
652
|
if (getMinDist) {
|
|
679
653
|
distMap.forEach((d, v) => {
|
|
680
654
|
if (v !== srcVertex) {
|
|
@@ -685,11 +659,9 @@ export abstract class AbstractGraph<
|
|
|
685
659
|
}
|
|
686
660
|
});
|
|
687
661
|
}
|
|
688
|
-
|
|
689
662
|
if (genPaths) {
|
|
690
663
|
getPaths(minDest);
|
|
691
664
|
}
|
|
692
|
-
|
|
693
665
|
return { distMap, preMap, seen, paths, minDist, minPath };
|
|
694
666
|
}
|
|
695
667
|
|
|
@@ -705,29 +677,23 @@ export abstract class AbstractGraph<
|
|
|
705
677
|
bellmanFord(src: VO | VertexKey, scanNegativeCycle?: boolean, getMin?: boolean, genPath?: boolean) {
|
|
706
678
|
if (getMin === undefined) getMin = false;
|
|
707
679
|
if (genPath === undefined) genPath = false;
|
|
708
|
-
|
|
709
680
|
const srcVertex = this._getVertex(src);
|
|
710
681
|
const paths: VO[][] = [];
|
|
711
682
|
const distMap: Map<VO, number> = new Map();
|
|
712
683
|
const preMap: Map<VO, VO> = new Map();
|
|
713
684
|
let min = Number.MAX_SAFE_INTEGER;
|
|
714
685
|
let minPath: VO[] = [];
|
|
715
|
-
|
|
716
686
|
let hasNegativeCycle: boolean | undefined;
|
|
717
687
|
if (scanNegativeCycle) hasNegativeCycle = false;
|
|
718
688
|
if (!srcVertex) return { hasNegativeCycle, distMap, preMap, paths, min, minPath };
|
|
719
|
-
|
|
720
689
|
const vertexMap = this._vertexMap;
|
|
721
690
|
const numOfVertices = vertexMap.size;
|
|
722
691
|
const edgeMap = this.edgeSet();
|
|
723
692
|
const numOfEdges = edgeMap.length;
|
|
724
|
-
|
|
725
693
|
this._vertexMap.forEach(vertex => {
|
|
726
694
|
distMap.set(vertex, Number.MAX_SAFE_INTEGER);
|
|
727
695
|
});
|
|
728
|
-
|
|
729
696
|
distMap.set(srcVertex, 0);
|
|
730
|
-
|
|
731
697
|
for (let i = 1; i < numOfVertices; ++i) {
|
|
732
698
|
for (let j = 0; j < numOfEdges; ++j) {
|
|
733
699
|
const ends = this.getEndsOfEdge(edgeMap[j]);
|
|
@@ -745,7 +711,6 @@ export abstract class AbstractGraph<
|
|
|
745
711
|
}
|
|
746
712
|
}
|
|
747
713
|
}
|
|
748
|
-
|
|
749
714
|
let minDest: VO | undefined = undefined;
|
|
750
715
|
if (getMin) {
|
|
751
716
|
distMap.forEach((d, v) => {
|
|
@@ -757,7 +722,6 @@ export abstract class AbstractGraph<
|
|
|
757
722
|
}
|
|
758
723
|
});
|
|
759
724
|
}
|
|
760
|
-
|
|
761
725
|
if (genPath) {
|
|
762
726
|
for (const vertex of vertexMap) {
|
|
763
727
|
const vertexOrKey = vertex[1];
|
|
@@ -774,7 +738,6 @@ export abstract class AbstractGraph<
|
|
|
774
738
|
}
|
|
775
739
|
}
|
|
776
740
|
}
|
|
777
|
-
|
|
778
741
|
for (let j = 0; j < numOfEdges; ++j) {
|
|
779
742
|
const ends = this.getEndsOfEdge(edgeMap[j]);
|
|
780
743
|
if (ends) {
|
|
@@ -786,7 +749,6 @@ export abstract class AbstractGraph<
|
|
|
786
749
|
}
|
|
787
750
|
}
|
|
788
751
|
}
|
|
789
|
-
|
|
790
752
|
return { hasNegativeCycle, distMap, preMap, paths, min, minPath };
|
|
791
753
|
}
|
|
792
754
|
|
|
@@ -798,10 +760,8 @@ export abstract class AbstractGraph<
|
|
|
798
760
|
floydWarshall(): { costs: number[][]; predecessor: (VO | undefined)[][] } {
|
|
799
761
|
const idAndVertices = [...this._vertexMap];
|
|
800
762
|
const n = idAndVertices.length;
|
|
801
|
-
|
|
802
763
|
const costs: number[][] = [];
|
|
803
764
|
const predecessor: (VO | undefined)[][] = [];
|
|
804
|
-
|
|
805
765
|
for (let i = 0; i < n; i++) {
|
|
806
766
|
costs[i] = [];
|
|
807
767
|
predecessor[i] = [];
|
|
@@ -809,13 +769,11 @@ export abstract class AbstractGraph<
|
|
|
809
769
|
predecessor[i][j] = undefined;
|
|
810
770
|
}
|
|
811
771
|
}
|
|
812
|
-
|
|
813
772
|
for (let i = 0; i < n; i++) {
|
|
814
773
|
for (let j = 0; j < n; j++) {
|
|
815
774
|
costs[i][j] = this.getEdge(idAndVertices[i][1], idAndVertices[j][1])?.weight || Number.MAX_SAFE_INTEGER;
|
|
816
775
|
}
|
|
817
776
|
}
|
|
818
|
-
|
|
819
777
|
for (let k = 0; k < n; k++) {
|
|
820
778
|
for (let i = 0; i < n; i++) {
|
|
821
779
|
for (let j = 0; j < n; j++) {
|
|
@@ -838,7 +796,6 @@ export abstract class AbstractGraph<
|
|
|
838
796
|
getCycles(isInclude2Cycle: boolean = false): VertexKey[][] {
|
|
839
797
|
const cycles: VertexKey[][] = [];
|
|
840
798
|
const visited: Set<VO> = new Set();
|
|
841
|
-
|
|
842
799
|
const dfs = (vertex: VO, currentPath: VertexKey[], visited: Set<VO>) => {
|
|
843
800
|
if (visited.has(vertex)) {
|
|
844
801
|
if (
|
|
@@ -849,27 +806,20 @@ export abstract class AbstractGraph<
|
|
|
849
806
|
}
|
|
850
807
|
return;
|
|
851
808
|
}
|
|
852
|
-
|
|
853
809
|
visited.add(vertex);
|
|
854
810
|
currentPath.push(vertex.key);
|
|
855
|
-
|
|
856
811
|
for (const neighbor of this.getNeighbors(vertex)) {
|
|
857
812
|
if (neighbor) dfs(neighbor, currentPath, visited);
|
|
858
813
|
}
|
|
859
|
-
|
|
860
814
|
visited.delete(vertex);
|
|
861
815
|
currentPath.pop();
|
|
862
816
|
};
|
|
863
|
-
|
|
864
817
|
for (const vertex of this.vertexMap.values()) {
|
|
865
818
|
dfs(vertex, [], visited);
|
|
866
819
|
}
|
|
867
|
-
|
|
868
820
|
const uniqueCycles = new Map<string, VertexKey[]>();
|
|
869
|
-
|
|
870
821
|
for (const cycle of cycles) {
|
|
871
822
|
const sorted = [...cycle].sort().toString();
|
|
872
|
-
|
|
873
823
|
if (uniqueCycles.has(sorted)) continue;
|
|
874
824
|
else {
|
|
875
825
|
uniqueCycles.set(sorted, cycle);
|
|
@@ -935,6 +885,8 @@ export abstract class AbstractGraph<
|
|
|
935
885
|
return mapped;
|
|
936
886
|
}
|
|
937
887
|
|
|
888
|
+
// ===== Same-species factory & cloning helpers =====
|
|
889
|
+
|
|
938
890
|
/**
|
|
939
891
|
* Create a deep clone of the graph with the same species.
|
|
940
892
|
* @remarks Time O(V + E), Space O(V + E)
|
|
@@ -948,7 +900,90 @@ export abstract class AbstractGraph<
|
|
|
948
900
|
return this._createLike(undefined, this._snapshotOptions());
|
|
949
901
|
}
|
|
950
902
|
|
|
951
|
-
|
|
903
|
+
/**
|
|
904
|
+
* Generate a text-based visual representation of the graph.
|
|
905
|
+
*
|
|
906
|
+
* **Adjacency list format:**
|
|
907
|
+
* ```
|
|
908
|
+
* Graph (5 vertices, 6 edges):
|
|
909
|
+
* A -> B (1), C (2)
|
|
910
|
+
* B -> D (3)
|
|
911
|
+
* C -> (no outgoing edges)
|
|
912
|
+
* D -> A (1)
|
|
913
|
+
* E (isolated)
|
|
914
|
+
* ```
|
|
915
|
+
*
|
|
916
|
+
* @param options - Optional display settings.
|
|
917
|
+
* @param options.showWeight - Whether to show edge weights (default: true).
|
|
918
|
+
* @returns The visual string.
|
|
919
|
+
*/
|
|
920
|
+
override toVisual(options?: { showWeight?: boolean }): string {
|
|
921
|
+
const showWeight = options?.showWeight ?? true;
|
|
922
|
+
const vertices = [...this._vertexMap.values()];
|
|
923
|
+
const vertexCount = vertices.length;
|
|
924
|
+
const edgeCount = this.edgeSet().length;
|
|
925
|
+
const lines: string[] = [`Graph (${vertexCount} vertices, ${edgeCount} edges):`];
|
|
926
|
+
for (const vertex of vertices) {
|
|
927
|
+
const neighbors = this.getNeighbors(vertex);
|
|
928
|
+
if (neighbors.length === 0) {
|
|
929
|
+
lines.push(` ${vertex.key} (isolated)`);
|
|
930
|
+
} else {
|
|
931
|
+
const edgeStrs = neighbors.map(neighbor => {
|
|
932
|
+
const edge = this.getEdge(vertex, neighbor);
|
|
933
|
+
if (edge && showWeight && edge.weight !== undefined && edge.weight !== 1) {
|
|
934
|
+
return `${neighbor.key} (${edge.weight})`;
|
|
935
|
+
}
|
|
936
|
+
return `${neighbor.key}`;
|
|
937
|
+
});
|
|
938
|
+
lines.push(` ${vertex.key} ${this._edgeConnector} ${edgeStrs.join(', ')}`);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return lines.join('\n');
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Generate DOT language representation for Graphviz.
|
|
946
|
+
*
|
|
947
|
+
* @param options - Optional display settings.
|
|
948
|
+
* @param options.name - Graph name (default: 'G').
|
|
949
|
+
* @param options.showWeight - Whether to label edges with weight (default: true).
|
|
950
|
+
* @returns DOT format string.
|
|
951
|
+
*/
|
|
952
|
+
toDot(options?: { name?: string; showWeight?: boolean }): string {
|
|
953
|
+
const name = options?.name ?? 'G';
|
|
954
|
+
const showWeight = options?.showWeight ?? true;
|
|
955
|
+
const isDirected = this._edgeConnector === '->';
|
|
956
|
+
const graphType = isDirected ? 'digraph' : 'graph';
|
|
957
|
+
const edgeOp = isDirected ? '->' : '--';
|
|
958
|
+
const lines: string[] = [`${graphType} ${name} {`];
|
|
959
|
+
// Add all vertices (ensures isolated vertices appear)
|
|
960
|
+
for (const vertex of this._vertexMap.values()) {
|
|
961
|
+
lines.push(` "${vertex.key}";`);
|
|
962
|
+
}
|
|
963
|
+
// Add edges
|
|
964
|
+
const visited = new Set<string>();
|
|
965
|
+
for (const vertex of this._vertexMap.values()) {
|
|
966
|
+
for (const neighbor of this.getNeighbors(vertex)) {
|
|
967
|
+
const edgeId = isDirected ? `${vertex.key}->${neighbor.key}` : [vertex.key, neighbor.key].sort().join('--');
|
|
968
|
+
if (visited.has(edgeId)) continue;
|
|
969
|
+
visited.add(edgeId);
|
|
970
|
+
const edge = this.getEdge(vertex, neighbor);
|
|
971
|
+
const label =
|
|
972
|
+
edge && showWeight && edge.weight !== undefined && edge.weight !== 1 ? ` [label="${edge.weight}"]` : '';
|
|
973
|
+
lines.push(` "${vertex.key}" ${edgeOp} "${neighbor.key}"${label};`);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
lines.push('}');
|
|
977
|
+
return lines.join('\n');
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Print the graph to console.
|
|
982
|
+
* @param options - Display settings passed to `toVisual`.
|
|
983
|
+
*/
|
|
984
|
+
override print(options?: { showWeight?: boolean }): void {
|
|
985
|
+
console.log(this.toVisual(options));
|
|
986
|
+
}
|
|
952
987
|
|
|
953
988
|
/**
|
|
954
989
|
* Internal iterator over `[key, value]` entries in insertion order.
|
|
@@ -1079,108 +1114,4 @@ export abstract class AbstractGraph<
|
|
|
1079
1114
|
protected _getVertexKey(vertexOrKey: VO | VertexKey): VertexKey {
|
|
1080
1115
|
return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
|
|
1081
1116
|
}
|
|
1082
|
-
|
|
1083
|
-
/**
|
|
1084
|
-
* The edge connector string used in visual output.
|
|
1085
|
-
* Override in subclasses (e.g., '--' for undirected, '->' for directed).
|
|
1086
|
-
*/
|
|
1087
|
-
protected get _edgeConnector(): string {
|
|
1088
|
-
return '--';
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
/**
|
|
1092
|
-
* Generate a text-based visual representation of the graph.
|
|
1093
|
-
*
|
|
1094
|
-
* **Adjacency list format:**
|
|
1095
|
-
* ```
|
|
1096
|
-
* Graph (5 vertices, 6 edges):
|
|
1097
|
-
* A -> B (1), C (2)
|
|
1098
|
-
* B -> D (3)
|
|
1099
|
-
* C -> (no outgoing edges)
|
|
1100
|
-
* D -> A (1)
|
|
1101
|
-
* E (isolated)
|
|
1102
|
-
* ```
|
|
1103
|
-
*
|
|
1104
|
-
* @param options - Optional display settings.
|
|
1105
|
-
* @param options.showWeight - Whether to show edge weights (default: true).
|
|
1106
|
-
* @returns The visual string.
|
|
1107
|
-
*/
|
|
1108
|
-
override toVisual(options?: { showWeight?: boolean }): string {
|
|
1109
|
-
const showWeight = options?.showWeight ?? true;
|
|
1110
|
-
const vertices = [...this._vertexMap.values()];
|
|
1111
|
-
const vertexCount = vertices.length;
|
|
1112
|
-
const edgeCount = this.edgeSet().length;
|
|
1113
|
-
|
|
1114
|
-
const lines: string[] = [`Graph (${vertexCount} vertices, ${edgeCount} edges):`];
|
|
1115
|
-
|
|
1116
|
-
for (const vertex of vertices) {
|
|
1117
|
-
const neighbors = this.getNeighbors(vertex);
|
|
1118
|
-
if (neighbors.length === 0) {
|
|
1119
|
-
lines.push(` ${vertex.key} (isolated)`);
|
|
1120
|
-
} else {
|
|
1121
|
-
const edgeStrs = neighbors.map(neighbor => {
|
|
1122
|
-
const edge = this.getEdge(vertex, neighbor);
|
|
1123
|
-
if (edge && showWeight && edge.weight !== undefined && edge.weight !== 1) {
|
|
1124
|
-
return `${neighbor.key} (${edge.weight})`;
|
|
1125
|
-
}
|
|
1126
|
-
return `${neighbor.key}`;
|
|
1127
|
-
});
|
|
1128
|
-
lines.push(` ${vertex.key} ${this._edgeConnector} ${edgeStrs.join(', ')}`);
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
return lines.join('\n');
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
/**
|
|
1136
|
-
* Generate DOT language representation for Graphviz.
|
|
1137
|
-
*
|
|
1138
|
-
* @param options - Optional display settings.
|
|
1139
|
-
* @param options.name - Graph name (default: 'G').
|
|
1140
|
-
* @param options.showWeight - Whether to label edges with weight (default: true).
|
|
1141
|
-
* @returns DOT format string.
|
|
1142
|
-
*/
|
|
1143
|
-
toDot(options?: { name?: string; showWeight?: boolean }): string {
|
|
1144
|
-
const name = options?.name ?? 'G';
|
|
1145
|
-
const showWeight = options?.showWeight ?? true;
|
|
1146
|
-
const isDirected = this._edgeConnector === '->';
|
|
1147
|
-
const graphType = isDirected ? 'digraph' : 'graph';
|
|
1148
|
-
const edgeOp = isDirected ? '->' : '--';
|
|
1149
|
-
|
|
1150
|
-
const lines: string[] = [`${graphType} ${name} {`];
|
|
1151
|
-
|
|
1152
|
-
// Add all vertices (ensures isolated vertices appear)
|
|
1153
|
-
for (const vertex of this._vertexMap.values()) {
|
|
1154
|
-
lines.push(` "${vertex.key}";`);
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
// Add edges
|
|
1158
|
-
const visited = new Set<string>();
|
|
1159
|
-
for (const vertex of this._vertexMap.values()) {
|
|
1160
|
-
for (const neighbor of this.getNeighbors(vertex)) {
|
|
1161
|
-
const edgeId = isDirected
|
|
1162
|
-
? `${vertex.key}->${neighbor.key}`
|
|
1163
|
-
: [vertex.key, neighbor.key].sort().join('--');
|
|
1164
|
-
if (visited.has(edgeId)) continue;
|
|
1165
|
-
visited.add(edgeId);
|
|
1166
|
-
|
|
1167
|
-
const edge = this.getEdge(vertex, neighbor);
|
|
1168
|
-
const label = edge && showWeight && edge.weight !== undefined && edge.weight !== 1
|
|
1169
|
-
? ` [label="${edge.weight}"]`
|
|
1170
|
-
: '';
|
|
1171
|
-
lines.push(` "${vertex.key}" ${edgeOp} "${neighbor.key}"${label};`);
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
lines.push('}');
|
|
1176
|
-
return lines.join('\n');
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
/**
|
|
1180
|
-
* Print the graph to console.
|
|
1181
|
-
* @param options - Display settings passed to `toVisual`.
|
|
1182
|
-
*/
|
|
1183
|
-
override print(options?: { showWeight?: boolean }): void {
|
|
1184
|
-
console.log(this.toVisual(options));
|
|
1185
|
-
}
|
|
1186
1117
|
}
|