JavaScript - 图形遍历 - 从起始节点按顺序获取节点(最接近第一个)

时间:2014-04-09 09:51:08

标签: javascript algorithm graph traversal graph-traversal

我有一张如下图:

root : {
    nodeType : "root",
    children: [
    "A",
    "B",
    "C"
    ]
}
nodes : [
"A": {
    nodeType : "node",
    children: [
    "D",
    "E"
    ]
},
"B": {
    nodeType : "node",
    children: [
    "D",
    "F"
    ]
},
"C": {
    nodeType : "leaf"
},
"D": {
    nodeType : "node",
    children: [
    "G"
    ]
},
"E": {
    nodeType : "leaf"
},
"F": {
    nodeType : "leaf"
},
"G": {
    nodeType : "leaf"
},
]

我需要编写一个javascript函数,给定一个起点(例如“B”),它将以最接近起始点优先级的方式遍历图形。例如对于B,它会得到孩子D,F,然后是根,然后是兄弟姐妹B,C,然后是granchild G,然后是B和C的孩子,依此类推。

即使只是让算法没问题

PS:我知道我可以在那里使用dijkstra,但我真的不知道如何

2 个答案:

答案 0 :(得分:1)

您可以使用Breadth-first search实施,例如here。如果树中的边缘具有与之相关的权重,则需要Dijkstra的算法。

由于您未将父项保留在节点对象中,因此需要添加预处理步骤以将父字段添加到所有节点。这是必需的,以便在B开始时您知道访问根。这可以使用简单的遍历来完成。

广度优先搜索会将您需要访问的节点保留在队列中。新节点将添加到队列的末尾。该算法从队列的前面选择要访问的新节点。

但要小心,因为如果允许复制节点,队列可能会变得非常大。

答案 1 :(得分:0)

感谢关于使用广度优先算法的cyon建议,我想出了这个 (基于http://java.dzone.com/articles/algorithm-week-graph-breadth):

var graph = {
    A : [B, C],
    B : [A, D],
    C : [A, D],
    D : [A, C ,E],
    E : [B, F],
    F : [E]
};

function init (visited, graph) 
{
    for (var key in graph) {
       var vertex = graph[key];
        visited[key] = false;
    }
}

function breadthFirst (graph, start, visited)
{
    // Create an empty queue
    var queue = [];

    // Initially enqueue only the starting vertex
    queue.push(start);

    //Set the starting vertex to visited
    visited[start] = true;

    //Add it to the result
    result.push( start );

    //While there is still remaining vertexes in queue
    while (queue.length > 0) {

       //Remove first vertex from queue and save it in "t"
       var currentVertexID = queue.shift();

       //For each key in graph at "t"
       var currentVertex = graph[currentVertexID];
       for (var key in currentVertex) {

       var target = currentVertex[key];

            //If it has not been visited yet
            if (!visited[target]) {

                //Mark it as visited
                visited[target] = true;

                //Add it to queue
                queue.push(target);

                //Save it in result
                result.push(target);
                //console.log(result);
            }
        }
    }
}

var result = [];
var visited = [];
init(visited, graph);
breadthFirst(graph, 2, visited);    
console.log(result);    

因为我有一个分离的根,并且我的图中只有父子关系(因为我从树中迁移),所以我必须在使用广度之前建立一个完整的关系矩阵(以便它可以查找父母)。

我发布它是因为它可以用于预处理,以便首先在树上使用广度

generateNodesAdjacencyMatrix : function(){
            var adjacencyMatrix = {};
            function recursiveFindNestedAndSaveLinks(parentKey, childrenKeys){
                //Add the links to parent pointing to his children
                if(!_.isArray(adjacencyMatrix[parentKey])){
                    adjacencyMatrix[parentKey] = [];
                }
                adjacencyMatrix[parentKey] = adjacencyMatrix[parentKey].concat(childrenKeys);

                //For each children
                _.each(childrenKeys, function (childKey){
                    //Add a link to parent
                    if(!_.isArray(adjacencyMatrix[childKey])){
                        adjacencyMatrix[childKey] = [];
                    }
                    adjacencyMatrix[childKey].push(parentKey);

                    //If it has children as well, do recursive on him
                    var child = childs[childKey];
                    if(!_.isUndefined(child) && !_.isUndefined(child.children)){
                        recursiveFindNestedAndSaveLinks(childKey, child.children);
                    }
                }, this);
            }
            recursiveFindNestedAndSaveLinks('root', root.children);
            return adjacencyMatrix;
        },