tree-set-typed 2.3.0
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/.eslintrc.js +61 -0
- package/.prettierignore +6 -0
- package/.prettierrc.js +16 -0
- package/LICENSE +21 -0
- package/README.md +482 -0
- package/coverage/clover.xml +13 -0
- package/coverage/coverage-final.json +96 -0
- package/coverage/coverage-summary.json +60 -0
- package/coverage/lcov-report/base.css +403 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +119 -0
- package/coverage/lcov-report/index.ts.html +109 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +206 -0
- package/coverage/lcov.info +14 -0
- package/dist/cjs/index.cjs +12 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs-legacy/index.cjs +12 -0
- package/dist/cjs-legacy/index.cjs.map +1 -0
- package/dist/esm/index.mjs +3 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm-legacy/index.mjs +3 -0
- package/dist/esm-legacy/index.mjs.map +1 -0
- package/dist/types/common/index.d.ts +12 -0
- package/dist/types/constants/index.d.ts +4 -0
- package/dist/types/data-structures/base/index.d.ts +2 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +219 -0
- package/dist/types/data-structures/base/iterable-entry-base.d.ts +150 -0
- package/dist/types/data-structures/base/linear-base.d.ts +335 -0
- package/dist/types/data-structures/binary-tree/avl-tree-counter.d.ts +236 -0
- package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +197 -0
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +440 -0
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +174 -0
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +807 -0
- package/dist/types/data-structures/binary-tree/bst.d.ts +645 -0
- package/dist/types/data-structures/binary-tree/index.d.ts +10 -0
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +312 -0
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +160 -0
- package/dist/types/data-structures/binary-tree/tree-counter.d.ts +243 -0
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +333 -0
- package/dist/types/data-structures/graph/abstract-graph.d.ts +340 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +332 -0
- package/dist/types/data-structures/graph/index.d.ts +4 -0
- package/dist/types/data-structures/graph/map-graph.d.ts +78 -0
- package/dist/types/data-structures/graph/undirected-graph.d.ts +347 -0
- package/dist/types/data-structures/hash/hash-map.d.ts +428 -0
- package/dist/types/data-structures/hash/index.d.ts +1 -0
- package/dist/types/data-structures/heap/heap.d.ts +552 -0
- package/dist/types/data-structures/heap/index.d.ts +3 -0
- package/dist/types/data-structures/heap/max-heap.d.ts +32 -0
- package/dist/types/data-structures/heap/min-heap.d.ts +33 -0
- package/dist/types/data-structures/index.d.ts +12 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +437 -0
- package/dist/types/data-structures/linked-list/index.d.ts +3 -0
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +567 -0
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +27 -0
- package/dist/types/data-structures/matrix/index.d.ts +2 -0
- package/dist/types/data-structures/matrix/matrix.d.ts +168 -0
- package/dist/types/data-structures/matrix/navigator.d.ts +55 -0
- package/dist/types/data-structures/priority-queue/index.d.ts +3 -0
- package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +27 -0
- package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +26 -0
- package/dist/types/data-structures/priority-queue/priority-queue.d.ts +15 -0
- package/dist/types/data-structures/queue/deque.d.ts +459 -0
- package/dist/types/data-structures/queue/index.d.ts +2 -0
- package/dist/types/data-structures/queue/queue.d.ts +364 -0
- package/dist/types/data-structures/stack/index.d.ts +1 -0
- package/dist/types/data-structures/stack/stack.d.ts +324 -0
- package/dist/types/data-structures/tree/index.d.ts +1 -0
- package/dist/types/data-structures/tree/tree.d.ts +62 -0
- package/dist/types/data-structures/trie/index.d.ts +1 -0
- package/dist/types/data-structures/trie/trie.d.ts +412 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/interfaces/binary-tree.d.ts +60 -0
- package/dist/types/interfaces/doubly-linked-list.d.ts +1 -0
- package/dist/types/interfaces/graph.d.ts +21 -0
- package/dist/types/interfaces/heap.d.ts +1 -0
- package/dist/types/interfaces/index.d.ts +8 -0
- package/dist/types/interfaces/navigator.d.ts +1 -0
- package/dist/types/interfaces/priority-queue.d.ts +1 -0
- package/dist/types/interfaces/segment-tree.d.ts +1 -0
- package/dist/types/interfaces/singly-linked-list.d.ts +1 -0
- package/dist/types/types/common.d.ts +15 -0
- package/dist/types/types/data-structures/base/base.d.ts +13 -0
- package/dist/types/types/data-structures/base/index.d.ts +1 -0
- package/dist/types/types/data-structures/binary-tree/avl-tree-counter.d.ts +2 -0
- package/dist/types/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +2 -0
- package/dist/types/types/data-structures/binary-tree/avl-tree.d.ts +2 -0
- package/dist/types/types/data-structures/binary-tree/binary-indexed-tree.d.ts +1 -0
- package/dist/types/types/data-structures/binary-tree/binary-tree.d.ts +29 -0
- package/dist/types/types/data-structures/binary-tree/bst.d.ts +12 -0
- package/dist/types/types/data-structures/binary-tree/index.d.ts +9 -0
- package/dist/types/types/data-structures/binary-tree/red-black-tree.d.ts +3 -0
- package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -0
- package/dist/types/types/data-structures/binary-tree/tree-counter.d.ts +2 -0
- package/dist/types/types/data-structures/binary-tree/tree-multi-map.d.ts +2 -0
- package/dist/types/types/data-structures/graph/abstract-graph.d.ts +14 -0
- package/dist/types/types/data-structures/graph/directed-graph.d.ts +1 -0
- package/dist/types/types/data-structures/graph/index.d.ts +3 -0
- package/dist/types/types/data-structures/graph/map-graph.d.ts +1 -0
- package/dist/types/types/data-structures/graph/undirected-graph.d.ts +1 -0
- package/dist/types/types/data-structures/hash/hash-map.d.ts +19 -0
- package/dist/types/types/data-structures/hash/index.d.ts +2 -0
- package/dist/types/types/data-structures/heap/heap.d.ts +5 -0
- package/dist/types/types/data-structures/heap/index.d.ts +1 -0
- package/dist/types/types/data-structures/heap/max-heap.d.ts +1 -0
- package/dist/types/types/data-structures/heap/min-heap.d.ts +1 -0
- package/dist/types/types/data-structures/index.d.ts +12 -0
- package/dist/types/types/data-structures/linked-list/doubly-linked-list.d.ts +2 -0
- package/dist/types/types/data-structures/linked-list/index.d.ts +3 -0
- package/dist/types/types/data-structures/linked-list/singly-linked-list.d.ts +2 -0
- package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +4 -0
- package/dist/types/types/data-structures/matrix/index.d.ts +2 -0
- package/dist/types/types/data-structures/matrix/matrix.d.ts +7 -0
- package/dist/types/types/data-structures/matrix/navigator.d.ts +14 -0
- package/dist/types/types/data-structures/priority-queue/index.d.ts +3 -0
- package/dist/types/types/data-structures/priority-queue/max-priority-queue.d.ts +1 -0
- package/dist/types/types/data-structures/priority-queue/min-priority-queue.d.ts +1 -0
- package/dist/types/types/data-structures/priority-queue/priority-queue.d.ts +2 -0
- package/dist/types/types/data-structures/queue/deque.d.ts +4 -0
- package/dist/types/types/data-structures/queue/index.d.ts +2 -0
- package/dist/types/types/data-structures/queue/queue.d.ts +4 -0
- package/dist/types/types/data-structures/stack/index.d.ts +1 -0
- package/dist/types/types/data-structures/stack/stack.d.ts +2 -0
- package/dist/types/types/data-structures/tree/index.d.ts +1 -0
- package/dist/types/types/data-structures/tree/tree.d.ts +1 -0
- package/dist/types/types/data-structures/trie/index.d.ts +1 -0
- package/dist/types/types/data-structures/trie/trie.d.ts +4 -0
- package/dist/types/types/index.d.ts +3 -0
- package/dist/types/types/utils/index.d.ts +2 -0
- package/dist/types/types/utils/utils.d.ts +22 -0
- package/dist/types/types/utils/validate-type.d.ts +19 -0
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/number.d.ts +14 -0
- package/dist/types/utils/utils.d.ts +209 -0
- package/dist/umd/red-black-tree-typed.js +14578 -0
- package/dist/umd/red-black-tree-typed.js.map +1 -0
- package/dist/umd/red-black-tree-typed.min.js +44 -0
- package/dist/umd/red-black-tree-typed.min.js.map +1 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/highlight.css +92 -0
- package/docs/assets/main.js +59 -0
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1383 -0
- package/docs/classes/AVLTree.html +2046 -0
- package/docs/classes/AVLTreeNode.html +263 -0
- package/docs/index.html +523 -0
- package/docs/modules.html +45 -0
- package/jest.config.js +8 -0
- package/package.json +113 -0
- package/src/common/index.ts +23 -0
- package/src/constants/index.ts +4 -0
- package/src/data-structures/base/index.ts +2 -0
- package/src/data-structures/base/iterable-element-base.ts +352 -0
- package/src/data-structures/base/iterable-entry-base.ts +246 -0
- package/src/data-structures/base/linear-base.ts +643 -0
- package/src/data-structures/binary-tree/avl-tree-counter.ts +539 -0
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +438 -0
- package/src/data-structures/binary-tree/avl-tree.ts +840 -0
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +331 -0
- package/src/data-structures/binary-tree/binary-tree.ts +2492 -0
- package/src/data-structures/binary-tree/bst.ts +2024 -0
- package/src/data-structures/binary-tree/index.ts +10 -0
- package/src/data-structures/binary-tree/red-black-tree.ts +767 -0
- package/src/data-structures/binary-tree/segment-tree.ts +324 -0
- package/src/data-structures/binary-tree/tree-counter.ts +575 -0
- package/src/data-structures/binary-tree/tree-multi-map.ts +549 -0
- package/src/data-structures/graph/abstract-graph.ts +1081 -0
- package/src/data-structures/graph/directed-graph.ts +715 -0
- package/src/data-structures/graph/index.ts +4 -0
- package/src/data-structures/graph/map-graph.ts +132 -0
- package/src/data-structures/graph/undirected-graph.ts +626 -0
- package/src/data-structures/hash/hash-map.ts +813 -0
- package/src/data-structures/hash/index.ts +1 -0
- package/src/data-structures/heap/heap.ts +1020 -0
- package/src/data-structures/heap/index.ts +3 -0
- package/src/data-structures/heap/max-heap.ts +47 -0
- package/src/data-structures/heap/min-heap.ts +36 -0
- package/src/data-structures/index.ts +12 -0
- package/src/data-structures/linked-list/doubly-linked-list.ts +876 -0
- package/src/data-structures/linked-list/index.ts +3 -0
- package/src/data-structures/linked-list/singly-linked-list.ts +1050 -0
- package/src/data-structures/linked-list/skip-linked-list.ts +173 -0
- package/src/data-structures/matrix/index.ts +2 -0
- package/src/data-structures/matrix/matrix.ts +491 -0
- package/src/data-structures/matrix/navigator.ts +124 -0
- package/src/data-structures/priority-queue/index.ts +3 -0
- package/src/data-structures/priority-queue/max-priority-queue.ts +42 -0
- package/src/data-structures/priority-queue/min-priority-queue.ts +29 -0
- package/src/data-structures/priority-queue/priority-queue.ts +19 -0
- package/src/data-structures/queue/deque.ts +1001 -0
- package/src/data-structures/queue/index.ts +2 -0
- package/src/data-structures/queue/queue.ts +592 -0
- package/src/data-structures/stack/index.ts +1 -0
- package/src/data-structures/stack/stack.ts +469 -0
- package/src/data-structures/tree/index.ts +1 -0
- package/src/data-structures/tree/tree.ts +115 -0
- package/src/data-structures/trie/index.ts +1 -0
- package/src/data-structures/trie/trie.ts +756 -0
- package/src/index.ts +24 -0
- package/src/interfaces/binary-tree.ts +252 -0
- package/src/interfaces/doubly-linked-list.ts +1 -0
- package/src/interfaces/graph.ts +44 -0
- package/src/interfaces/heap.ts +1 -0
- package/src/interfaces/index.ts +8 -0
- package/src/interfaces/navigator.ts +1 -0
- package/src/interfaces/priority-queue.ts +1 -0
- package/src/interfaces/segment-tree.ts +1 -0
- package/src/interfaces/singly-linked-list.ts +1 -0
- package/src/types/common.ts +25 -0
- package/src/types/data-structures/base/base.ts +34 -0
- package/src/types/data-structures/base/index.ts +1 -0
- package/src/types/data-structures/binary-tree/avl-tree-counter.ts +3 -0
- package/src/types/data-structures/binary-tree/avl-tree-multi-map.ts +3 -0
- package/src/types/data-structures/binary-tree/avl-tree.ts +3 -0
- package/src/types/data-structures/binary-tree/binary-indexed-tree.ts +1 -0
- package/src/types/data-structures/binary-tree/binary-tree.ts +31 -0
- package/src/types/data-structures/binary-tree/bst.ts +19 -0
- package/src/types/data-structures/binary-tree/index.ts +9 -0
- package/src/types/data-structures/binary-tree/red-black-tree.ts +5 -0
- package/src/types/data-structures/binary-tree/segment-tree.ts +1 -0
- package/src/types/data-structures/binary-tree/tree-counter.ts +3 -0
- package/src/types/data-structures/binary-tree/tree-multi-map.ts +3 -0
- package/src/types/data-structures/graph/abstract-graph.ts +18 -0
- package/src/types/data-structures/graph/directed-graph.ts +2 -0
- package/src/types/data-structures/graph/index.ts +3 -0
- package/src/types/data-structures/graph/map-graph.ts +1 -0
- package/src/types/data-structures/graph/undirected-graph.ts +1 -0
- package/src/types/data-structures/hash/hash-map.ts +19 -0
- package/src/types/data-structures/hash/index.ts +3 -0
- package/src/types/data-structures/heap/heap.ts +6 -0
- package/src/types/data-structures/heap/index.ts +1 -0
- package/src/types/data-structures/heap/max-heap.ts +1 -0
- package/src/types/data-structures/heap/min-heap.ts +1 -0
- package/src/types/data-structures/index.ts +12 -0
- package/src/types/data-structures/linked-list/doubly-linked-list.ts +3 -0
- package/src/types/data-structures/linked-list/index.ts +3 -0
- package/src/types/data-structures/linked-list/singly-linked-list.ts +3 -0
- package/src/types/data-structures/linked-list/skip-linked-list.ts +1 -0
- package/src/types/data-structures/matrix/index.ts +2 -0
- package/src/types/data-structures/matrix/matrix.ts +7 -0
- package/src/types/data-structures/matrix/navigator.ts +14 -0
- package/src/types/data-structures/priority-queue/index.ts +3 -0
- package/src/types/data-structures/priority-queue/max-priority-queue.ts +1 -0
- package/src/types/data-structures/priority-queue/min-priority-queue.ts +1 -0
- package/src/types/data-structures/priority-queue/priority-queue.ts +3 -0
- package/src/types/data-structures/queue/deque.ts +5 -0
- package/src/types/data-structures/queue/index.ts +2 -0
- package/src/types/data-structures/queue/queue.ts +5 -0
- package/src/types/data-structures/stack/index.ts +1 -0
- package/src/types/data-structures/stack/stack.ts +3 -0
- package/src/types/data-structures/tree/index.ts +1 -0
- package/src/types/data-structures/tree/tree.ts +1 -0
- package/src/types/data-structures/trie/index.ts +1 -0
- package/src/types/data-structures/trie/trie.ts +3 -0
- package/src/types/index.ts +3 -0
- package/src/types/utils/index.ts +2 -0
- package/src/types/utils/utils.ts +33 -0
- package/src/types/utils/validate-type.ts +35 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/number.ts +22 -0
- package/src/utils/utils.ts +350 -0
- package/test/index.test.ts +111 -0
- package/tsconfig.base.json +23 -0
- package/tsconfig.json +12 -0
- package/tsconfig.test.json +8 -0
- package/tsconfig.types.json +15 -0
- package/tsup.config.js +28 -0
- package/tsup.node.config.js +71 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* data-structure-typed
|
|
3
|
+
*
|
|
4
|
+
* @author Pablo Zeng
|
|
5
|
+
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
6
|
+
* @license MIT License
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { GraphOptions, VertexKey } from '../../types';
|
|
10
|
+
import { IGraph } from '../../interfaces';
|
|
11
|
+
import { AbstractEdge, AbstractGraph, AbstractVertex } from './abstract-graph';
|
|
12
|
+
import { arrayRemove } from '../../utils';
|
|
13
|
+
|
|
14
|
+
export class UndirectedVertex<V = any> extends AbstractVertex<V> {
|
|
15
|
+
constructor(key: VertexKey, value?: V) {
|
|
16
|
+
super(key, value);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class UndirectedEdge<E = number> extends AbstractEdge<E> {
|
|
21
|
+
endpoints: [VertexKey, VertexKey];
|
|
22
|
+
|
|
23
|
+
constructor(v1: VertexKey, v2: VertexKey, weight?: number, value?: E) {
|
|
24
|
+
super(weight, value);
|
|
25
|
+
this.endpoints = [v1, v2];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Undirected graph implementation.
|
|
31
|
+
* @template V - Vertex value type.
|
|
32
|
+
* @template E - Edge value type.
|
|
33
|
+
* @template VO - Concrete vertex class (extends AbstractVertex<V>).
|
|
34
|
+
* @template EO - Concrete edge class (extends AbstractEdge<E>).
|
|
35
|
+
* @remarks Time O(1), Space O(1)
|
|
36
|
+
* @example
|
|
37
|
+
* // basic UndirectedGraph vertex and edge creation
|
|
38
|
+
* // Create a simple undirected graph
|
|
39
|
+
* const graph = new UndirectedGraph<string>();
|
|
40
|
+
*
|
|
41
|
+
* // Add vertices
|
|
42
|
+
* graph.addVertex('A');
|
|
43
|
+
* graph.addVertex('B');
|
|
44
|
+
* graph.addVertex('C');
|
|
45
|
+
* graph.addVertex('D');
|
|
46
|
+
*
|
|
47
|
+
* // Verify vertices exist
|
|
48
|
+
* console.log(graph.hasVertex('A')); // true;
|
|
49
|
+
* console.log(graph.hasVertex('B')); // true;
|
|
50
|
+
* console.log(graph.hasVertex('E')); // false;
|
|
51
|
+
*
|
|
52
|
+
* // Check vertex count
|
|
53
|
+
* console.log(graph.size); // 4;
|
|
54
|
+
* @example
|
|
55
|
+
* // UndirectedGraph edge operations (bidirectional)
|
|
56
|
+
* const graph = new UndirectedGraph<string>();
|
|
57
|
+
*
|
|
58
|
+
* // Add vertices
|
|
59
|
+
* graph.addVertex('A');
|
|
60
|
+
* graph.addVertex('B');
|
|
61
|
+
* graph.addVertex('C');
|
|
62
|
+
*
|
|
63
|
+
* // Add undirected edges (both directions automatically)
|
|
64
|
+
* graph.addEdge('A', 'B', 1);
|
|
65
|
+
* graph.addEdge('B', 'C', 2);
|
|
66
|
+
* graph.addEdge('A', 'C', 3);
|
|
67
|
+
*
|
|
68
|
+
* // Verify edges exist in both directions
|
|
69
|
+
* console.log(graph.hasEdge('A', 'B')); // true;
|
|
70
|
+
* console.log(graph.hasEdge('B', 'A')); // true; // Bidirectional!
|
|
71
|
+
*
|
|
72
|
+
* console.log(graph.hasEdge('C', 'B')); // true;
|
|
73
|
+
* console.log(graph.hasEdge('B', 'C')); // true; // Bidirectional!
|
|
74
|
+
*
|
|
75
|
+
* // Get neighbors of A
|
|
76
|
+
* const neighborsA = graph.getNeighbors('A');
|
|
77
|
+
* console.log(neighborsA[0].key); // 'B';
|
|
78
|
+
* console.log(neighborsA[1].key); // 'C';
|
|
79
|
+
* @example
|
|
80
|
+
* // UndirectedGraph deleteEdge and vertex operations
|
|
81
|
+
* const graph = new UndirectedGraph<string>();
|
|
82
|
+
*
|
|
83
|
+
* // Build a simple undirected graph
|
|
84
|
+
* graph.addVertex('X');
|
|
85
|
+
* graph.addVertex('Y');
|
|
86
|
+
* graph.addVertex('Z');
|
|
87
|
+
* graph.addEdge('X', 'Y', 1);
|
|
88
|
+
* graph.addEdge('Y', 'Z', 2);
|
|
89
|
+
* graph.addEdge('X', 'Z', 3);
|
|
90
|
+
*
|
|
91
|
+
* // Delete an edge
|
|
92
|
+
* graph.deleteEdge('X', 'Y');
|
|
93
|
+
* console.log(graph.hasEdge('X', 'Y')); // false;
|
|
94
|
+
*
|
|
95
|
+
* // Bidirectional deletion confirmed
|
|
96
|
+
* console.log(graph.hasEdge('Y', 'X')); // false;
|
|
97
|
+
*
|
|
98
|
+
* // Other edges should remain
|
|
99
|
+
* console.log(graph.hasEdge('Y', 'Z')); // true;
|
|
100
|
+
* console.log(graph.hasEdge('Z', 'Y')); // true;
|
|
101
|
+
*
|
|
102
|
+
* // Delete a vertex
|
|
103
|
+
* graph.deleteVertex('Y');
|
|
104
|
+
* console.log(graph.hasVertex('Y')); // false;
|
|
105
|
+
* console.log(graph.size); // 2;
|
|
106
|
+
* @example
|
|
107
|
+
* // UndirectedGraph connectivity and neighbors
|
|
108
|
+
* const graph = new UndirectedGraph<string>();
|
|
109
|
+
*
|
|
110
|
+
* // Build a friendship network
|
|
111
|
+
* const people = ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'];
|
|
112
|
+
* for (const person of people) {
|
|
113
|
+
* graph.addVertex(person);
|
|
114
|
+
* }
|
|
115
|
+
*
|
|
116
|
+
* // Add friendships (undirected edges)
|
|
117
|
+
* graph.addEdge('Alice', 'Bob', 1);
|
|
118
|
+
* graph.addEdge('Alice', 'Charlie', 1);
|
|
119
|
+
* graph.addEdge('Bob', 'Diana', 1);
|
|
120
|
+
* graph.addEdge('Charlie', 'Eve', 1);
|
|
121
|
+
* graph.addEdge('Diana', 'Eve', 1);
|
|
122
|
+
*
|
|
123
|
+
* // Get friends of each person
|
|
124
|
+
* const aliceFriends = graph.getNeighbors('Alice');
|
|
125
|
+
* console.log(aliceFriends[0].key); // 'Bob';
|
|
126
|
+
* console.log(aliceFriends[1].key); // 'Charlie';
|
|
127
|
+
* console.log(aliceFriends.length); // 2;
|
|
128
|
+
*
|
|
129
|
+
* const dianaFriends = graph.getNeighbors('Diana');
|
|
130
|
+
* console.log(dianaFriends[0].key); // 'Bob';
|
|
131
|
+
* console.log(dianaFriends[1].key); // 'Eve';
|
|
132
|
+
* console.log(dianaFriends.length); // 2;
|
|
133
|
+
*
|
|
134
|
+
* // Verify bidirectional friendship
|
|
135
|
+
* const bobFriends = graph.getNeighbors('Bob');
|
|
136
|
+
* console.log(bobFriends[0].key); // 'Alice'; // Alice -> Bob -> Alice ✓
|
|
137
|
+
* console.log(bobFriends[1].key); // 'Diana';
|
|
138
|
+
* @example
|
|
139
|
+
* // UndirectedGraph for social network connectivity analysis
|
|
140
|
+
* interface Person {
|
|
141
|
+
* id: number;
|
|
142
|
+
* name: string;
|
|
143
|
+
* location: string;
|
|
144
|
+
* }
|
|
145
|
+
*
|
|
146
|
+
* // UndirectedGraph is perfect for modeling symmetric relationships
|
|
147
|
+
* // (friendships, collaborations, partnerships)
|
|
148
|
+
* const socialNetwork = new UndirectedGraph<number, Person>();
|
|
149
|
+
*
|
|
150
|
+
* // Add people as vertices
|
|
151
|
+
* const people: [number, Person][] = [
|
|
152
|
+
* [1, { id: 1, name: 'Alice', location: 'New York' }],
|
|
153
|
+
* [2, { id: 2, name: 'Bob', location: 'San Francisco' }],
|
|
154
|
+
* [3, { id: 3, name: 'Charlie', location: 'Boston' }],
|
|
155
|
+
* [4, { id: 4, name: 'Diana', location: 'New York' }],
|
|
156
|
+
* [5, { id: 5, name: 'Eve', location: 'Seattle' }]
|
|
157
|
+
* ];
|
|
158
|
+
*
|
|
159
|
+
* for (const [id] of people) {
|
|
160
|
+
* socialNetwork.addVertex(id);
|
|
161
|
+
* }
|
|
162
|
+
*
|
|
163
|
+
* // Add friendships (automatically bidirectional)
|
|
164
|
+
* socialNetwork.addEdge(1, 2, 1); // Alice <-> Bob
|
|
165
|
+
* socialNetwork.addEdge(1, 3, 1); // Alice <-> Charlie
|
|
166
|
+
* socialNetwork.addEdge(2, 4, 1); // Bob <-> Diana
|
|
167
|
+
* socialNetwork.addEdge(3, 5, 1); // Charlie <-> Eve
|
|
168
|
+
* socialNetwork.addEdge(4, 5, 1); // Diana <-> Eve
|
|
169
|
+
*
|
|
170
|
+
* console.log(socialNetwork.size); // 5;
|
|
171
|
+
*
|
|
172
|
+
* // Find direct connections for Alice
|
|
173
|
+
* const aliceConnections = socialNetwork.getNeighbors(1);
|
|
174
|
+
* console.log(aliceConnections[0].key); // 2;
|
|
175
|
+
* console.log(aliceConnections[1].key); // 3;
|
|
176
|
+
* console.log(aliceConnections.length); // 2;
|
|
177
|
+
*
|
|
178
|
+
* // Verify bidirectional connections
|
|
179
|
+
* console.log(socialNetwork.hasEdge(1, 2)); // true;
|
|
180
|
+
* console.log(socialNetwork.hasEdge(2, 1)); // true; // Friendship works both ways!
|
|
181
|
+
*
|
|
182
|
+
* // Remove a person from network
|
|
183
|
+
* socialNetwork.deleteVertex(2); // Bob leaves
|
|
184
|
+
* console.log(socialNetwork.hasVertex(2)); // false;
|
|
185
|
+
* console.log(socialNetwork.size); // 4;
|
|
186
|
+
*
|
|
187
|
+
* // Alice loses Bob as a friend
|
|
188
|
+
* const updatedAliceConnections = socialNetwork.getNeighbors(1);
|
|
189
|
+
* console.log(updatedAliceConnections[0].key); // 3;
|
|
190
|
+
* console.log(updatedAliceConnections[1]); // undefined;
|
|
191
|
+
*
|
|
192
|
+
* // Diana loses Bob as a friend
|
|
193
|
+
* const dianaConnections = socialNetwork.getNeighbors(4);
|
|
194
|
+
* console.log(dianaConnections[0].key); // 5;
|
|
195
|
+
* console.log(dianaConnections[1]); // undefined;
|
|
196
|
+
*/
|
|
197
|
+
export class UndirectedGraph<
|
|
198
|
+
V = any,
|
|
199
|
+
E = any,
|
|
200
|
+
VO extends UndirectedVertex<V> = UndirectedVertex<V>,
|
|
201
|
+
EO extends UndirectedEdge<E> = UndirectedEdge<E>
|
|
202
|
+
>
|
|
203
|
+
extends AbstractGraph<V, E, VO, EO>
|
|
204
|
+
implements IGraph<V, E, VO, EO>
|
|
205
|
+
{
|
|
206
|
+
/**
|
|
207
|
+
* Construct an undirected graph with runtime defaults.
|
|
208
|
+
* @param options - `GraphOptions<V>` (e.g. `vertexValueInitializer`, `defaultEdgeWeight`).
|
|
209
|
+
* @remarks Time O(1), Space O(1)
|
|
210
|
+
*/
|
|
211
|
+
constructor(options?: Partial<GraphOptions<V>>) {
|
|
212
|
+
super(options);
|
|
213
|
+
this._edgeMap = new Map<VO, EO[]>();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
protected _edgeMap: Map<VO, EO[]>;
|
|
217
|
+
|
|
218
|
+
get edgeMap(): Map<VO, EO[]> {
|
|
219
|
+
return this._edgeMap;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
set edgeMap(v: Map<VO, EO[]>) {
|
|
223
|
+
this._edgeMap = v;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Construct an undirected graph from keys with value initializer `v => v`.
|
|
228
|
+
* @template K - Vertex key type.
|
|
229
|
+
* @param keys - Iterable of vertex keys.
|
|
230
|
+
* @returns UndirectedGraph with all keys added.
|
|
231
|
+
* @remarks Time O(V), Space O(V)
|
|
232
|
+
*/
|
|
233
|
+
static fromKeys<K extends VertexKey>(
|
|
234
|
+
keys: Iterable<K>
|
|
235
|
+
): UndirectedGraph<K, any, UndirectedVertex<K>, UndirectedEdge<any>> {
|
|
236
|
+
const g: UndirectedGraph<K, any, UndirectedVertex<K>, UndirectedEdge<any>> = new UndirectedGraph<K, any>({
|
|
237
|
+
vertexValueInitializer: (k: VertexKey) => k as K
|
|
238
|
+
});
|
|
239
|
+
for (const k of keys) g.addVertex(k);
|
|
240
|
+
return g;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Construct an undirected graph from `[key, value]` entries.
|
|
245
|
+
* @template V - Vertex value type.
|
|
246
|
+
* @param entries - Iterable of `[key, value]` pairs.
|
|
247
|
+
* @returns UndirectedGraph with all vertices added.
|
|
248
|
+
* @remarks Time O(V), Space O(V)
|
|
249
|
+
*/
|
|
250
|
+
static fromEntries<V>(
|
|
251
|
+
entries: Iterable<[VertexKey, V]>
|
|
252
|
+
): UndirectedGraph<V, any, UndirectedVertex<V>, UndirectedEdge<any>> {
|
|
253
|
+
const g: UndirectedGraph<V, any, UndirectedVertex<V>, UndirectedEdge<any>> = new UndirectedGraph<V, any>();
|
|
254
|
+
for (const [k, v] of entries) g.addVertex(k, v);
|
|
255
|
+
return g;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Create an undirected vertex instance. Does not insert into the graph.
|
|
260
|
+
* @param key - Vertex identifier.
|
|
261
|
+
* @param value - Optional payload.
|
|
262
|
+
* @returns Concrete vertex instance.
|
|
263
|
+
* @remarks Time O(1), Space O(1)
|
|
264
|
+
*/
|
|
265
|
+
createVertex(key: VertexKey, value?: VO['value']): VO {
|
|
266
|
+
return new UndirectedVertex(key, value) as VO;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Create an undirected edge instance. Does not insert into the graph.
|
|
271
|
+
* @param v1 - One endpoint key.
|
|
272
|
+
* @param v2 - The other endpoint key.
|
|
273
|
+
* @param weight - Edge weight; defaults to `defaultEdgeWeight`.
|
|
274
|
+
* @param value - Edge payload.
|
|
275
|
+
* @returns Concrete edge instance.
|
|
276
|
+
* @remarks Time O(1), Space O(1)
|
|
277
|
+
*/
|
|
278
|
+
override createEdge(v1: VertexKey, v2: VertexKey, weight?: number, value?: EO['value']): EO {
|
|
279
|
+
return new UndirectedEdge(v1, v2, weight ?? this.options.defaultEdgeWeight ?? 1, value) as EO;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Get an undirected edge between two vertices, if present.
|
|
284
|
+
* @param v1 - One vertex or key.
|
|
285
|
+
* @param v2 - The other vertex or key.
|
|
286
|
+
* @returns Edge instance or `undefined`.
|
|
287
|
+
* @remarks Time O(1) avg, Space O(1)
|
|
288
|
+
*/
|
|
289
|
+
getEdge(v1: VO | VertexKey | undefined, v2: VO | VertexKey | undefined): EO | undefined {
|
|
290
|
+
let edgeMap: EO[] | undefined = [];
|
|
291
|
+
|
|
292
|
+
if (v1 !== undefined && v2 !== undefined) {
|
|
293
|
+
const vertex1: VO | undefined = this._getVertex(v1);
|
|
294
|
+
const vertex2: VO | undefined = this._getVertex(v2);
|
|
295
|
+
|
|
296
|
+
if (vertex1 && vertex2) {
|
|
297
|
+
edgeMap = this._edgeMap.get(vertex1)?.filter(e => e.endpoints.includes(vertex2.key));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return edgeMap ? edgeMap[0] || undefined : undefined;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Delete a single undirected edge between two vertices.
|
|
306
|
+
* @param v1 - One vertex or key.
|
|
307
|
+
* @param v2 - The other vertex or key.
|
|
308
|
+
* @returns Removed edge or `undefined`.
|
|
309
|
+
* @remarks Time O(1) avg, Space O(1)
|
|
310
|
+
*/
|
|
311
|
+
deleteEdgeBetween(v1: VO | VertexKey, v2: VO | VertexKey): EO | undefined {
|
|
312
|
+
const vertex1: VO | undefined = this._getVertex(v1);
|
|
313
|
+
const vertex2: VO | undefined = this._getVertex(v2);
|
|
314
|
+
|
|
315
|
+
if (!vertex1 || !vertex2) {
|
|
316
|
+
return undefined;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const v1Edges = this._edgeMap.get(vertex1);
|
|
320
|
+
let removed: EO | undefined = undefined;
|
|
321
|
+
if (v1Edges) {
|
|
322
|
+
removed = arrayRemove<EO>(v1Edges, (e: EO) => e.endpoints.includes(vertex2.key))[0] || undefined;
|
|
323
|
+
}
|
|
324
|
+
const v2Edges = this._edgeMap.get(vertex2);
|
|
325
|
+
if (v2Edges) {
|
|
326
|
+
arrayRemove<EO>(v2Edges, (e: EO) => e.endpoints.includes(vertex1.key));
|
|
327
|
+
}
|
|
328
|
+
return removed;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Delete an edge by instance or by a pair of keys.
|
|
333
|
+
* @param edgeOrOneSideVertexKey - Edge instance or one endpoint vertex/key.
|
|
334
|
+
* @param otherSideVertexKey - Required second endpoint when deleting by pair.
|
|
335
|
+
* @returns Removed edge or `undefined`.
|
|
336
|
+
* @remarks Time O(1) avg, Space O(1)
|
|
337
|
+
*/
|
|
338
|
+
deleteEdge(edgeOrOneSideVertexKey: EO | VertexKey, otherSideVertexKey?: VertexKey): EO | undefined {
|
|
339
|
+
let oneSide: VO | undefined, otherSide: VO | undefined;
|
|
340
|
+
if (this.isVertexKey(edgeOrOneSideVertexKey)) {
|
|
341
|
+
if (this.isVertexKey(otherSideVertexKey)) {
|
|
342
|
+
oneSide = this._getVertex(edgeOrOneSideVertexKey);
|
|
343
|
+
otherSide = this._getVertex(otherSideVertexKey);
|
|
344
|
+
} else {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
oneSide = this._getVertex(edgeOrOneSideVertexKey.endpoints[0]);
|
|
349
|
+
otherSide = this._getVertex(edgeOrOneSideVertexKey.endpoints[1]);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (oneSide && otherSide) {
|
|
353
|
+
return this.deleteEdgeBetween(oneSide, otherSide);
|
|
354
|
+
} else {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Delete a vertex and remove it from all neighbor lists.
|
|
361
|
+
* @param vertexOrKey - Vertex or key.
|
|
362
|
+
* @returns `true` if removed; otherwise `false`.
|
|
363
|
+
* @remarks Time O(deg), Space O(1)
|
|
364
|
+
*/
|
|
365
|
+
deleteVertex(vertexOrKey: VO | VertexKey): boolean {
|
|
366
|
+
let vertexKey: VertexKey;
|
|
367
|
+
let vertex: VO | undefined;
|
|
368
|
+
if (this.isVertexKey(vertexOrKey)) {
|
|
369
|
+
vertex = this.getVertex(vertexOrKey);
|
|
370
|
+
vertexKey = vertexOrKey;
|
|
371
|
+
} else {
|
|
372
|
+
vertex = vertexOrKey;
|
|
373
|
+
vertexKey = this._getVertexKey(vertexOrKey);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* All neighbors connected via undirected edges.
|
|
378
|
+
* @param vertexOrKey - Vertex or key.
|
|
379
|
+
* @returns Array of neighbor vertices.
|
|
380
|
+
* @remarks Time O(deg), Space O(deg)
|
|
381
|
+
*/
|
|
382
|
+
const neighbors = this.getNeighbors(vertexOrKey);
|
|
383
|
+
|
|
384
|
+
if (vertex) {
|
|
385
|
+
neighbors.forEach(neighbor => {
|
|
386
|
+
const neighborEdges = this._edgeMap.get(neighbor);
|
|
387
|
+
if (neighborEdges) {
|
|
388
|
+
const restEdges = neighborEdges.filter(edge => {
|
|
389
|
+
return !edge.endpoints.includes(vertexKey);
|
|
390
|
+
});
|
|
391
|
+
this._edgeMap.set(neighbor, restEdges);
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
this._edgeMap.delete(vertex);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return this._vertexMap.delete(vertexKey);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Degree of a vertex (# of incident undirected edges).
|
|
402
|
+
* @param vertexOrKey - Vertex or key.
|
|
403
|
+
* @returns Non-negative integer.
|
|
404
|
+
* @remarks Time O(1) avg, Space O(1)
|
|
405
|
+
*/
|
|
406
|
+
degreeOf(vertexOrKey: VertexKey | VO): number {
|
|
407
|
+
const vertex = this._getVertex(vertexOrKey);
|
|
408
|
+
if (vertex) {
|
|
409
|
+
return this._edgeMap.get(vertex)?.length || 0;
|
|
410
|
+
} else {
|
|
411
|
+
return 0;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Incident undirected edges of a vertex.
|
|
417
|
+
* @param vertexOrKey - Vertex or key.
|
|
418
|
+
* @returns Array of incident edges.
|
|
419
|
+
* @remarks Time O(deg), Space O(deg)
|
|
420
|
+
*/
|
|
421
|
+
edgesOf(vertexOrKey: VertexKey | VO): EO[] {
|
|
422
|
+
const vertex = this._getVertex(vertexOrKey);
|
|
423
|
+
if (vertex) {
|
|
424
|
+
return this._edgeMap.get(vertex) || [];
|
|
425
|
+
} else {
|
|
426
|
+
return [];
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Unique set of undirected edges across endpoints.
|
|
432
|
+
* @returns Array of edges.
|
|
433
|
+
* @remarks Time O(E), Space O(E)
|
|
434
|
+
*/
|
|
435
|
+
edgeSet(): EO[] {
|
|
436
|
+
const edgeSet: Set<EO> = new Set();
|
|
437
|
+
this._edgeMap.forEach(edgeMap => {
|
|
438
|
+
edgeMap.forEach(edge => {
|
|
439
|
+
edgeSet.add(edge);
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
return [...edgeSet];
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
getNeighbors(vertexOrKey: VO | VertexKey): VO[] {
|
|
446
|
+
const neighbors: VO[] = [];
|
|
447
|
+
const vertex = this._getVertex(vertexOrKey);
|
|
448
|
+
if (vertex) {
|
|
449
|
+
const neighborEdges = this.edgesOf(vertex);
|
|
450
|
+
for (const edge of neighborEdges) {
|
|
451
|
+
const neighbor = this._getVertex(edge.endpoints.filter(e => e !== vertex.key)[0]);
|
|
452
|
+
if (neighbor) {
|
|
453
|
+
neighbors.push(neighbor);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return neighbors;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Resolve an edge's two endpoints to vertex instances.
|
|
462
|
+
* @param edge - Edge instance.
|
|
463
|
+
* @returns `[v1, v2]` or `undefined` if either endpoint is missing.
|
|
464
|
+
* @remarks Time O(1), Space O(1)
|
|
465
|
+
*/
|
|
466
|
+
getEndsOfEdge(edge: EO): [VO, VO] | undefined {
|
|
467
|
+
if (!this.hasEdge(edge.endpoints[0], edge.endpoints[1])) {
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
470
|
+
const v1 = this._getVertex(edge.endpoints[0]);
|
|
471
|
+
const v2 = this._getVertex(edge.endpoints[1]);
|
|
472
|
+
if (v1 && v2) {
|
|
473
|
+
return [v1, v2];
|
|
474
|
+
} else {
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Whether the graph has no vertices and no edges.
|
|
481
|
+
* @remarks Time O(1), Space O(1)
|
|
482
|
+
*/
|
|
483
|
+
isEmpty(): boolean {
|
|
484
|
+
return this.vertexMap.size === 0 && this.edgeMap.size === 0;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Remove all vertices and edges.
|
|
489
|
+
* @remarks Time O(V + E), Space O(1)
|
|
490
|
+
*/
|
|
491
|
+
clear() {
|
|
492
|
+
this._vertexMap = new Map<VertexKey, VO>();
|
|
493
|
+
this._edgeMap = new Map<VO, EO[]>();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Deep clone as the same concrete class.
|
|
498
|
+
* @returns A new graph of the same concrete class (`this` type).
|
|
499
|
+
* @remarks Time O(V + E), Space O(V + E)
|
|
500
|
+
*/
|
|
501
|
+
override clone(): this {
|
|
502
|
+
return super.clone();
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Tarjan-based bridge and articulation point detection.
|
|
507
|
+
* @returns `{ dfnMap, lowMap, bridges, cutVertices }`.
|
|
508
|
+
* @remarks Time O(V + E), Space O(V + E)
|
|
509
|
+
*/
|
|
510
|
+
tarjan(): { dfnMap: Map<VO, number>; lowMap: Map<VO, number>; bridges: EO[]; cutVertices: VO[] } {
|
|
511
|
+
const dfnMap = new Map<VO, number>();
|
|
512
|
+
const lowMap = new Map<VO, number>();
|
|
513
|
+
const bridges: EO[] = [];
|
|
514
|
+
const cutVertices: VO[] = [];
|
|
515
|
+
|
|
516
|
+
let time = 0;
|
|
517
|
+
|
|
518
|
+
const dfs = (vertex: VO, parent: VO | undefined) => {
|
|
519
|
+
dfnMap.set(vertex, time);
|
|
520
|
+
lowMap.set(vertex, time);
|
|
521
|
+
time++;
|
|
522
|
+
|
|
523
|
+
const neighbors = this.getNeighbors(vertex);
|
|
524
|
+
let childCount = 0;
|
|
525
|
+
|
|
526
|
+
for (const neighbor of neighbors) {
|
|
527
|
+
if (!dfnMap.has(neighbor)) {
|
|
528
|
+
childCount++;
|
|
529
|
+
dfs(neighbor, vertex);
|
|
530
|
+
lowMap.set(vertex, Math.min(lowMap.get(vertex)!, lowMap.get(neighbor)!));
|
|
531
|
+
|
|
532
|
+
if (lowMap.get(neighbor)! > dfnMap.get(vertex)!) {
|
|
533
|
+
// Found a bridge
|
|
534
|
+
const edge = this.getEdge(vertex, neighbor);
|
|
535
|
+
if (edge) {
|
|
536
|
+
bridges.push(edge);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (parent !== undefined && lowMap.get(neighbor)! >= dfnMap.get(vertex)!) {
|
|
541
|
+
// Found an articulation point
|
|
542
|
+
cutVertices.push(vertex);
|
|
543
|
+
}
|
|
544
|
+
} else if (neighbor !== parent) {
|
|
545
|
+
lowMap.set(vertex, Math.min(lowMap.get(vertex)!, dfnMap.get(neighbor)!));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (parent === undefined && childCount > 1) {
|
|
550
|
+
// Special case for root in DFS tree
|
|
551
|
+
cutVertices.push(vertex);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
for (const vertex of this.vertexMap.values()) {
|
|
556
|
+
if (!dfnMap.has(vertex)) {
|
|
557
|
+
dfs(vertex, undefined);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return {
|
|
562
|
+
dfnMap,
|
|
563
|
+
lowMap,
|
|
564
|
+
bridges,
|
|
565
|
+
cutVertices
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Get bridges discovered by `tarjan()`.
|
|
571
|
+
* @returns Array of edges that are bridges.
|
|
572
|
+
* @remarks Time O(B), Space O(1)
|
|
573
|
+
*/
|
|
574
|
+
getBridges() {
|
|
575
|
+
return this.tarjan().bridges;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Get articulation points discovered by `tarjan()`.
|
|
580
|
+
* @returns Array of cut vertices.
|
|
581
|
+
* @remarks Time O(C), Space O(1)
|
|
582
|
+
*/
|
|
583
|
+
getCutVertices() {
|
|
584
|
+
return this.tarjan().cutVertices;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* DFN index map computed by `tarjan()`.
|
|
589
|
+
* @returns Map from vertex to DFN index.
|
|
590
|
+
* @remarks Time O(V), Space O(V)
|
|
591
|
+
*/
|
|
592
|
+
getDFNMap() {
|
|
593
|
+
return this.tarjan().dfnMap;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* LOW link map computed by `tarjan()`.
|
|
598
|
+
* @returns Map from vertex to LOW value.
|
|
599
|
+
* @remarks Time O(V), Space O(V)
|
|
600
|
+
*/
|
|
601
|
+
getLowMap() {
|
|
602
|
+
return this.tarjan().lowMap;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Internal hook to attach an undirected edge into adjacency maps.
|
|
607
|
+
* @param edge - Edge instance.
|
|
608
|
+
* @returns `true` if both endpoints exist; otherwise `false`.
|
|
609
|
+
* @remarks Time O(1) avg, Space O(1)
|
|
610
|
+
*/
|
|
611
|
+
protected _addEdge(edge: EO): boolean {
|
|
612
|
+
for (const end of edge.endpoints) {
|
|
613
|
+
const endVertex = this._getVertex(end);
|
|
614
|
+
if (endVertex === undefined) return false;
|
|
615
|
+
if (endVertex) {
|
|
616
|
+
const edgeMap = this._edgeMap.get(endVertex);
|
|
617
|
+
if (edgeMap) {
|
|
618
|
+
edgeMap.push(edge);
|
|
619
|
+
} else {
|
|
620
|
+
this._edgeMap.set(endVertex, [edge]);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
}
|