图形结构:克隆图,图的遍历的应用,递归和迭代
生活随笔
收集整理的這篇文章主要介紹了
图形结构:克隆图,图的遍历的应用,递归和迭代
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
克隆一張無向圖,圖中的每個節(jié)點包含一個 label (標簽)和一個 neighbors (鄰接點)列表 。
克隆圖時圖的遍歷的應用,樹的遍歷,圖的遍歷是最基本的操作,他們和數(shù)組的遍歷是一樣的,線性結(jié)構(gòu)的問題都是在數(shù)組遍歷的基礎(chǔ)上進行操作,同樣樹的問題和圖的問題也都是在其遍歷的基礎(chǔ)上操作,我們所要做的是在遍歷的基礎(chǔ)上添加數(shù)據(jù)的操作。
# Definition for a undirected graph node class UndirectedGraphNode:def __init__(self, x):self.label = xself.neighbors = []# 克隆圖是圖的遍歷的應用,就是我們在遍歷圖時需要進行一些操作 class Solution:# @param node, a undirected graph node# @return a undirected graph nodedef cloneGraph(self, node):if not node:return node# visited是一個字典:node.label:新復制的結(jié)點,node.label可以定位原來的結(jié)點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個操作,相當于標記了原圖中這個結(jié)點已經(jīng)訪問了# 二是復制了這個結(jié)點,鄰居還有待添加進去visited[neighborNode.label] = UndirectedGraphNode(neighborNode.label)# 標記了結(jié)點之后,結(jié)點入棧stack.append(neighborNode)# 既然新圖鄰居結(jié)點都復制了,那么就可以更新新圖的鄰居列表了visited[curNode.label].neighbors.append(visited[neighborNode.label])return rootclass Solution2:# @param node, a undirected graph node# @return a undirected graph nodedef cloneGraph(self, node):if not node:return node#visited是一個字典:原圖的node:新復制的結(jié)點,這樣使用更加簡潔,速度更快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=============================================================================
下面來總結(jié)一下克隆圖的思路,首先圖形的遍歷很清楚了,我們所要做的是:在遍歷每一個結(jié)點
時,復制該結(jié)點以及他的鄰接結(jié)點,但是有一個問題,這時新圖的鄰接結(jié)點還沒有新建,就沒有
辦法,更新新圖這個結(jié)點的鄰接結(jié)點表,但是我們在遍歷原圖的時候,會把原圖的鄰接結(jié)點都
一個一個的放入到棧中或者隊列中,在放入前我們就可以把新圖的結(jié)點復制了,這樣新圖結(jié)點
鄰接結(jié)點都存在了,就可以直接添加了,這里面需要注意,原圖遍歷的時候結(jié)點入棧時會去重
但是新圖需要把所有的鄰接結(jié)點都添加進去,只要確認他的列表里面的結(jié)點都創(chuàng)建了,就行了
這就是為什么visited[curNode].neighbors.append(visited[neighborNode])在if語句的
外面。然后,我們還是沒有講到為什么會想到使用{原結(jié)點:新結(jié)點}的字典,這是因為對一個結(jié)點
操作有3個,一是新建結(jié)點(未更新鄰接表),二是更新自己鄰接表,三是被用作更新其他結(jié)點的
鄰接表。我們操作過程一直都是在原圖上遍歷,也就是指針是指向原圖的結(jié)點,新圖對應的在哪里
我們不知道,把原結(jié)點和新結(jié)點一一對應起來,就相當于一個指針同時指向了原圖和新圖。
類似的可以擴展,可以把任意的遍歷看成最簡單的數(shù)組遍歷,就是指針按照一定方式走,假如兩個數(shù)組
可以關(guān)聯(lián)起來,可以使用一個指針同時遍歷兩個數(shù)組,簡單化遍歷之后,一般的問題都只是添加
遍歷過程的處理。
=============================================================================
遞歸方式,更加能從整體考察問題:
class Solution3:# @param node, a undirected graph node# @return a undirected graph nodedef 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# 還有一種思路:不是從子圖來思考問題,而是從子圖延申到子問題,這個問題是克隆子圖, # 克隆子圖里面的每一個結(jié)點,并返回克隆的始頂點 class Solution4:# @param node, a undirected graph node# @return a undirected graph nodedef 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)總結(jié)
以上是生活随笔為你收集整理的图形结构:克隆图,图的遍历的应用,递归和迭代的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图形结构:遍历模型,分治法,动态规划,回
- 下一篇: 图形结构:安排课程,图的遍历策略