UNPKG

deque-typed

Version:
333 lines (332 loc) 12.7 kB
/** * data-structure-typed * * @author Pablo Zeng * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com> * @license MIT License */ import type { GraphOptions, VertexKey } from '../../types'; import { AbstractEdge, AbstractGraph, AbstractVertex } from './abstract-graph'; import { IGraph } from '../../interfaces'; export declare class DirectedVertex<V = any> extends AbstractVertex<V> { constructor(key: VertexKey, value?: V); } export declare class DirectedEdge<E = any> extends AbstractEdge<E> { src: VertexKey; dest: VertexKey; constructor(src: VertexKey, dest: VertexKey, weight?: number, value?: E); } /** * Directed graph implementation. * @template V - Vertex value type. * @template E - Edge value type. * @template VO - Concrete vertex class (extends AbstractVertex<V>). * @template EO - Concrete edge class (extends AbstractEdge<E>). * @remarks Time O(1), Space O(1) * @example * // basic DirectedGraph vertex and edge creation * // Create a simple directed graph * const graph = new DirectedGraph<string>(); * * // Add vertices * graph.addVertex('A'); * graph.addVertex('B'); * graph.addVertex('C'); * * // Verify vertices exist * console.log(graph.hasVertex('A')); // true; * console.log(graph.hasVertex('B')); // true; * console.log(graph.hasVertex('C')); // true; * console.log(graph.hasVertex('D')); // false; * * // Check vertex count * console.log(graph.size); // 3; * @example * // DirectedGraph edge operations * const graph = new DirectedGraph<string>(); * * // Add vertices * graph.addVertex('A'); * graph.addVertex('B'); * graph.addVertex('C'); * * // Add directed edges * graph.addEdge('A', 'B', 1); * graph.addEdge('B', 'C', 2); * graph.addEdge('A', 'C', 3); * * // Verify edges exist * console.log(graph.hasEdge('A', 'B')); // true; * console.log(graph.hasEdge('B', 'C')); // true; * console.log(graph.hasEdge('C', 'B')); // false; // Graph is directed * * // Get neighbors of A * const neighborsA = graph.getNeighbors('A'); * console.log(neighborsA[0].key); // 'B'; * console.log(neighborsA[1].key); // 'C'; * @example * // DirectedGraph deleteEdge and vertex operations * const graph = new DirectedGraph<string>(); * * // Build a small graph * graph.addVertex('X'); * graph.addVertex('Y'); * graph.addVertex('Z'); * graph.addEdge('X', 'Y', 1); * graph.addEdge('Y', 'Z', 2); * * // Delete an edge * graph.deleteEdgeSrcToDest('X', 'Y'); * console.log(graph.hasEdge('X', 'Y')); // false; * * // Edge in other direction should not exist * console.log(graph.hasEdge('Y', 'X')); // false; * * // Other edges should remain * console.log(graph.hasEdge('Y', 'Z')); // true; * * // Delete a vertex * graph.deleteVertex('Y'); * console.log(graph.hasVertex('Y')); // false; * console.log(graph.size); // 2; * @example * // DirectedGraph topologicalSort for task scheduling * const graph = new DirectedGraph<string>(); * * // Build a DAG (Directed Acyclic Graph) for task dependencies * graph.addVertex('Design'); * graph.addVertex('Implement'); * graph.addVertex('Test'); * graph.addVertex('Deploy'); * * // Add dependency edges * graph.addEdge('Design', 'Implement', 1); // Design must come before Implement * graph.addEdge('Implement', 'Test', 1); // Implement must come before Test * graph.addEdge('Test', 'Deploy', 1); // Test must come before Deploy * * // Topological sort gives valid execution order * const executionOrder = graph.topologicalSort(); * console.log(executionOrder); // defined; * console.log(executionOrder); // ['Design', 'Implement', 'Test', 'Deploy']; * * // All vertices should be included * console.log(executionOrder?.length); // 4; * @example * // DirectedGraph dijkstra shortest path for network routing * // Build a weighted directed graph representing network nodes and costs * const network = new DirectedGraph<string>(); * * // Add network nodes * network.addVertex('Router-A'); * network.addVertex('Router-B'); * network.addVertex('Router-C'); * network.addVertex('Router-D'); * network.addVertex('Router-E'); * * // Add weighted edges (network latency costs) * network.addEdge('Router-A', 'Router-B', 5); * network.addEdge('Router-A', 'Router-C', 10); * network.addEdge('Router-B', 'Router-D', 3); * network.addEdge('Router-C', 'Router-D', 2); * network.addEdge('Router-D', 'Router-E', 4); * network.addEdge('Router-B', 'Router-E', 12); * * // Find shortest path from Router-A to Router-E * const { minDist, minPath } = network.dijkstra('Router-A', 'Router-E', true, true) || { * minDist: undefined, * minPath: undefined * }; * * // Verify shortest path is found * console.log(minDist); // defined; * console.log(minPath); // defined; * * // Shortest path should be A -> B -> D -> E with cost 5+3+4=12 * // Or A -> C -> D -> E with cost 10+2+4=16 * // So the minimum is 12 * console.log(minDist); // <= 16; * * // Verify path is valid (includes start and end) * console.log(minPath?.[0].key); // 'Router-A'; * console.log(minPath?.[minPath.length - 1].key); // 'Router-E'; */ export declare class DirectedGraph<V = any, E = any, VO extends DirectedVertex<V> = DirectedVertex<V>, EO extends DirectedEdge<E> = DirectedEdge<E>> extends AbstractGraph<V, E, VO, EO> implements IGraph<V, E, VO, EO> { /** * Construct a directed graph with runtime defaults. * @param options - `GraphOptions<V>` (e.g. `vertexValueInitializer`, `defaultEdgeWeight`). * @remarks Time O(1), Space O(1) */ constructor(options?: Partial<GraphOptions<V>>); protected _outEdgeMap: Map<VO, EO[]>; get outEdgeMap(): Map<VO, EO[]>; set outEdgeMap(v: Map<VO, EO[]>); protected _inEdgeMap: Map<VO, EO[]>; get inEdgeMap(): Map<VO, EO[]>; set inEdgeMap(v: Map<VO, EO[]>); /** * Construct a directed graph from keys with value initializer `v => v`. * @template K - Vertex key type. * @param keys - Iterable of vertex keys. * @returns DirectedGraph with all keys added. * @remarks Time O(V), Space O(V) */ static fromKeys<K extends VertexKey>(keys: Iterable<K>): DirectedGraph<K, any, DirectedVertex<K>, DirectedEdge<any>>; /** * Construct a directed graph from `[key, value]` entries. * @template V - Vertex value type. * @param entries - Iterable of `[key, value]` pairs. * @returns DirectedGraph with all vertices added. * @remarks Time O(V), Space O(V) */ static fromEntries<V>(entries: Iterable<[VertexKey, V]>): DirectedGraph<V, any, DirectedVertex<V>, DirectedEdge<any>>; /** * Create a directed vertex instance. Does not insert into the graph. * @param key - Vertex identifier. * @param value - Optional payload. * @returns Concrete vertex instance. * @remarks Time O(1), Space O(1) */ createVertex(key: VertexKey, value?: VO['value']): VO; /** * Create a directed edge instance. Does not insert into the graph. * @param src - Source vertex key. * @param dest - Destination vertex key. * @param weight - Edge weight; defaults to `defaultEdgeWeight`. * @param value - Edge payload. * @returns Concrete edge instance. * @remarks Time O(1), Space O(1) */ createEdge(src: VertexKey, dest: VertexKey, weight?: number, value?: E): EO; /** * Get the unique edge from `src` to `dest`, if present. * @param srcOrKey - Source vertex or key. * @param destOrKey - Destination vertex or key. * @returns Edge instance or `undefined`. * @remarks Time O(1) avg, Space O(1) */ getEdge(srcOrKey: VO | VertexKey | undefined, destOrKey: VO | VertexKey | undefined): EO | undefined; /** * Delete edge `src -> dest` if present. * @param srcOrKey - Source vertex or key. * @param destOrKey - Destination vertex or key. * @returns Removed edge or `undefined`. * @remarks Time O(1) avg, Space O(1) */ deleteEdgeSrcToDest(srcOrKey: VO | VertexKey, destOrKey: VO | VertexKey): EO | undefined; /** * Delete an edge by instance or by `(srcKey, destKey)`. * @param edgeOrSrcVertexKey - Edge instance or source vertex/key. * @param destVertexKey - Optional destination vertex/key when deleting by pair. * @returns Removed edge or `undefined`. * @remarks Time O(1) avg, Space O(1) */ deleteEdge(edgeOrSrcVertexKey: EO | VertexKey, destVertexKey?: VertexKey): EO | undefined; deleteVertex(vertexOrKey: VO | VertexKey): boolean; deleteEdgesBetween(v1: VertexKey | VO, v2: VertexKey | VO): EO[]; /** * Incoming edges of a vertex. * @param vertexOrKey - Vertex or key. * @returns Array of incoming edges. * @remarks Time O(deg_in), Space O(deg_in) */ incomingEdgesOf(vertexOrKey: VO | VertexKey): EO[]; /** * Outgoing edges of a vertex. * @param vertexOrKey - Vertex or key. * @returns Array of outgoing edges. * @remarks Time O(deg_out), Space O(deg_out) */ outgoingEdgesOf(vertexOrKey: VO | VertexKey): EO[]; /** * Degree (in + out) of a vertex. * @param vertexOrKey - Vertex or key. * @returns Non-negative integer. * @remarks Time O(1) avg, Space O(1) */ degreeOf(vertexOrKey: VertexKey | VO): number; inDegreeOf(vertexOrKey: VertexKey | VO): number; outDegreeOf(vertexOrKey: VertexKey | VO): number; /** * All incident edges of a vertex. * @param vertexOrKey - Vertex or key. * @returns Array of incident edges. * @remarks Time O(deg_in + deg_out), Space O(deg_in + deg_out) */ edgesOf(vertexOrKey: VertexKey | VO): EO[]; getEdgeSrc(e: EO): VO | undefined; getEdgeDest(e: EO): VO | undefined; /** * Direct children reachable by one outgoing edge. * @param vertex - Vertex or key. * @returns Array of neighbor vertices. * @remarks Time O(deg_out), Space O(deg_out) */ getDestinations(vertex: VO | VertexKey | undefined): VO[]; /** * Topological sort if DAG; returns `undefined` if a cycle exists. * @param propertyName - `'key'` to map to keys; `'vertex'` to keep instances. * @returns Array of keys/vertices, or `undefined` when cycle is found. * @remarks Time O(V + E), Space O(V) */ topologicalSort(propertyName?: 'vertex' | 'key'): Array<VO | VertexKey> | undefined; edgeSet(): EO[]; getNeighbors(vertexOrKey: VO | VertexKey): VO[]; /** * Resolve an edge's `[src, dest]` endpoints to vertex instances. * @param edge - Edge instance. * @returns `[src, dest]` or `undefined` if either endpoint is missing. * @remarks Time O(1), Space O(1) */ getEndsOfEdge(edge: EO): [VO, VO] | undefined; /** * Whether the graph has no vertices and no edges. * @remarks Time O(1), Space O(1) */ isEmpty(): boolean; /** * Remove all vertices and edges. * @remarks Time O(V + E), Space O(1) */ clear(): void; /** * Deep clone as the same concrete class. * @returns A new graph of the same concrete class (`this` type). * @remarks Time O(V + E), Space O(V + E) */ clone(): this; /** * Tarjan's algorithm for strongly connected components. * @returns `{ dfnMap, lowMap, SCCs }`. * @remarks Time O(V + E), Space O(V + E) */ tarjan(): { dfnMap: Map<VO, number>; lowMap: Map<VO, number>; SCCs: Map<number, VO[]>; }; /** * DFN index map computed by `tarjan()`. * @returns Map from vertex to DFN index. * @remarks Time O(V), Space O(V) */ getDFNMap(): Map<VO, number>; /** * LOW link map computed by `tarjan()`. * @returns Map from vertex to LOW value. * @remarks Time O(V), Space O(V) */ getLowMap(): Map<VO, number>; /** * Strongly connected components computed by `tarjan()`. * @returns Map from SCC id to vertices. * @remarks Time O(#SCC + V), Space O(V) */ getSCCs(): Map<number, VO[]>; /** * Internal hook to attach a directed edge into adjacency maps. * @param edge - Edge instance. * @returns `true` if inserted; otherwise `false`. * @remarks Time O(1) avg, Space O(1) */ protected _addEdge(edge: EO): boolean; }