binary-tree-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/README.md +0 -84
- package/dist/cjs/index.cjs +965 -420
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +962 -417
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +965 -421
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +962 -418
- package/dist/esm-legacy/index.mjs.map +1 -1
- 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/binary-tree-typed.js +959 -414
- package/dist/umd/binary-tree-typed.js.map +1 -1
- package/dist/umd/binary-tree-typed.min.js +3 -3
- package/dist/umd/binary-tree-typed.min.js.map +1 -1
- package/package.json +2 -2
- 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 +134 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +303 -247
- package/src/data-structures/binary-tree/binary-tree.ts +542 -121
- package/src/data-structures/binary-tree/bst.ts +346 -37
- package/src/data-structures/binary-tree/red-black-tree.ts +309 -96
- package/src/data-structures/binary-tree/segment-tree.ts +372 -248
- package/src/data-structures/binary-tree/tree-map.ts +1292 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +1098 -215
- package/src/data-structures/binary-tree/tree-multi-set.ts +863 -69
- package/src/data-structures/binary-tree/tree-set.ts +1143 -15
- package/src/data-structures/graph/abstract-graph.ts +106 -1
- package/src/data-structures/graph/directed-graph.ts +223 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +299 -59
- package/src/data-structures/hash/hash-map.ts +243 -79
- package/src/data-structures/heap/heap.ts +291 -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 +286 -44
- package/src/data-structures/linked-list/singly-linked-list.ts +278 -65
- package/src/data-structures/linked-list/skip-linked-list.ts +689 -90
- package/src/data-structures/matrix/matrix.ts +425 -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 +343 -68
- package/src/data-structures/queue/queue.ts +211 -42
- package/src/data-structures/stack/stack.ts +174 -32
- package/src/data-structures/trie/trie.ts +215 -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,22 @@ 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
|
+
* @example
|
|
229
|
+
* // Get edge between vertices
|
|
230
|
+
* const g = new DirectedGraph();
|
|
231
|
+
* g.addVertex('A');
|
|
232
|
+
* g.addVertex('B');
|
|
233
|
+
* g.addEdge('A', 'B', 5);
|
|
234
|
+
* const edge = g.getEdge('A', 'B');
|
|
235
|
+
* console.log(edge?.weight); // 5;
|
|
263
236
|
*/
|
|
264
237
|
getEdge(srcOrKey: VO | VertexKey | undefined, destOrKey: VO | VertexKey | undefined): EO | undefined {
|
|
265
238
|
let edgeMap: EO[] = [];
|
|
@@ -312,6 +285,42 @@ export class DirectedGraph<
|
|
|
312
285
|
* @param destVertexKey - Optional destination vertex/key when deleting by pair.
|
|
313
286
|
* @returns Removed edge or `undefined`.
|
|
314
287
|
* @remarks Time O(1) avg, Space O(1)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
* @example
|
|
300
|
+
* // DirectedGraph deleteEdge and vertex operations
|
|
301
|
+
* const graph = new DirectedGraph<string>();
|
|
302
|
+
*
|
|
303
|
+
* // Build a small graph
|
|
304
|
+
* graph.addVertex('X');
|
|
305
|
+
* graph.addVertex('Y');
|
|
306
|
+
* graph.addVertex('Z');
|
|
307
|
+
* graph.addEdge('X', 'Y', 1);
|
|
308
|
+
* graph.addEdge('Y', 'Z', 2);
|
|
309
|
+
*
|
|
310
|
+
* // Delete an edge
|
|
311
|
+
* graph.deleteEdgeSrcToDest('X', 'Y');
|
|
312
|
+
* console.log(graph.hasEdge('X', 'Y')); // false;
|
|
313
|
+
*
|
|
314
|
+
* // Edge in other direction should not exist
|
|
315
|
+
* console.log(graph.hasEdge('Y', 'X')); // false;
|
|
316
|
+
*
|
|
317
|
+
* // Other edges should remain
|
|
318
|
+
* console.log(graph.hasEdge('Y', 'Z')); // true;
|
|
319
|
+
*
|
|
320
|
+
* // Delete a vertex
|
|
321
|
+
* graph.deleteVertex('Y');
|
|
322
|
+
* console.log(graph.hasVertex('Y')); // false;
|
|
323
|
+
* console.log(graph.size); // 2;
|
|
315
324
|
*/
|
|
316
325
|
deleteEdge(edgeOrSrcVertexKey: EO | VertexKey, destVertexKey?: VertexKey): EO | undefined {
|
|
317
326
|
let removed: EO | undefined = undefined;
|
|
@@ -343,6 +352,26 @@ export class DirectedGraph<
|
|
|
343
352
|
return removed;
|
|
344
353
|
}
|
|
345
354
|
|
|
355
|
+
/**
|
|
356
|
+
* Remove a vertex
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
* @example
|
|
366
|
+
* // Remove a vertex
|
|
367
|
+
* const g = new DirectedGraph();
|
|
368
|
+
* g.addVertex('A');
|
|
369
|
+
* g.addVertex('B');
|
|
370
|
+
* g.addEdge('A', 'B');
|
|
371
|
+
* g.deleteVertex('A');
|
|
372
|
+
* console.log(g.hasVertex('A')); // false;
|
|
373
|
+
* console.log(g.hasEdge('A', 'B')); // false;
|
|
374
|
+
*/
|
|
346
375
|
deleteVertex(vertexOrKey: VO | VertexKey): boolean {
|
|
347
376
|
let vertexKey: VertexKey;
|
|
348
377
|
let vertex: VO | undefined;
|
|
@@ -391,6 +420,23 @@ export class DirectedGraph<
|
|
|
391
420
|
* @param vertexOrKey - Vertex or key.
|
|
392
421
|
* @returns Array of incoming edges.
|
|
393
422
|
* @remarks Time O(deg_in), Space O(deg_in)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
* @example
|
|
432
|
+
* // Get incoming edges
|
|
433
|
+
* const g = new DirectedGraph();
|
|
434
|
+
* g.addVertex('A');
|
|
435
|
+
* g.addVertex('B');
|
|
436
|
+
* g.addVertex('C');
|
|
437
|
+
* g.addEdge('A', 'C');
|
|
438
|
+
* g.addEdge('B', 'C');
|
|
439
|
+
* console.log(g.incomingEdgesOf('C').length); // 2;
|
|
394
440
|
*/
|
|
395
441
|
incomingEdgesOf(vertexOrKey: VO | VertexKey): EO[] {
|
|
396
442
|
const target = this._getVertex(vertexOrKey);
|
|
@@ -405,6 +451,23 @@ export class DirectedGraph<
|
|
|
405
451
|
* @param vertexOrKey - Vertex or key.
|
|
406
452
|
* @returns Array of outgoing edges.
|
|
407
453
|
* @remarks Time O(deg_out), Space O(deg_out)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
* @example
|
|
463
|
+
* // Get outgoing edges
|
|
464
|
+
* const g = new DirectedGraph();
|
|
465
|
+
* g.addVertex('A');
|
|
466
|
+
* g.addVertex('B');
|
|
467
|
+
* g.addVertex('C');
|
|
468
|
+
* g.addEdge('A', 'B');
|
|
469
|
+
* g.addEdge('A', 'C');
|
|
470
|
+
* console.log(g.outgoingEdgesOf('A').length); // 2;
|
|
408
471
|
*/
|
|
409
472
|
outgoingEdgesOf(vertexOrKey: VO | VertexKey): EO[] {
|
|
410
473
|
const target = this._getVertex(vertexOrKey);
|
|
@@ -488,6 +551,39 @@ export class DirectedGraph<
|
|
|
488
551
|
* @param propertyName - `'key'` to map to keys; `'vertex'` to keep instances.
|
|
489
552
|
* @returns Array of keys/vertices, or `undefined` when cycle is found.
|
|
490
553
|
* @remarks Time O(V + E), Space O(V)
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
* @example
|
|
566
|
+
* // DirectedGraph topologicalSort for task scheduling
|
|
567
|
+
* const graph = new DirectedGraph<string>();
|
|
568
|
+
*
|
|
569
|
+
* // Build a DAG (Directed Acyclic Graph) for task dependencies
|
|
570
|
+
* graph.addVertex('Design');
|
|
571
|
+
* graph.addVertex('Implement');
|
|
572
|
+
* graph.addVertex('Test');
|
|
573
|
+
* graph.addVertex('Deploy');
|
|
574
|
+
*
|
|
575
|
+
* // Add dependency edges
|
|
576
|
+
* graph.addEdge('Design', 'Implement', 1); // Design must come before Implement
|
|
577
|
+
* graph.addEdge('Implement', 'Test', 1); // Implement must come before Test
|
|
578
|
+
* graph.addEdge('Test', 'Deploy', 1); // Test must come before Deploy
|
|
579
|
+
*
|
|
580
|
+
* // Topological sort gives valid execution order
|
|
581
|
+
* const executionOrder = graph.topologicalSort();
|
|
582
|
+
* console.log(executionOrder); // defined;
|
|
583
|
+
* console.log(executionOrder); // ['Design', 'Implement', 'Test', 'Deploy'];
|
|
584
|
+
*
|
|
585
|
+
* // All vertices should be included
|
|
586
|
+
* console.log(executionOrder?.length); // 4;
|
|
491
587
|
*/
|
|
492
588
|
topologicalSort(propertyName?: 'vertex' | 'key'): Array<VO | VertexKey> | undefined {
|
|
493
589
|
propertyName = propertyName ?? 'key';
|
|
@@ -526,6 +622,24 @@ export class DirectedGraph<
|
|
|
526
622
|
return sorted.reverse();
|
|
527
623
|
}
|
|
528
624
|
|
|
625
|
+
/**
|
|
626
|
+
* Get all edges
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
* @example
|
|
636
|
+
* // Get all edges
|
|
637
|
+
* const g = new DirectedGraph();
|
|
638
|
+
* g.addVertex('A');
|
|
639
|
+
* g.addVertex('B');
|
|
640
|
+
* g.addEdge('A', 'B', 3);
|
|
641
|
+
* console.log(g.edgeSet().length); // 1;
|
|
642
|
+
*/
|
|
529
643
|
edgeSet(): EO[] {
|
|
530
644
|
let edgeMap: EO[] = [];
|
|
531
645
|
this._outEdgeMap.forEach(outEdges => {
|
|
@@ -534,6 +648,28 @@ export class DirectedGraph<
|
|
|
534
648
|
return edgeMap;
|
|
535
649
|
}
|
|
536
650
|
|
|
651
|
+
/**
|
|
652
|
+
* Get outgoing neighbors
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
* @example
|
|
663
|
+
* // Get outgoing neighbors
|
|
664
|
+
* const g = new DirectedGraph();
|
|
665
|
+
* g.addVertex('A');
|
|
666
|
+
* g.addVertex('B');
|
|
667
|
+
* g.addVertex('C');
|
|
668
|
+
* g.addEdge('A', 'B');
|
|
669
|
+
* g.addEdge('A', 'C');
|
|
670
|
+
* const neighbors = g.getNeighbors('A');
|
|
671
|
+
* console.log(neighbors.map(v => v.key).sort()); // ['B', 'C'];
|
|
672
|
+
*/
|
|
537
673
|
getNeighbors(vertexOrKey: VO | VertexKey): VO[] {
|
|
538
674
|
const neighbors: VO[] = [];
|
|
539
675
|
const vertex = this._getVertex(vertexOrKey);
|
|
@@ -600,6 +736,27 @@ export class DirectedGraph<
|
|
|
600
736
|
* Tarjan's algorithm for strongly connected components.
|
|
601
737
|
* @returns `{ dfnMap, lowMap, SCCs }`.
|
|
602
738
|
* @remarks Time O(V + E), Space O(V + E)
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
* @example
|
|
748
|
+
* // Find strongly connected components
|
|
749
|
+
* const g = new DirectedGraph();
|
|
750
|
+
* g.addVertex('A');
|
|
751
|
+
* g.addVertex('B');
|
|
752
|
+
* g.addVertex('C');
|
|
753
|
+
* g.addEdge('A', 'B');
|
|
754
|
+
* g.addEdge('B', 'C');
|
|
755
|
+
* g.addEdge('C', 'A');
|
|
756
|
+
* const { SCCs } = g.tarjan();
|
|
757
|
+
* // A→B→C→A forms one SCC with 3 members
|
|
758
|
+
* const sccArrays = [...SCCs.values()];
|
|
759
|
+
* console.log(sccArrays.some(scc => scc.length === 3)); // true;
|
|
603
760
|
*/
|
|
604
761
|
tarjan(): { dfnMap: Map<VO, number>; lowMap: Map<VO, number>; SCCs: Map<number, VO[]> } {
|
|
605
762
|
const dfnMap = new Map<VO, number>();
|
|
@@ -674,6 +831,25 @@ export class DirectedGraph<
|
|
|
674
831
|
* Strongly connected components computed by `tarjan()`.
|
|
675
832
|
* @returns Map from SCC id to vertices.
|
|
676
833
|
* @remarks Time O(#SCC + V), Space O(V)
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
* @example
|
|
843
|
+
* // Get strongly connected components
|
|
844
|
+
* const g = new DirectedGraph();
|
|
845
|
+
* g.addVertex(1);
|
|
846
|
+
* g.addVertex(2);
|
|
847
|
+
* g.addVertex(3);
|
|
848
|
+
* g.addEdge(1, 2);
|
|
849
|
+
* g.addEdge(2, 3);
|
|
850
|
+
* g.addEdge(3, 1);
|
|
851
|
+
* const sccs = g.getSCCs(); // Map<number, VO[]>
|
|
852
|
+
* console.log(sccs.size); // >= 1;
|
|
677
853
|
*/
|
|
678
854
|
getSCCs(): Map<number, VO[]> {
|
|
679
855
|
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,
|