//Link is like an Edge in the graph/tree structure class Link { constructor(src, dest) { this.to = dest; this.from = src; } import(data) { for(var i in data) { this[i] = data[i]; } return this; } export() { return this; } } //Node--> Vertex class Node { constructor(id){ this.id = id; } import(data) { for(var i in data) { this[i] = data[i]; } return this; } export() { return this; } } class Graph{ constructor(){ this.nodes = {}; this.links = {} } addNode(node){ if(this.nodes[node.id]){ throw new Error("Node already exists with ID "+node.id); } this.nodes[node.id] = node; if(!this.links[node.id]) this.links[node.id] = this._emptyLink(); } _emptyLink() { return { out: new Set(), in: new Set() }; } //we give the link we addLink(link){ let dest = link.from; let to = link.to; if(!this.nodes[dest] || !this.nodes[to]){ console.log(this.nodes, dest, to); throw new Error("One of the Nodes Doesnt Exist"); } if(this.links[dest].out.has(link) || this.links[to].in.has(link)){ throw new Error("Link already exists"); } this.links[dest].out.add(link); this.links[to].in.add(link); return link; } removeLink(link){ this.links[link.from].out.delete(link); this.links[link.to].in.delete(link); } removeNode(node){ if(!this.nodes[node.id]) return true; let outlinks = this.links[node.id].out let inlinks = this.links[node.id].in; outlinks.forEach(link => this.removeLink(link)) inlinks.forEach(link => this.removeLink(link)) delete this.nodes[node.id]; delete this.links[node.id]; return node; } linkNodes(src, dest) { return this.addLink(new Link(src, dest)); } has(id) { return !!this.nodes[id]; } getNode(id) { return this.nodes[id]; } getLinks(nodeid) { return this.links[nodeid]; } DFSRecursive(start, cb){ // needs correction because of link change to id if(!start) return null; var resultList = []; var visited = {}; var links = this.links; var found = false; let self = this; (function dfs(vertex){ visited[vertex.id] = true; resultList.push(vertex); if( cb(vertex) === true ) { found = true; return resultList; } for(var link of links[vertex.id].out) { let destNode = self.getNode(link.to); if(!visited[destNode]){ let res = dfs(destNode); if(found)return; resultList.pop(); } } })(start) return resultList; } //depth first DFS(start,cb){ // needs correction because of link change to id var visited = {}; visited[start.id] = true; var stack = [start]; var stackRes = [[]]; let vertex; while(stack.length){ vertex = stack.pop(); let res = stackRes.pop(); if( cb(vertex) === true ) { return [...res, vertex]; } for( var link of this.links[vertex.id].out ) { let destNode = link.to; if(!visited[destNode]){ visited[destNode] = true; stack.push(link.to); stackRes.push([...res, vertex]); } } // resultList.pop(); } return false; } BFS(start,cb){ // needs correction because of link change to id var visited = {[start.id]:true} var stack = [start]; var stackRes = [[]]; let vertex; while(stack.length){ vertex = stack.shift(); let res = stackRes.shift(); if( cb(vertex) === true ) { return [...res, vertex]; } for( var link of this.links[vertex.id].out ) { if(!visited[link.to]){ visited[link.to] = true; stack.push(link.to); stackRes.push([...res, vertex]); } } } return false; } export() { let { nodes, links } = this; // export Links care with SETS let ln = {}; for(let i in links) { ln[i] = { out: Array.from(links[i].out).map(link => link.export()), in : Array.from(links[i].in ).map(link => link.export()) } } // export nodes let nod = {}; for(let i in nodes) { nod[i] = nodes[i].export() } return { nodes: nod, links: ln }; } _loadLink(item) { if(!this.cacheSet) this.cacheSet = {}; let data = this.cacheSet["from" + item.from + "to" + item.to]; if(data) { return data; } else { return this.cacheSet["from" + item.from + "to" + item.to] = new Link().import(item); } } import(data, nodeType = Node) { let { nodes, links } = data; for (let i in nodes) { this.nodes[i] = new nodeType().import(nodes[i]); } for (let i in links) { this.links[i] = { out: new Set(links[i].out.map(item => this._loadLink(item))), in : new Set(links[i].in.map(item => this._loadLink(item))) } } } _debug(){ } } // var graph = new Graph(Node); // var A = new Node("A"); // var B = new Node('B'); // var C = new Node('C'); // var D = new Node('D'); // var E = new Node('E'); // var F = new Node("F"); // var AB = new Link(A,B); // var AD = new Link(A,D); // var BC = new Link(B,C); // var CF = new Link(C,F); // var DB = new Link(D,B); // var DE = new Link(D,E); // var EF = new Link(E,F); // var FE = new Link(F,E); /* graph.addNode(A); graph.addNode(B); graph.addNode(C); graph.addNode(D); graph.addNode(E); graph.addNode(F); graph.addLink(AB); graph.addLink(AD); graph.addLink(BC); graph.addLink(CF); graph.addLink(DB); graph.addLink(DE); graph.addLink(EF); graph.addLink(FE); */ //let recur = graph.DFS(A,(node) => node.id === E.id); //let bfs = graph.BFS(A,(node) => node.id === C.id); module.exports = { Node, Link, Graph };