UNPKG

@figliolia/data-structures

Version:

Efficient data structures for every day programming

153 lines (152 loc) 4.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeCache = exports.Graph = void 0; const LinkedList_1 = require("./LinkedList"); const Stack_1 = require("./Stack"); /** * Graph * * A generic graph construct for string and number values * * ```typescript * import { Graph, NodeCache } from "@figliolia/data-structures"; * * const cache = new NodeCache() * const root = cache.create(1); * const node2 = cache.create(2); * root.addEdge(node2); * root.addEdge(cache.create(4)); * node2.addEdge(cache.create(3)); * root.DFS(node => console.log(node.value)); // 1, 2, 3, 4 * root.BFS(node => console.log(node.value)); // 1, 2, 4, 3 * ``` */ class Graph { constructor(value) { this.edges = new Map(); this.value = value; } /** * Add Edge * * Adds a graph node to the current node's edges */ addEdge(edge) { this.edges.set(edge.value, edge); } /** * Connects To * * Returns true if the current node has an edge matching the input value. * This lookup occurs in O(1) */ connectsTo(edge) { return this.edges.has(edge); } /** * BFS * * Performs a breadth first search beginning with the current node. * Invokes the specified callback for each node visited */ BFS(callback) { const memo = new Set(); const queue = new LinkedList_1.LinkedList(); queue.push(this); while (queue.size) { const current = queue.shift(); if (!current) { continue; } callback(current); memo.add(current.value); for (const [value, neighbor] of current) { if (!memo.has(value)) { queue.push(neighbor); } } } memo.clear(); } /** * DFS * * Performs a depth first search beginning with the current node. * Invokes the specified callback for each node visited */ DFS(callback) { const memo = new Set(); const stack = new Stack_1.Stack(); stack.push(this); while (stack.length) { const current = stack.pop(); if (!current) { continue; } callback(current); memo.add(current.value); const tmp = new Stack_1.Stack(); for (const [value, neighbor] of current) { if (!memo.has(value)) { tmp.push(neighbor); } } while (tmp.length) { stack.push(tmp.pop()); } } memo.clear(); } *[Symbol.iterator]() { for (const [key, node] of this.edges) { yield [key, node]; } } } exports.Graph = Graph; /** * Node Cache * * A mechanism for storing all graph nodes in a flat structure. When using * the NodeCache along side Graph nodes, you can access nodes using their * value's in O(1) regardless of where in the graph a node is positioned * * ```typescript * import { NodeCache, Graph } from "@figliolia/data-structures"; * * const cache = new NodeCache(); * cache.create(1); * cache.reference(1)?.addEdge?.(cache.create(2)); * * // Cache = { 1 => Graph<1>, 2 => Graph<2> }; * // Graph<1> = { value: 1, edges: { 2 => Graph<2> } } * ``` */ class NodeCache { constructor() { this.storage = new Map(); } /** * Create * * Creates a graph node with the given value if it does not exist * in the cache. If a node with the provided value exists in the * cache, it is returned instead. */ create(value) { if (!this.storage.has(value)) { this.storage.set(value, new Graph(value)); } return this.storage.get(value); } /** * Reference * * Returns a cached reference to a node with the provided value or * undefined if it does not exist */ reference(value) { return this.storage.get(value); } } exports.NodeCache = NodeCache;