123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- //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
- };
|