克隆一张无向图,图中的每个节点包含一个 label (标签)和一个 neighbors (邻接点)列表 。
克隆图时图的遍历的应用,树的遍历,图的遍历是最基本的操作,他们和数组的遍历是一样的,线性结构的问题都是在数组遍历的基础上进行操作,同样树的问题和图的问题也都是在其遍历的基础上操作,我们所要做的是在遍历的基础上添加数据的操作。
class UndirectedGraphNode:
def __init__(self, x):
self.label = x
self.neighbors = []
class Solution:
def cloneGraph(self, node):
if not node:
return node
visited = {}
root = UndirectedGraphNode(node.label)
visited[node.label] = root
stack = [node,]
while stack:
curNode = stack.pop()
for neighborNode in curNode.neighbors:
if neighborNode.label not in visited:
visited[neighborNode.label] = UndirectedGraphNode(neighborNode.label)
stack.append(neighborNode)
visited[curNode.label].neighbors.append(visited[neighborNode.label])
return root
class Solution2:
def cloneGraph(self, node):
if not node:
return node
visited = {}
root = UndirectedGraphNode(node.label)
visited[node] = root
stack = [node,]
while stack:
curNode = stack.pop()
for neighborNode in curNode.neighbors:
if neighborNode not in visited:
visited[neighborNode] = UndirectedGraphNode(neighborNode.label)
stack.append(neighborNode)
visited[curNode].neighbors.append(visited[neighborNode])
return root
=============================================================================
下面来总结一下克隆图的思路,首先图形的遍历很清楚了,我们所要做的是:在遍历每一个结点
时,复制该结点以及他的邻接结点,但是有一个问题,这时新图的邻接结点还没有新建,就没有
办法,更新新图这个结点的邻接结点表,但是我们在遍历原图的时候,会把原图的邻接结点都
一个一个的放入到栈中或者队列中,在放入前我们就可以把新图的结点复制了,这样新图结点
邻接结点都存在了,就可以直接添加了,这里面需要注意,原图遍历的时候结点入栈时会去重
但是新图需要把所有的邻接结点都添加进去,只要确认他的列表里面的结点都创建了,就行了
这就是为什么visited[curNode].neighbors.append(visited[neighborNode])在if语句的
外面。然后,我们还是没有讲到为什么会想到使用{原结点:新结点}的字典,这是因为对一个结点
操作有3个,一是新建结点(未更新邻接表),二是更新自己邻接表,三是被用作更新其他结点的
邻接表。我们操作过程一直都是在原图上遍历,也就是指针是指向原图的结点,新图对应的在哪里
我们不知道,把原结点和新结点一一对应起来,就相当于一个指针同时指向了原图和新图。
类似的可以扩展,可以把任意的遍历看成最简单的数组遍历,就是指针按照一定方式走,假如两个数组
可以关联起来,可以使用一个指针同时遍历两个数组,简单化遍历之后,一般的问题都只是添加
遍历过程的处理。
=============================================================================
递归方式,更加能从整体考察问题:
class Solution3:
def cloneGraph(self,node):
if not node:
return node
visited ={}
root = UndirectedGraphNode(node.label)
visited[node] = root
def Rec(node,visited):
for neighborNode in node.neighbors:
if neighborNode not in visited:
visited[neighborNode] = UndirectedGraphNode(neighborNode.label)
Rec(neighborNode,visited)
visited[node].neighbors.append(visited[neighborNode])
Rec(node,visited)
return root
class Solution4:
def cloneGraph(self,node):
if not node:
return node
visited ={}
def cloneGraphRec(node,visited):
if node in visited:
return visited[node]
visited[node] = UndirectedGraphNode(node.label)
for neighborNode in node.neighbors:
visited[node].neighbors.append(cloneGraphRec(neighborNode,visited))
return visited[node]
return cloneGraphRec(node,visited)