// 图的核心就是 结点与它的邻接结点
// 所以克隆图就是克隆图的各个结点与这些结点的邻接关系
// 每次dfs算法传入的就是当前结点,dfs内继续递归的内容就是该结点的邻接结点
详细步骤在代码注释当中
深度优先遍历解法:
* // Definition for a Node.
* function Node(val, neighbors) {
* this.val = val === undefined ? 0 : val;
* this.neighbors = neighbors === undefined ? [] : neighbors;
* };
*/
var cloneGraph = function (node) {
if (!node) return;
const visited = new Map();
const dfs = (n) => {
// 创建新结点,克隆传入dfs传入结点的值
const nCopy = new Node(n.val);
// 访问过的结点存入字典当中
// 键:当前结点 值:当前结点的值
visited.set(n, nCopy);
// 递归 访问该结点的邻接结点
n.neighbors.forEach(ne => {
// 没有被访问过的结点继续递归
if (!visited.has(ne)) {
dfs(ne);
}
// 克隆结点的邻接关系
// 当前是在结点的邻接结点当中,且上方代码已经dfs完成了邻接结点
// 所以邻接结点已经存入了字典当中
nCopy.neighbors.push(visited.get(ne));
})
};
dfs(node);
return visited.get(node);
};
广度优先遍历解法:
var cloneGraph = function (node) {
if (!node) return;
const visited = new Map();
// 广度优先遍历,需要结合队列
const q = [node];
// 加入队列的结点要标记为已经访问过
visited.set(node,new Node(node.val));
while(q.length) {
const n = q.shift();
// 访问出队结点的邻接关系结点
n.neighbors.forEach(ne=>{
// 如果邻接结点没有访问过
if(!visited.has(ne)) {
// 推入队列
q.push(ne);
// 新加入队列的结点进行已访问标记
visited.set(ne,new Node(ne.val));
}
// 给该结点克隆它的邻接关系
visited.get(n).neighbors.push(visited.get(ne));
})
}
return visited.get(node);
};