data-structure-typed 2.4.4 → 2.5.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/CHANGELOG.md +22 -1
- package/README.md +34 -1
- package/dist/cjs/index.cjs +10639 -2151
- package/dist/cjs-legacy/index.cjs +10694 -2195
- package/dist/esm/index.mjs +10639 -2150
- package/dist/esm-legacy/index.mjs +10694 -2194
- package/dist/types/common/error.d.ts +23 -0
- package/dist/types/common/index.d.ts +1 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +128 -51
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +210 -164
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +439 -78
- package/dist/types/data-structures/binary-tree/bst.d.ts +311 -28
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +217 -31
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +218 -152
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +1281 -5
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +1087 -201
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +858 -65
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +1133 -5
- package/dist/types/data-structures/graph/abstract-graph.d.ts +44 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +220 -47
- package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
- package/dist/types/data-structures/graph/undirected-graph.d.ts +218 -59
- package/dist/types/data-structures/hash/hash-map.d.ts +230 -77
- package/dist/types/data-structures/heap/heap.d.ts +287 -99
- package/dist/types/data-structures/heap/max-heap.d.ts +46 -0
- package/dist/types/data-structures/heap/min-heap.d.ts +59 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +286 -44
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +278 -65
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +415 -12
- package/dist/types/data-structures/matrix/matrix.d.ts +331 -0
- package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +57 -0
- package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +60 -0
- package/dist/types/data-structures/priority-queue/priority-queue.d.ts +60 -0
- package/dist/types/data-structures/queue/deque.d.ts +313 -66
- package/dist/types/data-structures/queue/queue.d.ts +211 -42
- package/dist/types/data-structures/stack/stack.d.ts +174 -32
- package/dist/types/data-structures/trie/trie.d.ts +213 -43
- package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
- package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
- package/dist/types/types/data-structures/queue/deque.d.ts +6 -0
- package/dist/umd/data-structure-typed.js +10725 -2221
- package/dist/umd/data-structure-typed.min.js +4 -2
- package/package.json +5 -4
- package/src/common/error.ts +60 -0
- package/src/common/index.ts +2 -0
- package/src/data-structures/base/iterable-element-base.ts +2 -2
- package/src/data-structures/binary-tree/avl-tree.ts +146 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +317 -247
- package/src/data-structures/binary-tree/binary-tree.ts +567 -121
- package/src/data-structures/binary-tree/bst.ts +370 -37
- package/src/data-structures/binary-tree/red-black-tree.ts +328 -96
- package/src/data-structures/binary-tree/segment-tree.ts +378 -248
- package/src/data-structures/binary-tree/tree-map.ts +1411 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +1218 -215
- package/src/data-structures/binary-tree/tree-multi-set.ts +959 -69
- package/src/data-structures/binary-tree/tree-set.ts +1257 -15
- package/src/data-structures/graph/abstract-graph.ts +106 -1
- package/src/data-structures/graph/directed-graph.ts +233 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +308 -59
- package/src/data-structures/hash/hash-map.ts +254 -79
- package/src/data-structures/heap/heap.ts +305 -102
- package/src/data-structures/heap/max-heap.ts +48 -3
- package/src/data-structures/heap/min-heap.ts +59 -0
- package/src/data-structures/linked-list/doubly-linked-list.ts +303 -44
- package/src/data-structures/linked-list/singly-linked-list.ts +293 -65
- package/src/data-structures/linked-list/skip-linked-list.ts +707 -90
- package/src/data-structures/matrix/matrix.ts +433 -22
- package/src/data-structures/priority-queue/max-priority-queue.ts +59 -3
- package/src/data-structures/priority-queue/min-priority-queue.ts +60 -0
- package/src/data-structures/priority-queue/priority-queue.ts +60 -0
- package/src/data-structures/queue/deque.ts +358 -68
- package/src/data-structures/queue/queue.ts +223 -42
- package/src/data-structures/stack/stack.ts +184 -32
- package/src/data-structures/trie/trie.ts +227 -44
- package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
- package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
- package/src/types/data-structures/queue/deque.ts +7 -0
- package/src/utils/utils.ts +4 -2
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { DijkstraResult, EntryCallback, GraphOptions, VertexKey } from '../../types';
|
|
10
10
|
import { uuidV4 } from '../../utils';
|
|
11
|
+
import { ERR } from '../../common';
|
|
11
12
|
import { IterableEntryBase } from '../base';
|
|
12
13
|
import { IGraph } from '../../interfaces';
|
|
13
14
|
import { Heap } from '../heap';
|
|
@@ -274,7 +275,7 @@ export abstract class AbstractGraph<
|
|
|
274
275
|
const newEdge = this.createEdge(srcOrEdge, dest, weight, value);
|
|
275
276
|
return this._addEdge(newEdge);
|
|
276
277
|
} else {
|
|
277
|
-
throw new
|
|
278
|
+
throw new TypeError(ERR.invalidArgument('dest must be a Vertex or vertex key when srcOrEdge is an Edge.', 'Graph'));
|
|
278
279
|
}
|
|
279
280
|
}
|
|
280
281
|
}
|
|
@@ -1078,4 +1079,108 @@ export abstract class AbstractGraph<
|
|
|
1078
1079
|
protected _getVertexKey(vertexOrKey: VO | VertexKey): VertexKey {
|
|
1079
1080
|
return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
|
|
1080
1081
|
}
|
|
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
|
+
}
|
|
1081
1186
|
}
|
|
@@ -77,53 +77,6 @@ export class DirectedEdge<E = any> extends AbstractEdge<E> {
|
|
|
77
77
|
* console.log(neighborsA[0].key); // 'B';
|
|
78
78
|
* console.log(neighborsA[1].key); // 'C';
|
|
79
79
|
* @example
|
|
80
|
-
* // DirectedGraph deleteEdge and vertex operations
|
|
81
|
-
* const graph = new DirectedGraph<string>();
|
|
82
|
-
*
|
|
83
|
-
* // Build a small 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
|
-
*
|
|
90
|
-
* // Delete an edge
|
|
91
|
-
* graph.deleteEdgeSrcToDest('X', 'Y');
|
|
92
|
-
* console.log(graph.hasEdge('X', 'Y')); // false;
|
|
93
|
-
*
|
|
94
|
-
* // Edge in other direction should not exist
|
|
95
|
-
* console.log(graph.hasEdge('Y', 'X')); // false;
|
|
96
|
-
*
|
|
97
|
-
* // Other edges should remain
|
|
98
|
-
* console.log(graph.hasEdge('Y', 'Z')); // true;
|
|
99
|
-
*
|
|
100
|
-
* // Delete a vertex
|
|
101
|
-
* graph.deleteVertex('Y');
|
|
102
|
-
* console.log(graph.hasVertex('Y')); // false;
|
|
103
|
-
* console.log(graph.size); // 2;
|
|
104
|
-
* @example
|
|
105
|
-
* // DirectedGraph topologicalSort for task scheduling
|
|
106
|
-
* const graph = new DirectedGraph<string>();
|
|
107
|
-
*
|
|
108
|
-
* // Build a DAG (Directed Acyclic Graph) for task dependencies
|
|
109
|
-
* graph.addVertex('Design');
|
|
110
|
-
* graph.addVertex('Implement');
|
|
111
|
-
* graph.addVertex('Test');
|
|
112
|
-
* graph.addVertex('Deploy');
|
|
113
|
-
*
|
|
114
|
-
* // Add dependency edges
|
|
115
|
-
* graph.addEdge('Design', 'Implement', 1); // Design must come before Implement
|
|
116
|
-
* graph.addEdge('Implement', 'Test', 1); // Implement must come before Test
|
|
117
|
-
* graph.addEdge('Test', 'Deploy', 1); // Test must come before Deploy
|
|
118
|
-
*
|
|
119
|
-
* // Topological sort gives valid execution order
|
|
120
|
-
* const executionOrder = graph.topologicalSort();
|
|
121
|
-
* console.log(executionOrder); // defined;
|
|
122
|
-
* console.log(executionOrder); // ['Design', 'Implement', 'Test', 'Deploy'];
|
|
123
|
-
*
|
|
124
|
-
* // All vertices should be included
|
|
125
|
-
* console.log(executionOrder?.length); // 4;
|
|
126
|
-
* @example
|
|
127
80
|
* // DirectedGraph dijkstra shortest path for network routing
|
|
128
81
|
* // Build a weighted directed graph representing network nodes and costs
|
|
129
82
|
* const network = new DirectedGraph<string>();
|
|
@@ -180,6 +133,10 @@ export class DirectedGraph<
|
|
|
180
133
|
super(options);
|
|
181
134
|
}
|
|
182
135
|
|
|
136
|
+
protected override get _edgeConnector(): string {
|
|
137
|
+
return '->';
|
|
138
|
+
}
|
|
139
|
+
|
|
183
140
|
protected _outEdgeMap: Map<VO, EO[]> = new Map<VO, EO[]>();
|
|
184
141
|
|
|
185
142
|
get outEdgeMap(): Map<VO, EO[]> {
|
|
@@ -260,6 +217,23 @@ export class DirectedGraph<
|
|
|
260
217
|
* @param destOrKey - Destination vertex or key.
|
|
261
218
|
* @returns Edge instance or `undefined`.
|
|
262
219
|
* @remarks Time O(1) avg, Space O(1)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
* @example
|
|
230
|
+
* // Get edge between vertices
|
|
231
|
+
* const g = new DirectedGraph();
|
|
232
|
+
* g.addVertex('A');
|
|
233
|
+
* g.addVertex('B');
|
|
234
|
+
* g.addEdge('A', 'B', 5);
|
|
235
|
+
* const edge = g.getEdge('A', 'B');
|
|
236
|
+
* console.log(edge?.weight); // 5;
|
|
263
237
|
*/
|
|
264
238
|
getEdge(srcOrKey: VO | VertexKey | undefined, destOrKey: VO | VertexKey | undefined): EO | undefined {
|
|
265
239
|
let edgeMap: EO[] = [];
|
|
@@ -312,6 +286,43 @@ export class DirectedGraph<
|
|
|
312
286
|
* @param destVertexKey - Optional destination vertex/key when deleting by pair.
|
|
313
287
|
* @returns Removed edge or `undefined`.
|
|
314
288
|
* @remarks Time O(1) avg, Space O(1)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
* @example
|
|
302
|
+
* // DirectedGraph deleteEdge and vertex operations
|
|
303
|
+
* const graph = new DirectedGraph<string>();
|
|
304
|
+
*
|
|
305
|
+
* // Build a small graph
|
|
306
|
+
* graph.addVertex('X');
|
|
307
|
+
* graph.addVertex('Y');
|
|
308
|
+
* graph.addVertex('Z');
|
|
309
|
+
* graph.addEdge('X', 'Y', 1);
|
|
310
|
+
* graph.addEdge('Y', 'Z', 2);
|
|
311
|
+
*
|
|
312
|
+
* // Delete an edge
|
|
313
|
+
* graph.deleteEdgeSrcToDest('X', 'Y');
|
|
314
|
+
* console.log(graph.hasEdge('X', 'Y')); // false;
|
|
315
|
+
*
|
|
316
|
+
* // Edge in other direction should not exist
|
|
317
|
+
* console.log(graph.hasEdge('Y', 'X')); // false;
|
|
318
|
+
*
|
|
319
|
+
* // Other edges should remain
|
|
320
|
+
* console.log(graph.hasEdge('Y', 'Z')); // true;
|
|
321
|
+
*
|
|
322
|
+
* // Delete a vertex
|
|
323
|
+
* graph.deleteVertex('Y');
|
|
324
|
+
* console.log(graph.hasVertex('Y')); // false;
|
|
325
|
+
* console.log(graph.size); // 2;
|
|
315
326
|
*/
|
|
316
327
|
deleteEdge(edgeOrSrcVertexKey: EO | VertexKey, destVertexKey?: VertexKey): EO | undefined {
|
|
317
328
|
let removed: EO | undefined = undefined;
|
|
@@ -343,6 +354,27 @@ export class DirectedGraph<
|
|
|
343
354
|
return removed;
|
|
344
355
|
}
|
|
345
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Remove a vertex
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
* @example
|
|
369
|
+
* // Remove a vertex
|
|
370
|
+
* const g = new DirectedGraph();
|
|
371
|
+
* g.addVertex('A');
|
|
372
|
+
* g.addVertex('B');
|
|
373
|
+
* g.addEdge('A', 'B');
|
|
374
|
+
* g.deleteVertex('A');
|
|
375
|
+
* console.log(g.hasVertex('A')); // false;
|
|
376
|
+
* console.log(g.hasEdge('A', 'B')); // false;
|
|
377
|
+
*/
|
|
346
378
|
deleteVertex(vertexOrKey: VO | VertexKey): boolean {
|
|
347
379
|
let vertexKey: VertexKey;
|
|
348
380
|
let vertex: VO | undefined;
|
|
@@ -391,6 +423,24 @@ export class DirectedGraph<
|
|
|
391
423
|
* @param vertexOrKey - Vertex or key.
|
|
392
424
|
* @returns Array of incoming edges.
|
|
393
425
|
* @remarks Time O(deg_in), Space O(deg_in)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
* @example
|
|
436
|
+
* // Get incoming edges
|
|
437
|
+
* const g = new DirectedGraph();
|
|
438
|
+
* g.addVertex('A');
|
|
439
|
+
* g.addVertex('B');
|
|
440
|
+
* g.addVertex('C');
|
|
441
|
+
* g.addEdge('A', 'C');
|
|
442
|
+
* g.addEdge('B', 'C');
|
|
443
|
+
* console.log(g.incomingEdgesOf('C').length); // 2;
|
|
394
444
|
*/
|
|
395
445
|
incomingEdgesOf(vertexOrKey: VO | VertexKey): EO[] {
|
|
396
446
|
const target = this._getVertex(vertexOrKey);
|
|
@@ -405,6 +455,24 @@ export class DirectedGraph<
|
|
|
405
455
|
* @param vertexOrKey - Vertex or key.
|
|
406
456
|
* @returns Array of outgoing edges.
|
|
407
457
|
* @remarks Time O(deg_out), Space O(deg_out)
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
* @example
|
|
468
|
+
* // Get outgoing edges
|
|
469
|
+
* const g = new DirectedGraph();
|
|
470
|
+
* g.addVertex('A');
|
|
471
|
+
* g.addVertex('B');
|
|
472
|
+
* g.addVertex('C');
|
|
473
|
+
* g.addEdge('A', 'B');
|
|
474
|
+
* g.addEdge('A', 'C');
|
|
475
|
+
* console.log(g.outgoingEdgesOf('A').length); // 2;
|
|
408
476
|
*/
|
|
409
477
|
outgoingEdgesOf(vertexOrKey: VO | VertexKey): EO[] {
|
|
410
478
|
const target = this._getVertex(vertexOrKey);
|
|
@@ -488,6 +556,40 @@ export class DirectedGraph<
|
|
|
488
556
|
* @param propertyName - `'key'` to map to keys; `'vertex'` to keep instances.
|
|
489
557
|
* @returns Array of keys/vertices, or `undefined` when cycle is found.
|
|
490
558
|
* @remarks Time O(V + E), Space O(V)
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
* @example
|
|
572
|
+
* // DirectedGraph topologicalSort for task scheduling
|
|
573
|
+
* const graph = new DirectedGraph<string>();
|
|
574
|
+
*
|
|
575
|
+
* // Build a DAG (Directed Acyclic Graph) for task dependencies
|
|
576
|
+
* graph.addVertex('Design');
|
|
577
|
+
* graph.addVertex('Implement');
|
|
578
|
+
* graph.addVertex('Test');
|
|
579
|
+
* graph.addVertex('Deploy');
|
|
580
|
+
*
|
|
581
|
+
* // Add dependency edges
|
|
582
|
+
* graph.addEdge('Design', 'Implement', 1); // Design must come before Implement
|
|
583
|
+
* graph.addEdge('Implement', 'Test', 1); // Implement must come before Test
|
|
584
|
+
* graph.addEdge('Test', 'Deploy', 1); // Test must come before Deploy
|
|
585
|
+
*
|
|
586
|
+
* // Topological sort gives valid execution order
|
|
587
|
+
* const executionOrder = graph.topologicalSort();
|
|
588
|
+
* console.log(executionOrder); // defined;
|
|
589
|
+
* console.log(executionOrder); // ['Design', 'Implement', 'Test', 'Deploy'];
|
|
590
|
+
*
|
|
591
|
+
* // All vertices should be included
|
|
592
|
+
* console.log(executionOrder?.length); // 4;
|
|
491
593
|
*/
|
|
492
594
|
topologicalSort(propertyName?: 'vertex' | 'key'): Array<VO | VertexKey> | undefined {
|
|
493
595
|
propertyName = propertyName ?? 'key';
|
|
@@ -526,6 +628,25 @@ export class DirectedGraph<
|
|
|
526
628
|
return sorted.reverse();
|
|
527
629
|
}
|
|
528
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Get all edges
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
* @example
|
|
643
|
+
* // Get all edges
|
|
644
|
+
* const g = new DirectedGraph();
|
|
645
|
+
* g.addVertex('A');
|
|
646
|
+
* g.addVertex('B');
|
|
647
|
+
* g.addEdge('A', 'B', 3);
|
|
648
|
+
* console.log(g.edgeSet().length); // 1;
|
|
649
|
+
*/
|
|
529
650
|
edgeSet(): EO[] {
|
|
530
651
|
let edgeMap: EO[] = [];
|
|
531
652
|
this._outEdgeMap.forEach(outEdges => {
|
|
@@ -534,6 +655,29 @@ export class DirectedGraph<
|
|
|
534
655
|
return edgeMap;
|
|
535
656
|
}
|
|
536
657
|
|
|
658
|
+
/**
|
|
659
|
+
* Get outgoing neighbors
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
* @example
|
|
671
|
+
* // Get outgoing neighbors
|
|
672
|
+
* const g = new DirectedGraph();
|
|
673
|
+
* g.addVertex('A');
|
|
674
|
+
* g.addVertex('B');
|
|
675
|
+
* g.addVertex('C');
|
|
676
|
+
* g.addEdge('A', 'B');
|
|
677
|
+
* g.addEdge('A', 'C');
|
|
678
|
+
* const neighbors = g.getNeighbors('A');
|
|
679
|
+
* console.log(neighbors.map(v => v.key).sort()); // ['B', 'C'];
|
|
680
|
+
*/
|
|
537
681
|
getNeighbors(vertexOrKey: VO | VertexKey): VO[] {
|
|
538
682
|
const neighbors: VO[] = [];
|
|
539
683
|
const vertex = this._getVertex(vertexOrKey);
|
|
@@ -600,6 +744,28 @@ export class DirectedGraph<
|
|
|
600
744
|
* Tarjan's algorithm for strongly connected components.
|
|
601
745
|
* @returns `{ dfnMap, lowMap, SCCs }`.
|
|
602
746
|
* @remarks Time O(V + E), Space O(V + E)
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
* @example
|
|
757
|
+
* // Find strongly connected components
|
|
758
|
+
* const g = new DirectedGraph();
|
|
759
|
+
* g.addVertex('A');
|
|
760
|
+
* g.addVertex('B');
|
|
761
|
+
* g.addVertex('C');
|
|
762
|
+
* g.addEdge('A', 'B');
|
|
763
|
+
* g.addEdge('B', 'C');
|
|
764
|
+
* g.addEdge('C', 'A');
|
|
765
|
+
* const { SCCs } = g.tarjan();
|
|
766
|
+
* // A→B→C→A forms one SCC with 3 members
|
|
767
|
+
* const sccArrays = [...SCCs.values()];
|
|
768
|
+
* console.log(sccArrays.some(scc => scc.length === 3)); // true;
|
|
603
769
|
*/
|
|
604
770
|
tarjan(): { dfnMap: Map<VO, number>; lowMap: Map<VO, number>; SCCs: Map<number, VO[]> } {
|
|
605
771
|
const dfnMap = new Map<VO, number>();
|
|
@@ -674,6 +840,26 @@ export class DirectedGraph<
|
|
|
674
840
|
* Strongly connected components computed by `tarjan()`.
|
|
675
841
|
* @returns Map from SCC id to vertices.
|
|
676
842
|
* @remarks Time O(#SCC + V), Space O(V)
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
|
|
852
|
+
* @example
|
|
853
|
+
* // Get strongly connected components
|
|
854
|
+
* const g = new DirectedGraph();
|
|
855
|
+
* g.addVertex(1);
|
|
856
|
+
* g.addVertex(2);
|
|
857
|
+
* g.addVertex(3);
|
|
858
|
+
* g.addEdge(1, 2);
|
|
859
|
+
* g.addEdge(2, 3);
|
|
860
|
+
* g.addEdge(3, 1);
|
|
861
|
+
* const sccs = g.getSCCs(); // Map<number, VO[]>
|
|
862
|
+
* console.log(sccs.size); // >= 1;
|
|
677
863
|
*/
|
|
678
864
|
getSCCs(): Map<number, VO[]> {
|
|
679
865
|
return this.tarjan().SCCs;
|
|
@@ -33,7 +33,65 @@ export class MapEdge<E = any> extends DirectedEdge<E> {
|
|
|
33
33
|
* @template VO - Concrete vertex class (MapVertex<V>).
|
|
34
34
|
* @template EO - Concrete edge class (MapEdge<E>).
|
|
35
35
|
* @remarks Time O(1), Space O(1)
|
|
36
|
-
* @example
|
|
36
|
+
* @example
|
|
37
|
+
* // City navigation with shortest path
|
|
38
|
+
* const map = new MapGraph([0, 0], [10, 10]);
|
|
39
|
+
*
|
|
40
|
+
* map.addVertex(new MapVertex('Home', '', 0, 0));
|
|
41
|
+
* map.addVertex(new MapVertex('Office', '', 3, 4));
|
|
42
|
+
* map.addVertex(new MapVertex('Cafe', '', 1, 2));
|
|
43
|
+
* map.addVertex(new MapVertex('Park', '', 2, 1));
|
|
44
|
+
*
|
|
45
|
+
* map.addEdge('Home', 'Cafe', 2.2);
|
|
46
|
+
* map.addEdge('Cafe', 'Office', 3.5);
|
|
47
|
+
* map.addEdge('Home', 'Park', 2.0);
|
|
48
|
+
* map.addEdge('Park', 'Office', 4.0);
|
|
49
|
+
* map.addEdge('Home', 'Office', 7.0);
|
|
50
|
+
*
|
|
51
|
+
* // Find shortest path
|
|
52
|
+
* const result = map.dijkstra('Home', 'Office', true, true);
|
|
53
|
+
* console.log(result?.minDist); // 5.7; // Home → Cafe → Office
|
|
54
|
+
* console.log(result?.minPath.map(v => v.key)); // ['Home', 'Cafe', 'Office'];
|
|
55
|
+
* @example
|
|
56
|
+
* // Delivery route optimization
|
|
57
|
+
* const routes = new MapGraph([0, 0], [10, 10]);
|
|
58
|
+
*
|
|
59
|
+
* routes.addVertex(new MapVertex('Warehouse', '', 0, 0));
|
|
60
|
+
* routes.addVertex(new MapVertex('Customer A', '', 2, 3));
|
|
61
|
+
* routes.addVertex(new MapVertex('Customer B', '', 5, 1));
|
|
62
|
+
* routes.addVertex(new MapVertex('Customer C', '', 3, 5));
|
|
63
|
+
*
|
|
64
|
+
* routes.addEdge('Warehouse', 'Customer A', 3.6);
|
|
65
|
+
* routes.addEdge('Warehouse', 'Customer B', 5.1);
|
|
66
|
+
* routes.addEdge('Customer A', 'Customer C', 2.2);
|
|
67
|
+
* routes.addEdge('Customer A', 'Customer B', 3.6);
|
|
68
|
+
* routes.addEdge('Customer B', 'Customer C', 4.5);
|
|
69
|
+
*
|
|
70
|
+
* // Check outgoing neighbors of Customer A
|
|
71
|
+
* const neighbors = routes.getNeighbors('Customer A');
|
|
72
|
+
* console.log(neighbors.map(n => n.key).sort()); // ['Customer B', 'Customer C'];
|
|
73
|
+
*
|
|
74
|
+
* // Shortest path from Warehouse to Customer C
|
|
75
|
+
* const path = routes.getMinPathBetween('Warehouse', 'Customer C', true);
|
|
76
|
+
* console.log(path?.map(v => v.key)); // ['Warehouse', 'Customer A', 'Customer C'];
|
|
77
|
+
* @example
|
|
78
|
+
* // Campus map with building connections
|
|
79
|
+
* const campus = new MapGraph([0, 0], [5, 5]);
|
|
80
|
+
*
|
|
81
|
+
* campus.addVertex(new MapVertex('Library', '', 0, 0));
|
|
82
|
+
* campus.addVertex(new MapVertex('Lab', '', 1, 1));
|
|
83
|
+
* campus.addVertex(new MapVertex('Cafeteria', '', 2, 0));
|
|
84
|
+
*
|
|
85
|
+
* campus.addEdge('Library', 'Lab', 5);
|
|
86
|
+
* campus.addEdge('Lab', 'Cafeteria', 3);
|
|
87
|
+
* campus.addEdge('Library', 'Cafeteria', 10);
|
|
88
|
+
*
|
|
89
|
+
* console.log(campus.hasVertex('Library')); // true;
|
|
90
|
+
* console.log(campus.hasVertex('Gym')); // false;
|
|
91
|
+
*
|
|
92
|
+
* // Direct distance vs shortest path
|
|
93
|
+
* const direct = campus.dijkstra('Library', 'Cafeteria', true, true);
|
|
94
|
+
* console.log(direct?.minDist); // 8;
|
|
37
95
|
*/
|
|
38
96
|
export class MapGraph<
|
|
39
97
|
V = any,
|