max-priority-queue-typed 2.4.3 → 2.4.5
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/dist/cjs/index.cjs +57 -39
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +56 -38
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +57 -40
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +56 -39
- 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/binary-tree.d.ts +15 -5
- package/dist/types/data-structures/binary-tree/bst.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +7 -1
- package/dist/types/data-structures/graph/abstract-graph.d.ts +44 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +3 -2
- package/dist/types/data-structures/graph/undirected-graph.d.ts +16 -2
- package/dist/types/data-structures/hash/hash-map.d.ts +2 -2
- package/dist/types/data-structures/heap/heap.d.ts +3 -7
- package/dist/types/data-structures/queue/deque.d.ts +41 -1
- package/dist/types/types/data-structures/binary-tree/avl-tree.d.ts +1 -1
- package/dist/types/types/data-structures/binary-tree/red-black-tree.d.ts +1 -1
- package/dist/types/types/data-structures/linked-list/doubly-linked-list.d.ts +1 -1
- package/dist/types/types/data-structures/linked-list/singly-linked-list.d.ts +1 -1
- package/dist/types/types/data-structures/priority-queue/priority-queue.d.ts +1 -1
- package/dist/types/types/data-structures/queue/deque.d.ts +6 -0
- package/dist/types/types/data-structures/stack/stack.d.ts +1 -1
- package/dist/umd/max-priority-queue-typed.js +54 -36
- package/dist/umd/max-priority-queue-typed.js.map +1 -1
- package/dist/umd/max-priority-queue-typed.min.js +1 -1
- package/dist/umd/max-priority-queue-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 +5 -4
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +6 -5
- package/src/data-structures/binary-tree/binary-tree.ts +121 -49
- package/src/data-structures/binary-tree/bst.ts +12 -4
- package/src/data-structures/binary-tree/red-black-tree.ts +20 -0
- package/src/data-structures/binary-tree/tree-map.ts +8 -7
- package/src/data-structures/binary-tree/tree-multi-map.ts +4 -4
- package/src/data-structures/binary-tree/tree-multi-set.ts +10 -9
- package/src/data-structures/binary-tree/tree-set.ts +7 -6
- package/src/data-structures/graph/abstract-graph.ts +124 -19
- package/src/data-structures/graph/directed-graph.ts +8 -4
- package/src/data-structures/graph/map-graph.ts +1 -1
- package/src/data-structures/graph/undirected-graph.ts +99 -4
- package/src/data-structures/hash/hash-map.ts +19 -6
- package/src/data-structures/heap/heap.ts +21 -17
- package/src/data-structures/heap/max-heap.ts +2 -3
- package/src/data-structures/linked-list/doubly-linked-list.ts +4 -4
- package/src/data-structures/linked-list/singly-linked-list.ts +15 -9
- package/src/data-structures/matrix/matrix.ts +9 -10
- package/src/data-structures/priority-queue/max-priority-queue.ts +2 -3
- package/src/data-structures/queue/deque.ts +72 -4
- package/src/data-structures/stack/stack.ts +1 -1
- package/src/data-structures/trie/trie.ts +12 -6
- package/src/types/data-structures/binary-tree/avl-tree.ts +1 -1
- package/src/types/data-structures/binary-tree/red-black-tree.ts +1 -1
- package/src/types/data-structures/linked-list/doubly-linked-list.ts +1 -1
- package/src/types/data-structures/linked-list/singly-linked-list.ts +1 -1
- package/src/types/data-structures/priority-queue/priority-queue.ts +1 -1
- package/src/types/data-structures/queue/deque.ts +7 -0
- package/src/types/data-structures/stack/stack.ts +1 -1
- 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';
|
|
@@ -65,7 +66,7 @@ export abstract class AbstractGraph<
|
|
|
65
66
|
*/
|
|
66
67
|
constructor(options?: Partial<Record<string, unknown>>) {
|
|
67
68
|
super();
|
|
68
|
-
const graph = (options as
|
|
69
|
+
const graph = (options as { graph?: GraphOptions<V> })?.graph;
|
|
69
70
|
this._options = { defaultEdgeWeight: 1, ...(graph ?? {}) };
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -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
|
}
|
|
@@ -984,11 +985,12 @@ export abstract class AbstractGraph<
|
|
|
984
985
|
* @remarks Time O(1), Space O(1)
|
|
985
986
|
*/
|
|
986
987
|
protected _createInstance(_options?: Partial<Record<string, unknown>>): this {
|
|
987
|
-
const Ctor
|
|
988
|
-
const instance
|
|
989
|
-
const graph = (_options as
|
|
990
|
-
|
|
991
|
-
|
|
988
|
+
const Ctor = this.constructor as new () => this;
|
|
989
|
+
const instance = new Ctor();
|
|
990
|
+
const graph = (_options as { graph?: GraphOptions<V> })?.graph;
|
|
991
|
+
// Use bracket notation for protected field access on dynamically created instance
|
|
992
|
+
if (graph) instance['_options'] = { ...instance['_options'], ...graph };
|
|
993
|
+
else instance['_options'] = { ...instance['_options'], ...this._options };
|
|
992
994
|
return instance;
|
|
993
995
|
}
|
|
994
996
|
|
|
@@ -1009,28 +1011,27 @@ export abstract class AbstractGraph<
|
|
|
1009
1011
|
// 1) Add vertices
|
|
1010
1012
|
if (iter) {
|
|
1011
1013
|
for (const [k, v] of iter) {
|
|
1012
|
-
|
|
1014
|
+
g.addVertex(k as VertexKey, v as V | undefined);
|
|
1013
1015
|
}
|
|
1014
1016
|
} else {
|
|
1015
1017
|
for (const [k, v] of this) {
|
|
1016
|
-
|
|
1018
|
+
g.addVertex(k as VertexKey, v as V | undefined);
|
|
1017
1019
|
}
|
|
1018
1020
|
}
|
|
1019
1021
|
// 2) Add edges whose endpoints exist in the new graph
|
|
1020
1022
|
const edges = this.edgeSet();
|
|
1021
|
-
for (const e of edges
|
|
1022
|
-
const ends = this.getEndsOfEdge(e
|
|
1023
|
+
for (const e of edges) {
|
|
1024
|
+
const ends = this.getEndsOfEdge(e);
|
|
1023
1025
|
if (!ends) continue;
|
|
1024
1026
|
const [va, vb] = ends;
|
|
1025
|
-
const ka =
|
|
1026
|
-
const kb =
|
|
1027
|
-
|
|
1028
|
-
const
|
|
1027
|
+
const ka = va.key;
|
|
1028
|
+
const kb = vb.key;
|
|
1029
|
+
// Defensive check for edge cases where hasVertex may be overridden/undefined
|
|
1030
|
+
const hasA = typeof g.hasVertex === 'function' ? g.hasVertex(ka) : false;
|
|
1031
|
+
const hasB = typeof g.hasVertex === 'function' ? g.hasVertex(kb) : false;
|
|
1029
1032
|
if (hasA && hasB) {
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
const newEdge = (g as any).createEdge(ka, kb, w, val);
|
|
1033
|
-
(g as any)._addEdge(newEdge);
|
|
1033
|
+
const newEdge = g.createEdge(ka, kb, e.weight, e.value);
|
|
1034
|
+
(g as this & { _addEdge(edge: EO): boolean })._addEdge(newEdge);
|
|
1034
1035
|
}
|
|
1035
1036
|
}
|
|
1036
1037
|
return g;
|
|
@@ -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
|
}
|
|
@@ -180,6 +180,10 @@ export class DirectedGraph<
|
|
|
180
180
|
super(options);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
protected override get _edgeConnector(): string {
|
|
184
|
+
return '->';
|
|
185
|
+
}
|
|
186
|
+
|
|
183
187
|
protected _outEdgeMap: Map<VO, EO[]> = new Map<VO, EO[]>();
|
|
184
188
|
|
|
185
189
|
get outEdgeMap(): Map<VO, EO[]> {
|
|
@@ -207,8 +211,8 @@ export class DirectedGraph<
|
|
|
207
211
|
* @returns DirectedGraph with all keys added.
|
|
208
212
|
* @remarks Time O(V), Space O(V)
|
|
209
213
|
*/
|
|
210
|
-
static fromKeys<K extends VertexKey>(keys: Iterable<K>): DirectedGraph<K,
|
|
211
|
-
const g: DirectedGraph<K,
|
|
214
|
+
static fromKeys<K extends VertexKey>(keys: Iterable<K>): DirectedGraph<K, undefined, DirectedVertex<K>, DirectedEdge<undefined>> {
|
|
215
|
+
const g: DirectedGraph<K, undefined, DirectedVertex<K>, DirectedEdge<undefined>> = new DirectedGraph<K, undefined>({
|
|
212
216
|
vertexValueInitializer: (k: VertexKey) => k as K
|
|
213
217
|
});
|
|
214
218
|
for (const k of keys) g.addVertex(k);
|
|
@@ -224,8 +228,8 @@ export class DirectedGraph<
|
|
|
224
228
|
*/
|
|
225
229
|
static fromEntries<V>(
|
|
226
230
|
entries: Iterable<[VertexKey, V]>
|
|
227
|
-
): DirectedGraph<V,
|
|
228
|
-
const g: DirectedGraph<V,
|
|
231
|
+
): DirectedGraph<V, undefined, DirectedVertex<V>, DirectedEdge<undefined>> {
|
|
232
|
+
const g: DirectedGraph<V, undefined, DirectedVertex<V>, DirectedEdge<undefined>> = new DirectedGraph<V, undefined>();
|
|
229
233
|
for (const [k, v] of entries) g.addVertex(k, v);
|
|
230
234
|
return g;
|
|
231
235
|
}
|
|
@@ -111,7 +111,7 @@ export class MapGraph<
|
|
|
111
111
|
* @remarks Time O(1), Space O(1)
|
|
112
112
|
*/
|
|
113
113
|
protected override _snapshotOptions(): Record<string, unknown> {
|
|
114
|
-
return { ...
|
|
114
|
+
return { ...super._snapshotOptions(), originCoord: this.originCoord, bottomRight: this.bottomRight };
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
/**
|
|
@@ -232,8 +232,8 @@ export class UndirectedGraph<
|
|
|
232
232
|
*/
|
|
233
233
|
static fromKeys<K extends VertexKey>(
|
|
234
234
|
keys: Iterable<K>
|
|
235
|
-
): UndirectedGraph<K,
|
|
236
|
-
const g: UndirectedGraph<K,
|
|
235
|
+
): UndirectedGraph<K, undefined, UndirectedVertex<K>, UndirectedEdge<undefined>> {
|
|
236
|
+
const g: UndirectedGraph<K, undefined, UndirectedVertex<K>, UndirectedEdge<undefined>> = new UndirectedGraph<K, undefined>({
|
|
237
237
|
vertexValueInitializer: (k: VertexKey) => k as K
|
|
238
238
|
});
|
|
239
239
|
for (const k of keys) g.addVertex(k);
|
|
@@ -249,8 +249,8 @@ export class UndirectedGraph<
|
|
|
249
249
|
*/
|
|
250
250
|
static fromEntries<V>(
|
|
251
251
|
entries: Iterable<[VertexKey, V]>
|
|
252
|
-
): UndirectedGraph<V,
|
|
253
|
-
const g: UndirectedGraph<V,
|
|
252
|
+
): UndirectedGraph<V, undefined, UndirectedVertex<V>, UndirectedEdge<undefined>> {
|
|
253
|
+
const g: UndirectedGraph<V, undefined, UndirectedVertex<V>, UndirectedEdge<undefined>> = new UndirectedGraph<V, undefined>();
|
|
254
254
|
for (const [k, v] of entries) g.addVertex(k, v);
|
|
255
255
|
return g;
|
|
256
256
|
}
|
|
@@ -566,6 +566,101 @@ export class UndirectedGraph<
|
|
|
566
566
|
};
|
|
567
567
|
}
|
|
568
568
|
|
|
569
|
+
/**
|
|
570
|
+
* Find biconnected components using edge-stack Tarjan variant.
|
|
571
|
+
* A biconnected component is a maximal biconnected subgraph.
|
|
572
|
+
* @returns Array of edge arrays, each representing a biconnected component.
|
|
573
|
+
* @remarks Time O(V + E), Space O(V + E)
|
|
574
|
+
*/
|
|
575
|
+
getBiconnectedComponents(): EO[][] {
|
|
576
|
+
const dfn = new Map<VO, number>();
|
|
577
|
+
const low = new Map<VO, number>();
|
|
578
|
+
const edgeStack: EO[] = [];
|
|
579
|
+
const components: EO[][] = [];
|
|
580
|
+
let time = 0;
|
|
581
|
+
|
|
582
|
+
const dfs = (vertex: VO, parent: VO | undefined) => {
|
|
583
|
+
dfn.set(vertex, time);
|
|
584
|
+
low.set(vertex, time);
|
|
585
|
+
time++;
|
|
586
|
+
|
|
587
|
+
const neighbors = this.getNeighbors(vertex);
|
|
588
|
+
let childCount = 0;
|
|
589
|
+
|
|
590
|
+
for (const neighbor of neighbors) {
|
|
591
|
+
const edge = this.getEdge(vertex, neighbor);
|
|
592
|
+
if (!edge) continue;
|
|
593
|
+
|
|
594
|
+
if (!dfn.has(neighbor)) {
|
|
595
|
+
childCount++;
|
|
596
|
+
edgeStack.push(edge);
|
|
597
|
+
dfs(neighbor, vertex);
|
|
598
|
+
low.set(vertex, Math.min(low.get(vertex)!, low.get(neighbor)!));
|
|
599
|
+
|
|
600
|
+
// Articulation point found — pop edges to form a component
|
|
601
|
+
if (
|
|
602
|
+
(parent === undefined && childCount > 1) ||
|
|
603
|
+
(parent !== undefined && low.get(neighbor)! >= dfn.get(vertex)!)
|
|
604
|
+
) {
|
|
605
|
+
const component: EO[] = [];
|
|
606
|
+
let e: EO | undefined;
|
|
607
|
+
do {
|
|
608
|
+
e = edgeStack.pop();
|
|
609
|
+
if (e) component.push(e);
|
|
610
|
+
} while (e && e !== edge);
|
|
611
|
+
if (component.length > 0) components.push(component);
|
|
612
|
+
}
|
|
613
|
+
} else if (neighbor !== parent && dfn.get(neighbor)! < dfn.get(vertex)!) {
|
|
614
|
+
// Back edge (only push once per undirected edge)
|
|
615
|
+
edgeStack.push(edge);
|
|
616
|
+
low.set(vertex, Math.min(low.get(vertex)!, dfn.get(neighbor)!));
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
for (const vertex of this.vertexMap.values()) {
|
|
622
|
+
if (!dfn.has(vertex)) {
|
|
623
|
+
dfs(vertex, undefined);
|
|
624
|
+
// Remaining edges form a component
|
|
625
|
+
if (edgeStack.length > 0) {
|
|
626
|
+
components.push([...edgeStack]);
|
|
627
|
+
edgeStack.length = 0;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return components;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Detect whether the graph contains a cycle.
|
|
637
|
+
* Uses DFS with parent tracking.
|
|
638
|
+
* @returns `true` if a cycle exists, `false` otherwise.
|
|
639
|
+
* @remarks Time O(V + E), Space O(V)
|
|
640
|
+
*/
|
|
641
|
+
hasCycle(): boolean {
|
|
642
|
+
const visited = new Set<VO>();
|
|
643
|
+
|
|
644
|
+
const dfs = (vertex: VO, parent: VO | undefined): boolean => {
|
|
645
|
+
visited.add(vertex);
|
|
646
|
+
for (const neighbor of this.getNeighbors(vertex)) {
|
|
647
|
+
if (!visited.has(neighbor)) {
|
|
648
|
+
if (dfs(neighbor, vertex)) return true;
|
|
649
|
+
} else if (neighbor !== parent) {
|
|
650
|
+
return true; // back edge = cycle
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return false;
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
for (const vertex of this.vertexMap.values()) {
|
|
657
|
+
if (!visited.has(vertex)) {
|
|
658
|
+
if (dfs(vertex, undefined)) return true;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
|
|
569
664
|
/**
|
|
570
665
|
* Get bridges discovered by `tarjan()`.
|
|
571
666
|
* @returns Array of edges that are bridges.
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
} from '../../types';
|
|
16
16
|
import { IterableEntryBase } from '../base';
|
|
17
17
|
import { isWeakKey, rangeCheck } from '../../utils';
|
|
18
|
+
import { ERR } from '../../common';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Hash-based map. Supports object keys and custom hashing; offers O(1) average set/get/has.
|
|
@@ -197,7 +198,7 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
197
198
|
return this._objMap;
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
protected _toEntryFn?: (rawElement: R) => [K, V];
|
|
201
|
+
protected readonly _toEntryFn?: (rawElement: R) => [K, V];
|
|
201
202
|
|
|
202
203
|
/**
|
|
203
204
|
* Get the raw→entry converter function if present.
|
|
@@ -530,14 +531,15 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
530
531
|
return this._tail;
|
|
531
532
|
}
|
|
532
533
|
|
|
533
|
-
protected _toEntryFn?: (rawElement: R) => [K, V] = (rawElement: R) => {
|
|
534
|
+
protected readonly _toEntryFn?: (rawElement: R) => [K, V] = (rawElement: R) => {
|
|
534
535
|
if (this.isEntry(rawElement)) {
|
|
535
536
|
return rawElement;
|
|
536
537
|
}
|
|
537
|
-
throw new
|
|
538
|
-
'If
|
|
538
|
+
throw new TypeError(
|
|
539
|
+
ERR.invalidArgument('If elements do not adhere to [key, value], provide options.toEntryFn to transform raw records.', 'HashMap')
|
|
539
540
|
);
|
|
540
541
|
};
|
|
542
|
+
|
|
541
543
|
get toEntryFn() {
|
|
542
544
|
return this._toEntryFn;
|
|
543
545
|
}
|
|
@@ -712,8 +714,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
712
714
|
const cur = node;
|
|
713
715
|
node = node.next;
|
|
714
716
|
if (predicate(cur.key as K, cur.value as V | undefined, i++, this)) {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
+
const keyToCheck: unknown = cur.key;
|
|
718
|
+
if (isWeakKey(keyToCheck)) {
|
|
719
|
+
this._objMap.delete(keyToCheck);
|
|
717
720
|
} else {
|
|
718
721
|
const hash = this._hashFn(cur.key as K);
|
|
719
722
|
delete this._noObjMap[hash];
|
|
@@ -795,6 +798,16 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
|
|
|
795
798
|
}
|
|
796
799
|
|
|
797
800
|
protected _deleteNode(node: HashMapLinkedNode<K, V | undefined>): boolean {
|
|
801
|
+
// Remove from hash table
|
|
802
|
+
const key: unknown = node.key;
|
|
803
|
+
if (isWeakKey(key)) {
|
|
804
|
+
this._objMap.delete(key);
|
|
805
|
+
} else {
|
|
806
|
+
const hash = this._hashFn(key as K);
|
|
807
|
+
delete this._noObjMap[hash];
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// Remove from linked list
|
|
798
811
|
const { prev, next } = node;
|
|
799
812
|
prev.next = next;
|
|
800
813
|
next.prev = prev;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Comparator, DFSOrderPattern, ElementCallback, HeapOptions } from '../../types';
|
|
10
10
|
import { IterableElementBase } from '../base';
|
|
11
|
+
import { ERR } from '../../common';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Binary heap with pluggable comparator; supports fast insertion and removal of the top element.
|
|
@@ -611,7 +612,7 @@ export class Heap<E = any, R = any> extends IterableElementBase<E, R> {
|
|
|
611
612
|
thisArg?: unknown
|
|
612
613
|
): Heap<EM, RM> {
|
|
613
614
|
const { comparator, toElementFn, ...rest } = options ?? {};
|
|
614
|
-
if (!comparator) throw new TypeError('Heap.map
|
|
615
|
+
if (!comparator) throw new TypeError(ERR.comparatorRequired('Heap.map'));
|
|
615
616
|
const out = this._createLike<EM, RM>([], { ...rest, comparator, toElementFn });
|
|
616
617
|
let i = 0;
|
|
617
618
|
for (const x of this) {
|
|
@@ -639,20 +640,17 @@ export class Heap<E = any, R = any> extends IterableElementBase<E, R> {
|
|
|
639
640
|
return out;
|
|
640
641
|
}
|
|
641
642
|
|
|
642
|
-
protected _DEFAULT_COMPARATOR = (a: E, b: E): number => {
|
|
643
|
+
protected readonly _DEFAULT_COMPARATOR: Comparator<E> = (a: E, b: E): number => {
|
|
643
644
|
if (typeof a === 'object' || typeof b === 'object') {
|
|
644
|
-
throw TypeError(
|
|
645
|
+
throw new TypeError(ERR.comparatorRequired('Heap'));
|
|
645
646
|
}
|
|
646
|
-
if (
|
|
647
|
-
if (
|
|
647
|
+
if (a > b) return 1;
|
|
648
|
+
if (a < b) return -1;
|
|
648
649
|
return 0;
|
|
649
650
|
};
|
|
650
651
|
|
|
651
|
-
protected _comparator: Comparator<E> = this._DEFAULT_COMPARATOR;
|
|
652
|
-
|
|
653
|
-
* @remarks Time O(1), Space O(1)
|
|
654
|
-
* @returns Comparator function.
|
|
655
|
-
*/
|
|
652
|
+
protected readonly _comparator: Comparator<E> = this._DEFAULT_COMPARATOR;
|
|
653
|
+
|
|
656
654
|
/**
|
|
657
655
|
* Get the comparator used to order elements.
|
|
658
656
|
* @remarks Time O(1), Space O(1)
|
|
@@ -706,9 +704,11 @@ export class Heap<E = any, R = any> extends IterableElementBase<E, R> {
|
|
|
706
704
|
*/
|
|
707
705
|
|
|
708
706
|
protected _createInstance(options?: HeapOptions<E, R>): this {
|
|
709
|
-
const Ctor
|
|
710
|
-
|
|
711
|
-
|
|
707
|
+
const Ctor = this.constructor as new (
|
|
708
|
+
elements?: Iterable<E> | Iterable<R>,
|
|
709
|
+
options?: HeapOptions<E, R>
|
|
710
|
+
) => this;
|
|
711
|
+
return new Ctor([], { comparator: this.comparator, toElementFn: this.toElementFn, ...(options ?? {}) });
|
|
712
712
|
}
|
|
713
713
|
|
|
714
714
|
/**
|
|
@@ -725,8 +725,11 @@ export class Heap<E = any, R = any> extends IterableElementBase<E, R> {
|
|
|
725
725
|
elements: Iterable<EM> | Iterable<RM> = [],
|
|
726
726
|
options?: HeapOptions<EM, RM>
|
|
727
727
|
): Heap<EM, RM> {
|
|
728
|
-
const Ctor
|
|
729
|
-
|
|
728
|
+
const Ctor = this.constructor as new (
|
|
729
|
+
elements?: Iterable<EM> | Iterable<RM>,
|
|
730
|
+
options?: HeapOptions<EM, RM>
|
|
731
|
+
) => Heap<EM, RM>;
|
|
732
|
+
return new Ctor(elements, options);
|
|
730
733
|
}
|
|
731
734
|
|
|
732
735
|
/**
|
|
@@ -781,7 +784,7 @@ export class FibonacciHeap<E> {
|
|
|
781
784
|
constructor(comparator?: Comparator<E>) {
|
|
782
785
|
this.clear();
|
|
783
786
|
this._comparator = comparator || this._defaultComparator;
|
|
784
|
-
if (typeof this.comparator !== 'function') throw new
|
|
787
|
+
if (typeof this.comparator !== 'function') throw new TypeError(ERR.notAFunction('comparator', 'FibonacciHeap'));
|
|
785
788
|
}
|
|
786
789
|
|
|
787
790
|
protected _root?: FibonacciHeapNode<E>;
|
|
@@ -813,7 +816,8 @@ export class FibonacciHeap<E> {
|
|
|
813
816
|
return this._min;
|
|
814
817
|
}
|
|
815
818
|
|
|
816
|
-
protected _comparator: Comparator<E>;
|
|
819
|
+
protected readonly _comparator: Comparator<E>;
|
|
820
|
+
|
|
817
821
|
get comparator(): Comparator<E> {
|
|
818
822
|
return this._comparator;
|
|
819
823
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { HeapOptions } from '../../types';
|
|
8
8
|
import { Heap } from './heap';
|
|
9
|
+
import { ERR } from '../../common';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @template E
|
|
@@ -33,9 +34,7 @@ export class MaxHeap<E = any, R = any> extends Heap<E, R> {
|
|
|
33
34
|
super(elements, {
|
|
34
35
|
comparator: (a: E, b: E): number => {
|
|
35
36
|
if (typeof a === 'object' || typeof b === 'object') {
|
|
36
|
-
throw TypeError(
|
|
37
|
-
`When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
|
|
38
|
-
);
|
|
37
|
+
throw new TypeError(ERR.comparatorRequired('MaxHeap'));
|
|
39
38
|
}
|
|
40
39
|
if (a < b) return 1;
|
|
41
40
|
if (a > b) return -1;
|
|
@@ -182,7 +182,7 @@ export class DoublyLinkedListNode<E = any> extends LinkedListNode<E> {
|
|
|
182
182
|
* console.log(foundEntry?.value); // 'Bob';
|
|
183
183
|
*/
|
|
184
184
|
export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, DoublyLinkedListNode<E>> {
|
|
185
|
-
protected _equals: (a: E, b: E) => boolean = Object.is
|
|
185
|
+
protected _equals: (a: E, b: E) => boolean = (a, b) => Object.is(a, b);
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
188
|
* Create a DoublyLinkedList and optionally bulk-insert elements.
|
|
@@ -423,8 +423,8 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
|
|
|
423
423
|
at(index: number): E | undefined {
|
|
424
424
|
if (index < 0 || index >= this._length) return undefined;
|
|
425
425
|
let current = this.head;
|
|
426
|
-
for (let i = 0; i < index; i++) current = current
|
|
427
|
-
return current
|
|
426
|
+
for (let i = 0; i < index && current; i++) current = current.next;
|
|
427
|
+
return current?.value;
|
|
428
428
|
}
|
|
429
429
|
|
|
430
430
|
/**
|
|
@@ -437,7 +437,7 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
|
|
|
437
437
|
getNodeAt(index: number): DoublyLinkedListNode<E> | undefined {
|
|
438
438
|
if (index < 0 || index >= this._length) return undefined;
|
|
439
439
|
let current = this.head;
|
|
440
|
-
for (let i = 0; i < index; i++) current = current
|
|
440
|
+
for (let i = 0; i < index && current; i++) current = current.next;
|
|
441
441
|
return current;
|
|
442
442
|
}
|
|
443
443
|
|
|
@@ -246,7 +246,7 @@ export class SinglyLinkedListNode<E = any> extends LinkedListNode<E> {
|
|
|
246
246
|
* console.log(editor.getText()); // 'Haello';
|
|
247
247
|
*/
|
|
248
248
|
export class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, SinglyLinkedListNode<E>> {
|
|
249
|
-
protected _equals: (a: E, b: E) => boolean = Object.is
|
|
249
|
+
protected _equals: (a: E, b: E) => boolean = (a, b) => Object.is(a, b);
|
|
250
250
|
|
|
251
251
|
/**
|
|
252
252
|
* Create a SinglyLinkedList and optionally bulk-insert elements.
|
|
@@ -381,8 +381,8 @@ export class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, S
|
|
|
381
381
|
return value;
|
|
382
382
|
}
|
|
383
383
|
let current = this.head;
|
|
384
|
-
while (current.next !== this.tail) current = current.next
|
|
385
|
-
const value = this.tail
|
|
384
|
+
while (current.next && current.next !== this.tail) current = current.next;
|
|
385
|
+
const value = this.tail?.value;
|
|
386
386
|
current.next = undefined;
|
|
387
387
|
this._tail = current;
|
|
388
388
|
this._length--;
|
|
@@ -484,8 +484,8 @@ export class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, S
|
|
|
484
484
|
at(index: number): E | undefined {
|
|
485
485
|
if (index < 0 || index >= this._length) return undefined;
|
|
486
486
|
let current = this.head;
|
|
487
|
-
for (let i = 0; i < index; i++) current = current
|
|
488
|
-
return current
|
|
487
|
+
for (let i = 0; i < index && current; i++) current = current.next;
|
|
488
|
+
return current?.value;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
491
|
/**
|
|
@@ -511,7 +511,7 @@ export class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, S
|
|
|
511
511
|
getNodeAt(index: number): SinglyLinkedListNode<E> | undefined {
|
|
512
512
|
if (index < 0 || index >= this._length) return undefined;
|
|
513
513
|
let current = this.head;
|
|
514
|
-
for (let i = 0; i < index; i++) current = current
|
|
514
|
+
for (let i = 0; i < index && current; i++) current = current.next;
|
|
515
515
|
return current;
|
|
516
516
|
}
|
|
517
517
|
|
|
@@ -1003,7 +1003,10 @@ export class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, S
|
|
|
1003
1003
|
*/
|
|
1004
1004
|
|
|
1005
1005
|
protected _createInstance(options?: SinglyLinkedListOptions<E, R>): this {
|
|
1006
|
-
const Ctor
|
|
1006
|
+
const Ctor = this.constructor as new (
|
|
1007
|
+
elements?: Iterable<E> | Iterable<R> | Iterable<SinglyLinkedListNode<E>>,
|
|
1008
|
+
options?: SinglyLinkedListOptions<E, R>
|
|
1009
|
+
) => this;
|
|
1007
1010
|
return new Ctor([], options);
|
|
1008
1011
|
}
|
|
1009
1012
|
|
|
@@ -1021,8 +1024,11 @@ export class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, S
|
|
|
1021
1024
|
elements: Iterable<EM> | Iterable<RM> | Iterable<SinglyLinkedListNode<EM>> = [],
|
|
1022
1025
|
options?: SinglyLinkedListOptions<EM, RM>
|
|
1023
1026
|
): SinglyLinkedList<EM, RM> {
|
|
1024
|
-
const Ctor
|
|
1025
|
-
|
|
1027
|
+
const Ctor = this.constructor as new (
|
|
1028
|
+
elements?: Iterable<EM> | Iterable<RM> | Iterable<SinglyLinkedListNode<EM>>,
|
|
1029
|
+
options?: SinglyLinkedListOptions<EM, RM>
|
|
1030
|
+
) => SinglyLinkedList<EM, RM>;
|
|
1031
|
+
return new Ctor(elements, options);
|
|
1026
1032
|
}
|
|
1027
1033
|
|
|
1028
1034
|
/**
|