【问题标题】:Routing or pathfinding algorithm for multi-direction network in JavaScriptJavaScript中多向网络的路由或寻路算法
【发布时间】:2014-04-17 03:58:29
【问题描述】:

我正在尝试用 JavaScript 为以下由节点组成的网络编写路由/路径查找算法。每个节点都有规则来管理它是否可以作为入口点、出口点和/或被遍历。

给定一个有效的入口点,我需要解决以下两个问题:

  1. 网络的有效和可用出口点是什么
  2. 一旦确定并选择了有效的出口点,最佳路线是什么(需要遍历的节点)

网络规则:

  1. 您只能输入具有入口点的节点,即节点 A、B C、D、E、F、G
  2. 您只能退出具有退出点的节点,即节点 B、C、E、F、G
  3. 行进方向由入口节点决定 - 这决定了您可以行进和退出的方向。 。例如。通过节点A进入时顺时针行驶和退出
  4. 进入网络后就不能改变方向。

我将网络表示为一个对象数组,数组中的每个对象代表网络上的一个节点。

    var network = [{
                     id: 'A',
                     canBeEntry: true,
                     ifEntryRouteIs: 'CW',
                     isExitIfRouteIs: 'N/A',
                     neighbourCW: ['B'],
                     neighbourCCW: ['H']
                    }, {
                     id: 'B',
                     canBeEntry: true,
                     ifEntryRouteIs: 'CW&CCW',
                     isExitIfRouteIs: 'CW',
                     neighbourCW: ['C'],
                     neighbourCCW: ['A']
                    },
                    .
                    .
                    .
                    {
                     id: 'H',
                     canBeEntry: false,
                     ifEntryRouteIs: 'N/A',
                     isExitIfRouteIs: 'N/A',
                     neighbourCW: ['A'],
                     neighbourCCW: ['G']
                    }];

描述有效进入/退出节点、转换和权重的图表如下:

我对寻路和路由相关的算法(例如 Dijkstra 或 A* 搜索)做了一些或研究,但它们似乎基于成本和权重,我认为这不适用于我的网络。

有没有人对如何用 JavaScript 编写算法来首先确定出口点,然后是路线有任何想法或方法?

我试图在 JavaScript 中实现的 jsfiddle 在这里 http://jsfiddle.net/mkov/dgGHm/

【问题讨论】:

  • 这似乎是一个竞争问题。 Dijkstra 实际上适用于您的情况,您的成本始终为 1
  • 不是竞争问题。只是比我对一个项目的咀嚼还要多;)我想我理解 Dijkstra 可能如何协助路由,但是确定有效的退出点呢?我需要先执行此操作,以便为算法构建图表?
  • 您需要一种算法来检查给定起始节点的出口点,以及另一种算法来获得起始节点和所选出口节点之间的最短路线。我不明白的是ifEntryRouteIs:你怎么知道起始节点的方向?
  • 该项目涉及道路行程规划。并非所有节点都是网络的入口点,但对于我们可以进入的节点,我们可能只能沿一个方向行进,例如节点 A、C、G。类似地,我们可能只能从特定方向的某些节点退出。我已经知道每个节点的有效进出方向。

标签: javascript algorithm networking tree path-finding


【解决方案1】:

如果我理解正确,你想找到给定的起始节点和方向,可能的出口和通往它们的最短路径。这应该可行:(必须稍微修改原始数据):

var validExitPoints =[];
    var nodes=[];
    var tree_path=[];
    nodes.push({node:entryPoint});
    visited[entryPoint]=true;
    while(!nodes.length==0){
        var node=network_obj[nodes[0].node];

        nodes.shift();
        if(canExit(node.id,dir)){
            validExitPoints.push({node:node.id,path:''});
        }
        var neighbours=getNeighbours(node.id,dir);
        for(var i=0;i<neighbours.length;i++){
            if(visited[neighbours[i]]==false){
                nodes.push({node:neighbours[i]});
                visited[neighbours[i]]=true;
                tree_path[neighbours[i]]=node.id;
            }
        }
    }

这是主要代码,完整代码请看这里:

http://jsfiddle.net/juvian/dgGHm/6/

我使用了广度优先搜索,您可以在此处阅读更多信息:

http://en.wikipedia.org/wiki/Breadth-first_search

