繁体   English   中英

使用BFS克隆图形(无向)

[英]Clone a graph using BFS (undirected)

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

这个想法是访问每个节点并只复制一次,复制一个节点后,检查是否没有复制它的邻居,将那个邻居排入队列; 如果其邻居已被复制,则将它们放入彼此的邻居向量中。

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];
}

这是节点结构:

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

这是我正在练习的OJ: https : //leetcode.com/problems/clone-graph/

首先,您必须分别处理NULL节点的情况,因为如果输入图为NULL ,则在代码中将return m[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具有邻居BB不必也将节点A作为邻居。 但是对于每个节点,您都只是将其推向邻居,而且还将节点推向邻居的邻居,这是错误的。

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

有关更多详细信息,请参见代码执行:

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
----------------------------------------------------------------------------------------------------

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM