Advertisement
ouija_bh

Notes on DFS orderings

Sep 20th, 2023
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 10.25 KB | Source Code | 0 0
  1. /* Data structures and methods for graph traversal. Includes a short demonstration
  2.  * showing different depth-first search orderings including pre-order and reverse
  3.  * post-order.
  4.  * Source: Open Data Structures by Pat Morin.
  5.  */
  6.  
  7. // vertex colors
  8. const white = 0, offwhite = 1, grey = 2, black = 3;
  9.  
  10. class Vertex {
  11.   /** constructor() credit: Morin 12.2, 12.3.2.
  12.    * @param {string} name vertex name
  13.    * @param {number} index index in adjacency lists
  14.    */
  15.   constructor(name, index) {
  16.     this.name = name;
  17.     this.index = index;
  18.     this.adjacent = [];  // indexes of adjacent vertices
  19.     this.color = white;
  20.   }
  21. }
  22.  
  23. /** Represents a graph. */
  24. class AdjacencyLists {
  25.   #namesSet;
  26.   /** constructor() Builds array of vertices with given names. credit: Morin 12.2.
  27.    * @param {string[]} names names of all vertices
  28.    */
  29.   constructor(names) {
  30.     this.vertices = [];  // array of Vertex's
  31.     this.#namesSet = new Set(names);
  32.  
  33.     names = Array.from(this.#namesSet);  // remove any duplicate names
  34.     for (var i = 0; i < names.length; i++) {
  35.       this.vertices.push(new Vertex(names[i], i));
  36.     }
  37.   }
  38.  
  39.   /** getIndexFromName() get vertex index from name
  40.    * @param {string} vertexName name of vertex to find
  41.    * @returns {number} index of vertex, or -1 if not found
  42.    */
  43.   getIndexFromName(vertexName) {
  44.     var vertex = this.vertices.find(function(a) { return a.name == vertexName; });
  45.     if (vertex == undefined) { return -1; }
  46.     return vertex.index;
  47.   }
  48.  
  49.   /** addEdgeByIndex() credit: Morin 12.2.
  50.    * @param {number} vertexIndex index of vertex to modify
  51.    * @param {number} edgeIndex index of edge to add
  52.    * @returns {boolean} success?
  53.    */
  54.   addEdgeByIndex(vertexIndex, edgeIndex) {
  55.     if ((vertexIndex < 0) || (edgeIndex < 0) ||
  56.         (vertexIndex >= this.vertices.length) || (edgeIndex >= this.vertices.length)) {
  57.       return false;
  58.     }
  59.     this.vertices[vertexIndex].adjacent.push(edgeIndex);
  60.     return true;
  61.   }
  62.  
  63.   /** addEdgeByName()
  64.    * @param {string} vertexName name of vertex to modify
  65.    * @param {string} edgeName name of edge to add
  66.    * @returns {boolean} success?
  67.    */
  68.   addEdgeByName(vertexName, edgeName) {
  69.     var vertexIndex = this.getIndexFromName(vertexName);
  70.     var edgeIndex = this.getIndexFromName(edgeName);
  71.     return this.addEdgeByIndex(vertexIndex, edgeIndex);
  72.   }
  73.  
  74.   /** outEdgesByIndex() credit: Morin 12.2.
  75.    * @param {number} vertexIndex index of vertex to search
  76.    * @returns {number[]} indexes of out edges, or undefined if no such vertex
  77.    */
  78.   outEdgesByIndex(vertexIndex) {
  79.     if ((vertexIndex < 0) || (vertexIndex >= this.vertices.length)) {
  80.       return undefined;
  81.     }
  82.     return this.vertices[vertexIndex].adjacent;
  83.   }
  84.  
  85.   /** outEdgesByName()
  86.    * @param {string} vertexName name of vertex to search
  87.    * @returns {string[]} names of out edges, or undefined if no such vertex
  88.    */
  89.   outEdgesByName(vertexName) {
  90.     var indexes = this.outEdgesByIndex(this.getIndexFromName(vertexName));
  91.     if (indexes == undefined) { return undefined; }
  92.     var names = [];
  93.     for (var i = 0; i < indexes.length; i++) {
  94.       names.push(this.vertices[indexes[i]].name);
  95.     }
  96.     return names;
  97.   }
  98.  
  99.   /** inEdgesByIndex() credit: Morin 12.2.
  100.    * @param {number} vertexIndex index of vertex to search
  101.    * @returns {number[]} indexes of in edges, or undefined if no such vertex
  102.    */
  103.   inEdgesByIndex(vertexIndex) {
  104.     if ((vertexIndex < 0) || (vertexIndex >= this.vertices.length)) {
  105.       return undefined;
  106.     }
  107.     var edgeIndexes = [];  // array of number's
  108.     for (var i = 0; i < this.vertices.length; i++) {
  109.       if (this.vertices[i].adjacent.findIndex(function(a) { return a == vertexIndex; }) != -1) {
  110.         edgeIndexes.push(i);
  111.       }
  112.     }
  113.     return edgeIndexes;
  114.   }
  115.  
  116.   /** inEdgesByName()
  117.    * @param {string} vertexName name of vertex to search
  118.    * @returns {string[]} names of in edges, or undefined if no such vertex
  119.    */
  120.   inEdgesByName(vertexName) {
  121.     var indexes = this.inEdgesByIndex(this.getIndexFromName(vertexName));
  122.     if (indexes == undefined) { return undefined; }
  123.     var names = [];
  124.     for (var i = 0; i < indexes.length; i++) {
  125.       names.push(this.vertices[indexes[i]].name);
  126.     }
  127.     return names;
  128.   }
  129.  
  130.   /** unvisited() makes all vertices undiscovered */
  131.   unvisited() {
  132.     for (var i = 0; i < this.vertices.length; i++) {
  133.       this.vertices[i].color = white;
  134.     }
  135.   }
  136.  
  137.   /** #dfsPrePostInner() Inner depth-first search. credit: Morin 12.3.2.
  138.    * @param {number} vertexIndex index of vertex to visit
  139.    * @param {boolean} flag if true, pre-order vertices, else reverse post-order
  140.    * @param {Vertex[]} if flag, pre-ordering of discovered vertices, else reverse post-ordering
  141.    */
  142.   #dfsPrePostInner(vertexIndex, flag, dfsVertices) {
  143.     var vertex = this.vertices[vertexIndex];
  144.     if (flag) { dfsVertices.push(vertex); }
  145.     vertex.color = grey;
  146.     var edgeIndexes = this.outEdgesByIndex(vertexIndex);
  147.     for (var i = 0; i < edgeIndexes.length; i++) {
  148.       var edge = this.vertices[edgeIndexes[i]];
  149.       if (edge.color == white) {
  150.         edge.color = grey;
  151.         this.#dfsPrePostInner(edgeIndexes[i], flag, dfsVertices);
  152.       }
  153.     }
  154.     if (!flag) { dfsVertices.unshift(vertex); }
  155.     vertex.color = black;
  156.   }
  157.  
  158.   /** dfsPrePost() Depth-first search. credit: Morin 12.3.2.
  159.    * @param {number} startIndex index of vertex to start at
  160.    * @param {boolean} flag if true, pre-order vertices, else reverse post-order
  161.    * @returns {Vertex[]} if flag, pre-ordering of discovered vertices, else reverse post-ordering
  162.    */
  163.   dfsPrePost(startIndex, flag) {
  164.     var dfsVertices = [];  // array of Vertex's
  165.  
  166.     this.#dfsPrePostInner(startIndex, flag, dfsVertices);
  167.     this.unvisited();
  168.     return dfsVertices;
  169.   }
  170.  
  171.   /** dfs2Pre() Depth-first search. credit: Morin 12.3.2.
  172.    * @param {number} startIndex index of vertex to start at
  173.    * @returns {Vertex[]} pre-ordering of discovered vertices
  174.    */
  175.   dfs2Pre(startIndex) {
  176.     var dfsVertices = [];  // array of Vertex's
  177.     var stack = [];   // stack of indexes into this.vertices
  178.  
  179.     var vertexIndex = startIndex;
  180.     var vertex = this.vertices[vertexIndex];
  181.     stack.push(vertexIndex);
  182.     while (stack.length > 0) {
  183.       vertexIndex = stack.pop();
  184.       vertex = this.vertices[vertexIndex];
  185.       if (vertex.color == white) {
  186.         vertex.color = grey;
  187.         dfsVertices.push(vertex);
  188.         var edgeIndexes = this.outEdgesByIndex(vertexIndex);
  189.         for (var i = 0; i < edgeIndexes.length; i++) {  // push edge index
  190.           stack.push(edgeIndexes[i]);
  191.         }
  192.       }
  193.     }
  194.     this.unvisited();
  195.     return dfsVertices;
  196.   }
  197.  
  198.   /** dfs2Post() Depth-first search.
  199.    * @param {number} startIndex index of vertex to start at
  200.    * @returns {Vertex[]} reverse post-ordering of discovered vertices
  201.    */
  202.   dfs2Post(startIndex) {
  203.     var dfsVertices = [];  // array of Vertex's
  204.     var stack = [];   // stack of indexes into this.vertices
  205.  
  206.     var vertexIndex = startIndex;
  207.     var vertex = this.vertices[vertexIndex];
  208.     stack.push(vertexIndex);
  209.     while (stack.length > 0) {
  210.         // peek at top of stack
  211.       vertexIndex = stack[stack.length - 1];
  212.       vertex = this.vertices[vertexIndex];
  213.       if (vertex.color == white || vertex.color == offwhite) {
  214.         vertex.color = grey;
  215.         var edgeIndexes = this.outEdgesByIndex(vertexIndex);
  216.         for (var i = 0; i < edgeIndexes.length; i++) {
  217.           var edge = this.vertices[edgeIndexes[i]];
  218.           if (edge.color == white) {  // push edge index
  219.             stack.push(edge.index);
  220.             edge.color = offwhite;
  221.           }
  222.         }
  223.       } else {  // vertex.color == grey
  224.         dfsVertices.unshift(vertex);
  225.         stack.pop();
  226.         vertex.color = black;
  227.       }
  228.     }
  229.     this.unvisited();
  230.     return dfsVertices;
  231.   }
  232. }
  233.  
  234. /** formatVertices()
  235.  * @param {Vertex[]} vertices vertices to format as list
  236.  * @returns {string} vertex names formatted as list
  237.  */
  238. function formatVertices(vertices) {
  239.   var names = "";
  240.   for (var i = 0; i < vertices.length; i++) {
  241.     names += vertices[i].name;
  242.     if (i < vertices.length - 1) { names += ", "; }
  243.   }
  244.   return "\n " + names;
  245. }
  246.  
  247.  
  248. /** names of all vertices */
  249. var vertexNames = ["adams", "boston", "chicago", "denver", "easy", "frank", "george", "henry"];
  250. // create vertices
  251. var graph = new AdjacencyLists(vertexNames);
  252. /** edges in the form [vertex][array of edge names]. */
  253. var edges = [ ["boston"],
  254.               ["chicago", "easy", "denver"],
  255.               ["frank"],
  256.               ["george"],
  257.               ["frank", "george"],
  258.               [],
  259.               [],
  260.               [] ];
  261. // add edges
  262. for (var i = 0; i < edges.length; i++) {
  263.   for (var j = 0; j < edges[i].length; j++) {
  264.     graph.addEdgeByName(vertexNames[i], edges[i][j]);
  265.   }
  266. }
  267. // dfs pre-ordering
  268. var vertices = graph.dfsPrePost(0, true);
  269. console.log("dfs pre-ordering" + formatVertices(vertices));
  270. // dfs reverse post-ordering
  271. vertices = graph.dfsPrePost(0, false);
  272. console.log("dfs reverse post-ordering" + formatVertices(vertices));
  273. // dfs #2 pre-ordering
  274. vertices = graph.dfs2Pre(0);
  275. console.log("dfs #2 pre-ordering" + formatVertices(vertices));
  276. // dfs #2 reverse post-ordering
  277. vertices = graph.dfs2Post(0);
  278. console.log("dfs #2 reverse post-ordering" + formatVertices(vertices));
  279. // add two edges
  280. graph.addEdgeByIndex(graph.getIndexFromName("george"), graph.getIndexFromName("henry"));
  281. console.log("--added edge from george to henry--");
  282. graph.addEdgeByName("henry", "denver");
  283. console.log("--added edge from henry to denver--");
  284. // edges
  285. console.log("vertex george out edges: " + graph.outEdgesByName("george"));
  286. console.log("vertex denver in edges: " + graph.inEdgesByName("denver"));
  287. // dfs pre-ordering
  288. vertices = graph.dfsPrePost(0, true);
  289. console.log("dfs pre-ordering" + formatVertices(vertices));
  290. // dfs reverse post-ordering
  291. vertices = graph.dfsPrePost(0, false);
  292. console.log("dfs reverse post-ordering" + formatVertices(vertices));
  293. // dfs #2 pre-ordering
  294. vertices = graph.dfs2Pre(0);
  295. console.log("dfs #2 pre-ordering" + formatVertices(vertices));
  296. // dfs #2 reverse post-ordering
  297. vertices = graph.dfs2Post(0);
  298. console.log("dfs #2 reverse post-ordering" + formatVertices(vertices));
  299.  
  300. /** @version 1.0 */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement