克隆一张无向图,图中的每个节点包含一个 label (标签)和一个 neighbors (邻接点)列表 。
克隆图时图的遍历的应用,树的遍历,图的遍历是最基本的操作,他们和数组的遍历是一样的,线性结构的问题都是在数组遍历的基础上进行操作,同样树的问题和图的问题也都是在其遍历的基础上操作,我们所要做的是在遍历的基础上添加数据的操作。
# Definition for a undirected graph node
class UndirectedGraphNode:
def __init__(self, x):
self.label = x
self.neighbors = []
# 克隆图是图的遍历的应用,就是我们在遍历图时需要进行一些操作
class Solution:
# @param node, a undirected graph node
# @return a undirected graph node
def cloneGraph(self, node):
if not node:
return node
# visited是一个字典:node.label:新复制的结点,node.label可以定位原来的结点
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:
# 这个步骤做了2个操作,相当于标记了原图中这个结点已经访问了
# 二是复制了这个结点,邻居还有待添加进去
visited[neighborNode.label] = UndirectedGraphNode(neighborNode.label)
# 标记了结点之后,结点入栈
stack.append(neighborNode)
# 既然新图邻居结点都复制了,那么就可以更新新图的邻居列表了
visited[curNode.label].neighbors.append(visited[neighborNode.label])
return root
class Solution2:
# @param node, a undirected graph node
# @return a undirected graph node
def cloneGraph(self, node):
if not node:
return node
#visited是一个字典:原图的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个,一是新建结点(未更新邻接表),二是更新自己邻接表,三是被用作更新其他结点的
邻接表。我们操作过程一直都是在原图上遍历,也就是指针是指向原图的结点,新图对应的在哪里
我们不知道,把原结点和新结点一一对应起来,就相当于一个指针同时指向了原图和新图。
类似的可以扩展,可以把任意的遍历看成最简单的数组遍历,就是指针按照一定方式走,假如两个数组
可以关联起来,可以使用一个指针同时遍历两个数组,简单化遍历之后,一般的问题都只是添加
遍历过程的处理。
=============================================================================
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。



