给定两个节点,如何找出他们之间的所有路径?

给定一个数组,数组描述是两个点之间的连接关系,给定两个点,需要找出两个点之间的所有“路径”,如何写这个算法?

数据结构如下,描绘图形如下:

//原始数据结构

let arr = [
    //第一条路径
    {source: 'node-1', target: 'node-2'},
    {source: 'node-2', target: 'node-5'},
    {source: 'node-5', target: 'node-6'},
    {source: 'node-6', target: 'node-8'},
    //第二条路径
    {source: 'node-5', target: 'node-7'},
    {source: 'node-7', target: 'node-8'},
    //第三条路径
    {source: 'node-1', target: 'node-3'},
    {source: 'node-3', target: 'node-4'},
    {source: 'node-4', target: 'node-7'},
]

现在假设给定两个节点:node1、node8,需要求出他们之间的所有路径,用二维数组表示:

返回结果如下:


let result = [
    //第一条路径
    [
        {source: 'node-1', target: 'node-2'},
        {source: 'node-2', target: 'node-5'},
        {source: 'node-5', target: 'node-6'},
        {source: 'node-6', target: 'node-8'},
    ],
    //第二条路径
    [
        {source: 'node-1', target: 'node-2'},
        {source: 'node-2', target: 'node-5'},
        {source: 'node-5', target: 'node-7'},
        {source: 'node-7', target: 'node-8'},
    ],
    //第三条路径
    [
        {source: 'node-1', target: 'node-3'},
        {source: 'node-3', target: 'node-4'},
        {source: 'node-4', target: 'node-7'},
        {source: 'node-7', target: 'node-8'},
    ]
]
阅读 12.7k
avatarAI BotBETA
你可以使用深度优先搜索(DFS)算法来找出两个节点之间的所有路径。以下是一个可能的实现:

function findAllPaths(graph, start, end, path = [], allPaths = []) {

// 将当前节点添加到路径中
path = path.concat({source: start, target: undefined});
let node = {source: start, target: undefined};

// 查找当前节点的所有邻居
const neighbors = graph.filter(edge => edge.source === start);

// 遍历所有邻居
for (let neighbor of neighbors) {
    node.target = neighbor.target;
    
    // 如果找到了目标节点,保存当前路径
    if (neighbor.target === end) {
        allPaths.push([...path, node]);
    } else if (!path.some(p => p.target === neighbor.target)) { // 避免循环路径
        // 递归查找从邻居节点开始的所有路径
        findAllPaths(graph, neighbor.target, end, path, allPaths);
    }
}
return allPaths.map(p => p.map(({source, target}, index, arr) => ({
    source,
    target: index === arr.length - 1 ? end : arr[index + 1].source.split('-')[1]
})));

}

// 构建图的邻接表表示
const adjList = {};
arr.forEach(({source, target}) => {

if (!adjList[source]) adjList[source] = [];
adjList[source].push(target);

});

// 将邻接表转换为适合DFS遍历的数组形式
const graph = [];
for (let node in adjList) {

adjList[node].forEach(neighbor => {
    graph.push({source: node, target: neighbor});
});

}

// 调用函数并打印结果
const result = findAllPaths(graph, 'node-1', 'node-8');
console.log(result);


该代码首先构建了一个图的邻接表表示,然后将其转换为适合DFS遍历的数组形式。`findAllPaths` 函数使用递归的深度优先搜索来查找从起始节点到目标节点的所有路径。为了避免循环路径,它检查当前路径中是否已经包含了某个邻居节点。最后,它返回所有找到的路径,并将目标节点的 `target` 属性更新为正确的值。

注意:在将路径添加到 `allPaths` 数组之前,我们复制了 `path` 数组以避免直接修改原始数组(因为 JavaScript 中的数组是引用类型)。此外,在返回结果之前,我们遍历 `allPaths` 数组,将每个路径中的 `target` 属性更新为正确的节点名(因为原始 `graph` 数组中的 `target` 属性是未定义的,我们只在递归过程中使用了它)。
2 个回答
let arr = [
    {source: 'node-1', target: 'node-2'},
    {source: 'node-2', target: 'node-5'},
    {source: 'node-5', target: 'node-6'},
    {source: 'node-6', target: 'node-8'},
    {source: 'node-5', target: 'node-7'},
    {source: 'node-7', target: 'node-8'},
    {source: 'node-1', target: 'node-3'},
    {source: 'node-3', target: 'node-4'},
    {source: 'node-4', target: 'node-7'},
];

// 查找所有从 start 到 end 的路径
function findAllPaths(graph, start, end) {
    let paths = []; // 存储所有路径
    let stack = [[start, []]]; // 使用栈进行深度优先搜索
    let adjacencyList = {}; // 邻接表

    // 构建邻接表
    for (let edge of graph) {
        if (!adjacencyList[edge.source]) {
            adjacencyList[edge.source] = [];
        }
        adjacencyList[edge.source].push(edge.target);
    }

    // 深度优先搜索
    while (stack.length > 0) {
        let [node, path] = stack.pop();
        path = path.concat(node); // 更新路径

        if (node === end) {
            paths.push(path); // 找到一条完整路径
        } else if (adjacencyList[node]) {
            for (let neighbor of adjacencyList[node]) {
                if (!path.includes(neighbor)) {
                    stack.push([neighbor, path]); // 继续搜索
                }
            }
        }
    }

    return paths;
}

// 将路径转换为边的形式
function convertPathsToEdges(paths) {
    return paths.map(path => {
        let edges = [];
        for (let i = 0; i < path.length - 1; i++) {
            edges.push({source: path[i], target: path[i + 1]});
        }
        return edges;
    });
}

let paths = findAllPaths(arr, 'node-1', 'node-8'); // 查找所有路径
let result = convertPathsToEdges(paths); // 转换为边的形式

console.log(result); // 输出结果
const arr = [
    { source: 'node-1', target: 'node-2' },
    { source: 'node-2', target: 'node-5' },
    { source: 'node-5', target: 'node-6' },
    { source: 'node-6', target: 'node-8' },

    { source: 'node-5', target: 'node-7' },
    { source: 'node-7', target: 'node-8' },

    { source: 'node-1', target: 'node-3' },
    { source: 'node-3', target: 'node-4' },
    { source: 'node-4', target: 'node-7' }
]

interface Node {
    name: string
    to: Set<Node>
}

const graph = new Map<string, Node>()

arr.forEach(({ source, target }) => {
    if (!graph.has(target))
        graph.set(target, {
            name: target,
            to: new Set()
        })
    if (!graph.has(source))
        graph.set(source, {
            name: source,
            to: new Set([graph.get(target)!])
        })
    else graph.get(source)?.to.add(graph.get(target)!)
})

function findPath(from: Node, to: Node): Node[][] {
    return from === to
        ? [[to]]
        : Array.from(from.to)
                .map(node => findPath(node, to))
                .flat()
                .map(path => [from, ...path])
}

const result = findPath(graph.get('node-1')!, graph.get('node-8')!).map(path =>
    path
        .slice(0, -1)
        .map((node, idx) => ({ source: node.name, target: path[idx + 1].name }))
)

console.log(result)
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