使用BFS(无向)克隆图形

时间:2016-06-12 01:05:32

标签: c++ algorithm graph-theory breadth-first-search

我写了一个简单的算法来使用BFS克隆无向图,但似乎有一些逻辑错误,我无法弄清楚。有人可以看看吗?

想法是访问每个节点并复制它们一次,复制节点后,检查其邻居是否未被复制,将该邻居排入队列;如果它的邻居已被复制,则将它们放入彼此的“#39;邻居矢量。

UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
    //key -> old node, value -> the new copy
    unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> m;
    //the queue always contains old nodes that haven't been copied
    queue<UndirectedGraphNode*> q;
    if(node)
        q.push(node);

    while(!q.empty()) {

        UndirectedGraphNode* n = q.front();
        q.pop();
        if(m.count(n)) continue; // if the node is already copied, continue

        // create the copy
        m[n] = new UndirectedGraphNode(n->label);

        // loop through the neighbors, if it's copied already, add the new copy to new copy's neighbor list
        for(UndirectedGraphNode* oldNei : n->neighbors) {

            if(m.count(oldNei)) {
                UndirectedGraphNode* newNei = m[oldNei];
                m[n]->neighbors.push_back(newNei);
                newNei->neighbors.push_back(m[n]);
            }

            else// if not in the map, it's not copied/visited yet

                q.push(oldNei);
        }

    }

    return m[node];
}

这是节点struct:

/**
 * Definition for undirected graph.
 * struct UndirectedGraphNode {
 *     int label;
 *     vector<UndirectedGraphNode *> neighbors;
 *     UndirectedGraphNode(int x) : label(x) {};
 * };
 */

我在OJ练习:https://leetcode.com/problems/clone-graph/

1 个答案:

答案 0 :(得分:0)

首先,您必须单独处理NULL节点案例,因为在您的代码中,如果输入图表为return m[NULL],则NULL会导致runtime error

看看下面的代码,我已经评论了我添加和删除代码的地方,以及我添加和删除代码的原因。

UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
    // ++ if node is null just return null.
    if(node == NULL) return NULL;

    unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> m;
    queue<UndirectedGraphNode*> q;
    // -- if(node) no need to check this as we have checked it above
    q.push(node);

    // ++ as first input will not have copy so no need to check it in map
    // just create a copy and associate it with original node in map.
    UndirectedGraphNode *graphCopy = new UndirectedGraphNode(node->label);
    m[node] = graphCopy;

    while(!q.empty()) {
        UndirectedGraphNode* n = q.front();
        q.pop();
        // -- if(m.count(n)) continue; :- no need to check this condition as we will
        // only push non copied node in queue.

        // -- m[n] = new UndirectedGraphNode(n->label); :- we will create it inside loop

        // loop through the neighbors, if it's copied already, add the new copy to new copy's neighbor list
        for(UndirectedGraphNode* oldNei : n->neighbors) {
            // if node is processed/ copied earlier then just push it in neighbour of current node
            if(m.count(oldNei)) {
                UndirectedGraphNode* newNei = m[oldNei];
                m[n]->neighbors.push_back(newNei);
                // -- newNei->neighbors.push_back(m[n]); no need of making back connection as 
                // this node has already processed and contains all it neighbour
            }

            else {// if not in the map, it's not copied/visited yet then create new copy of node here 
                  //and push it into queue
                UndirectedGraphNode *p = new UndirectedGraphNode(oldNei->label); // ++ make a copy of node
                m[n]->neighbors.push_back(p); // ++ push it to current node neighbour
                m[oldNei] = p; // ++ associate copied node with its original one
                q.push(oldNei); // push that node to queue
            }
        }
    }
    return graphCopy;
} 

修改: -

您的计划错误: -

  1. 对于自我循环,您将获得错误的输出。当你通过回到节点的链接进行两次自我循环时。

  2. 如果节点A具有邻居B,则B也不必将节点A作为邻居。但是对于每个节点,你只是推动它的邻居而且还在邻居的邻居中推送节点,这是错误的。

  3. 如果未处理Node,那么您只是将其推入队列,而不是在当前节点和未处理节点之间建立任何链接。

  4. 有关详细信息,请参阅代码的执行: -

    Let's take same graph as of problem:
    First node is labeled as 1. Connect node 1 to both nodes 2 and 3.
    Second node is labeled as 2. Connect node 2 to node 3.
    Third node is labeled as 3. Connect node 3 to node 3 (itself), thus   forming a self-cycle.
    
    So original graph will have neighbor like this:
    Neighbor 1 -> 2 , 3
    Neighbor 2 -> 3
    Neighbor 3 -> 3
    
           1
          / \
         /   \
        2 --- 3
             / \
             \_/
    
    Now starting executing your code:
    assume 1 as root node
    
    first it will insert 1 in Queue
    Q -> [ 1 ]
    
    inside While Loop :-
    ----------------------------------------------------------------------------------------------------
    First Iteration:-
    n = 1
    Pop : Q -> empty // 1 is poped out so queue is empty now
    
    here node 1 is not in map so you will create a copy of node 1 and save it in map
    Map -> (1 , 1C)
    
    Check for neighbour of 1 -> which is 2 & 3
    
    inside for loop both node 2 & 3 is not processed so you will push it in Queue so Queue will became:-
    
    Q -> [2, 3]
    ----------------------------------------------------------------------------------------------------
    
    Second Iteration:-
    n = 2
    Pop : Q -> [ 3 ] 
    
    Node 2 is not in map-
    Create copy of node 2 and push it in map
    
    Map -> (1, 1C) , (2, 2C)
    
    Check for neighbour of 2 -> which is 3
    
    node 3 is not processed till now so push it in Queue 
    
    Q -> [3, 3]
    
    ----------------------------------------------------------------------------------------------------
    
    Third Tteration:-
    
    n = 3
    Pop : Q -> [ 3 ]
    
    node 3 is not in map so-
    Create copy of node 3 and push it in map
    
    Map -> (1, 1C) , (2, 2C) , (3, 3C)
    
    Check for neighbour of 3 -> which is 3
    
    Node 3 is also in map so you will create a link between node 3C & 3C which is correct but you will do it twice as you are pushing back node also so in this step you will do as follows
    
    Neighbour 3C -> 3C
    Neighbour 3C -> 3C
    
    So over all it will look like
    
    Neighbour 1C -> 
    Neighbour 2C -> 
    Neighbour 3C -> 3C, 3C
    
    This is your final result and it different from original
    ----------------------------------------------------------------------------------------------------