给定某些节点的所有可能路由,返回到起始节点

时间:2016-04-09 21:19:50

标签: javascript recursion

我目前正在处理一个小问题,它会输出访问所有节点并返回到起始节点的所有可能组合。

我在数组["a", "b", "c"]中有三个节点 所有可能的路线都是

pairs = [ [ 'a', 'b' ],
  [ 'a', 'c' ],
  [ 'b', 'a' ],
  [ 'b', 'c' ],
  [ 'c', 'a' ],
  [ 'c', 'b' ] ];

我生成路线的功能是(__用于下划线库)

routesRecursive = function(pairs, currentNode, origin, result) {
  __.each(pairs, function(pair) {
    if (currentNode === __.first(pair)) {
      var currentRoute = pair;
      var nextNode = __.last(currentRoute);
      if (nextNode === origin) {
        result.push(pair);
      } else {
        result.push(currentRoute);
        routesRecursive(__.without(pairs, currentRoute), nextNode, origin, result); 
      }
    }
  });
  return result;
}
routesRecursive(pairs, "a", "a", [])

所需的输出将是:

[
  [["a", "b"], ["b", "a"]],
  [["a", "b"], ["b", "c"], ["c", "a"]],
  [["a", "b"], ["b", "c"], ["c", "b"], ["b", "a"]],
  [["a", "c"], ["c", "a"]],
  [["a", "c"], ["c", "b"], ["b", "a"]],
  [["a", "c"], ["c", "b"], ["b", "c"], ["c", "a"]]
]

似乎我的功能无法产生预期效果,任何人都有任何建议吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

试试这个:

function paths({ graph = [], from, to }, path = []) {
    const linkedNodes = memoize(nodes.bind(null, graph));
    return explore(from, to);

    function explore(currNode, to, paths = []) {
        path.push(currNode);
        for (let linkedNode of linkedNodes(currNode)) {
            if (linkedNode === to) {
                let result = path.slice(); // copy values
                result.push(to);
                paths.push(result);
                continue;
            }
            // do not re-explore edges
            if (!hasEdgeBeenFollowedInPath({
                    edge: {
                        from: currNode,
                        to: linkedNode
                    },
                    path
                })) {                    
                explore(linkedNode, to, paths);
            }
        }
        path.pop(); // sub-graph fully explored            
        return paths;
    }
}

/** 
 * Get all nodes linked 
 * to from `node`.
 */
function nodes(graph, node) {
    return graph.reduce((p, c) => {
        (c[0] === node) && p.push(c[1]);
        return p;
    }, []);
}

/**
 * Has an edge been followed 
 * in the given path?
 */
function hasEdgeBeenFollowedInPath({ edge, path }) {
    var indices = allIndices(path, edge.from);
    return indices.some(i => path[i + 1] === edge.to);
}

/**
 * Utility to get all indices of 
 * values matching `val` in `arr`.
 */
function allIndices(arr, val) {
    var indices = [],
        i;
    for (i = 0; i < arr.length; i++) {
        if (arr[i] === val) {
            indices.push(i);
        }
    }
    return indices;
}

/**
 * Avoids recalculating linked 
 * nodes.
 */
function memoize(fn) {
    const cache = new Map();
    return function() {
        var key = JSON.stringify(arguments);
        var cached = cache.get(key);
        if (cached) {
            return cached;
        }
        cached = fn.apply(this, arguments)
        cache.set(key, cached);
        return cached;;
    };
}
const graph = [
    ['a', 'b'],
    ['a', 'c'],
    ['b', 'a'],
    ['b', 'c'],
    ['c', 'a'],
    ['c', 'b']
];
document.write(JSON.stringify(paths({
    graph,
    from: 'a',
    to: 'a'
})));