Lutz Roeder 4 лет назад
Родитель
Сommit
b07d87ea1e
1 измененных файлов с 65 добавлено и 91 удалено
  1. 65 91
      source/dagre.js

+ 65 - 91
source/dagre.js

@@ -145,46 +145,6 @@ dagre.layout = (graph, options) => {
             }
         };
 
-        // A helper that preforms a pre- or post-order traversal on the input graph and returns the nodes in the order they were visited.
-        // If the graph is undirected then this algorithm will navigate using neighbors.
-        // If the graph is directed then this algorithm will navigate using successors.
-        // Order must be one of 'pre' or 'post'.
-        const dfs = (g, vs, postorder) => {
-            const doDfs = (g, v, postorder, visited, navigation, acc) => {
-                if (!visited.has(v)) {
-                    visited.add(v);
-                    if (!postorder) {
-                        acc.push(v);
-                    }
-                    for (const w of navigation(v)) {
-                        doDfs(g, w, postorder, visited, navigation, acc);
-                    }
-                    if (postorder) {
-                        acc.push(v);
-                    }
-                }
-            };
-            if (!Array.isArray(vs)) {
-                vs = [ vs ];
-            }
-            const navigation = (g.isDirected() ? g.successors : g.neighbors).bind(g);
-            const acc = [];
-            const visited = new Set();
-            for (const v of vs) {
-                if (!g.hasNode(v)) {
-                    throw new Error('Graph does not have node: ' + v);
-                }
-                doDfs(g, v, postorder, visited, navigation, acc);
-            }
-            return acc;
-        };
-        const postorder = (g, vs) => {
-            return dfs(g, vs, true);
-        };
-        const preorder = (g, vs) => {
-            return dfs(g, vs, false);
-        };
-
         const removeSelfEdges = (g) => {
             for (const e of g.edges.values()) {
                 if (e.v === e.w) {
@@ -199,31 +159,28 @@ dagre.layout = (graph, options) => {
         };
 
         const acyclic_run = (g) => {
-            const dfsFAS = (g) => {
-                const fas = [];
-                const stack = new Set();
-                const visited = new Set();
-                const dfs = (v) => {
-                    if (!visited.has(v)) {
-                        visited.add(v);
-                        stack.add(v);
-                        for (const e of g.node(v).out) {
-                            if (stack.has(e.w)) {
-                                fas.push(e);
-                            }
-                            else {
-                                dfs(e.w);
-                            }
+            const fas = [];
+            const stack = new Set();
+            const visited = new Set();
+            const dfs = (v) => {
+                if (!visited.has(v)) {
+                    visited.add(v);
+                    stack.add(v);
+                    for (const e of g.node(v).out) {
+                        if (stack.has(e.w)) {
+                            fas.push(e);
+                        }
+                        else {
+                            dfs(e.w);
                         }
-                        stack.delete(v);
                     }
-                };
-                for (const v of g.nodes.keys()) {
-                    dfs(v);
+                    stack.delete(v);
                 }
-                return fas;
             };
-            for (const e of dfsFAS(g)) {
+            for (const v of g.nodes.keys()) {
+                dfs(v);
+            }
+            for (const e of fas) {
                 const label = e.label;
                 g.removeEdge(e);
                 label.forwardName = e.name;
@@ -455,8 +412,7 @@ dagre.layout = (graph, options) => {
                             const other = isOutEdge ? e.w : e.v;
                             if (other !== parent) {
                                 const pointsToHead = isOutEdge === childIsTail;
-                                const otherWeight = e.label.weight;
-                                cutValue += pointsToHead ? otherWeight : -otherWeight;
+                                cutValue += pointsToHead ? e.label.weight : -e.label.weight;
                                 const edge = t.edge(child, other);
                                 if (edge) {
                                     const otherCutValue = edge.label.cutvalue;
@@ -466,15 +422,28 @@ dagre.layout = (graph, options) => {
                         }
                         return cutValue;
                     };
-                    const assignCutValue = (t, g, child) => {
-                        const childLabel = t.node(child).label;
-                        const parent = childLabel.parent;
-                        t.edge(child, parent).label.cutvalue = calcCutValue(t, g, child);
+                    const postorder = (g, vs) => {
+                        const visited = new Set();
+                        const result = [];
+                        const dfs = (v) => {
+                            if (!visited.has(v)) {
+                                visited.add(v);
+                                for (const w of g.neighbors(v)) {
+                                    dfs(w);
+                                }
+                                result.push(v);
+                            }
+                        };
+                        for (const v of vs) {
+                            dfs(v);
+                        }
+                        return result;
                     };
-                    let vs = postorder(t, Array.from(t.nodes.keys()));
-                    vs = vs.slice(0, vs.length - 1);
-                    for (const v of vs) {
-                        assignCutValue(t, g, v);
+                    const vs = postorder(t, Array.from(t.nodes.keys()));
+                    for (const v of vs.slice(0, vs.length - 1)) {
+                        const childLabel = t.node(v).label;
+                        const parent = childLabel.parent;
+                        t.edge(v, parent).label.cutvalue = calcCutValue(t, g, v);
                     }
                 };
                 const leaveEdge = (tree) => {
@@ -525,9 +494,19 @@ dagre.layout = (graph, options) => {
                     initCutValues(t, g);
                     // update ranks
                     const root = Array.from(t.nodes.keys()).find((v) => !g.node(v).label.parent);
-                    let vs = preorder(t, root);
-                    vs = vs.slice(1);
-                    for (const v of vs) {
+                    const stack = [ root ];
+                    const visited = new Set();
+                    while (stack.length > 0) {
+                        const v = stack.pop();
+                        if (!visited.has(v)) {
+                            visited.add(v);
+                            for (const w of t.neighbors(v).reverse()) {
+                                stack.push(w);
+                            }
+                        }
+                    }
+                    const vs = Array.from(visited);
+                    for (const v of vs.slice(1)) {
                         const parent = t.node(v).label.parent;
                         let edge = g.edge(v, parent);
                         let flipped = false;
@@ -550,21 +529,17 @@ dagre.layout = (graph, options) => {
                     exchangeEdges(t, g, e, f);
                 }
             };
-
             switch(g.options.ranker) {
-                case 'tight-tree': {
+                case 'tight-tree':
                     longestPath(g);
                     feasibleTree(g);
                     break;
-                }
-                case 'longest-path': {
+                case 'longest-path':
                     longestPath(g);
                     break;
-                }
-                default: {
+                default:
                     networkSimplex(g);
                     break;
-                }
             }
         };
 
@@ -910,14 +885,10 @@ dagre.layout = (graph, options) => {
                     g.setEdge(prev, curr, { weight: 1 });
                 }
             };
-            const dfs = (v) => {
-                const children = g.children(v);
+            const queue = g.children();
+            while (queue.length > 0) {
+                const v = queue.shift();
                 const node = g.node(v).label;
-                if (children.length) {
-                    for (const v of children) {
-                        dfs(v);
-                    }
-                }
                 if ('minRank' in node) {
                     node.borderLeft = [];
                     node.borderRight = [];
@@ -927,9 +898,12 @@ dagre.layout = (graph, options) => {
                         addBorderNode(g, 'borderRight', '_br', v, node, rank);
                     }
                 }
-            };
-            for (const v of g.children()) {
-                dfs(v);
+                const children = g.children(v);
+                if (children.length) {
+                    for (const v of children) {
+                        queue.push(v);
+                    }
+                }
             }
         };