【讨论】:

  • 感谢 juvian,是的,我注意到我发布的链接的数据中有错误。我不认为这是最新版本。更新版本设置为基础:jsfiddle.net/mkov/dgGHm
  • 谢谢@juvian。您提供的解决方案看起来不错,但强制选择方向。为了澄清,给定一个起始(入口)节点(行进方向未选择但需要确定),有效的出口点是什么?选择有效的条目和退出点时,最短路径(和遍历的节点)。 B、C、E、F、G 将是网络的有效出口点(考虑入口节点的方向)
  • 那么你想选择A作为入口点并计算两个方向的出口点?一旦你开始顺时针走,你可以逆时针走,还是必须始终保持同一个方向,但要保持不变?
  • 正确。当您进入网络时,行进和退出的方向是指定的。行进方向一旦输入就不能改变。例如,如果您从节点 A 进入,您只能沿顺时针方向行驶,只能沿顺时针方向退出,但假设您从节点 F 进入,您可以向任一方向行驶,而退出节点可能位于任一方向方向。通过节点 A(顺时针)进入时的有效出口节点为:B、E、F 和 G。
  • 检查我的新小提琴:jsfiddle.net/juvian/dgGHm/8。如果它工作正常,我可以解释代码或更清楚,如果不能,请解释我一个它不能正常工作的情况
【解决方案2】:

我发现您的网络数据结构有点复杂。您实际上有两个图(cw 和 cww),它们共享它们的顶点,但不共享它们的边以及出口和入口点。

下面的实现定义了单独的图并将它们连接到图网络中。您可以使用 Juvian 建议的广度优先搜索为每个图创建最短路径列表。然后,您可以为所有图表组合这些列表。

下面的代码只是没有GUI和小提琴的寻路:

// Return an object that contains a path for each
// possible exit point
function find_exits(g, id, func) {
    var visited = {};
    var list = {};
    var v = g[id];
    var q = [[id, [id]]];

    visited[id] = true;
    if (v.exit) list[id] = [id];

    while (q.length) {
        var x = q.shift();
        var path = x[1];

        id = x[0];                
        v = g[id];

        for (var i = 0; i < v.edge.length; i++) {
            var next =  v.edge[i];
            if (next in visited) continue;

            visited[next] = true;
            if (g[next].exit) {
                list[next] = path.concat([next]);
            }
            q.push([next, path.concat([next])]);
        }
        path.pop();
    }

    return list;
}

// Combine two exit lists, choose the shorter path if there
// is an exit in both lists
function union(a, b) {
    var u = {};

    for (var x in a) u[x] = a[x];
    for (var x in b) {
        if (x in a && a[x].length < b[x].length) continue;
        u[x] = b[x];
    }
    return u;
}

var cw = {
    A: {
        entry: true,
        edge: ['B']
    },
    B: {
        entry: true,
        exit: true,
        edge: ['C']
    },
    C: {
        entry: true,
        edge: ['D']
    },
    D: {
        edge: ['E', 'F']
    },
    E: {
        exit: true
    },
    F: {
        entry: true,
        exit: true,
        edge: ['G']
    },
    G: {
        exit: true,
        edge: ['H']
    },
    H: {
        edge: ['A']
    }
};

var ccw = {
    A: {
        edge: ['H']
    },
    B: {
        entry: true,
        edge: ['A']
    },
    C: {
        exit: true,
        edge: ['B']
    },
    D: {
        entry: true,
        edge: ['C']
    },
    E: {
        entry: true,
        edge: ['D']
    },
    F: {
        entry: true,
        exit: true,
        edge: ['D']
    },
    G: {
        entry: true,
        edge: ['F']
    },
    H: {
        edge: ['G']
    }
};

// Housekeeping object for a network of several sub-graphs
var network = {
    graphs: [cw, ccw],
    traverse: function(func) {
        for (var i = 0; i < this.graphs.length; i++) {
            func(this.graphs[i]);
        }
    }
}

// Ensure that every vertex has edge, exit, entry
network.traverse(function(g) {
    for (var id in g) {
        var v = g[id];

        if (!("edge" in v)) v.edge = [];
        if (!("entry" in v)) v.entry = false;
        if (!("exit" in v)) v.exit = false;
    }
});

// Actual path-seeking

var start = 'B';
var exits = {};

network.traverse(function(g) {
    if (g[start].entry) {
        exits = union(exits, find_exits(g, start));
    }
});

console.log(exits);

这个例子没有显示实际路径是针对哪个图表,但我认为这可以很容易地添加。

【讨论】:

  • 谢谢@M Oehm。您的解决方案也有效,以这种方式重组网络更有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
相关资源
最近更新 更多