克隆一张无向图,图中的每个节点包含一个 label (标签)和一个 neighbors (邻接点)列表 。

克隆图时图的遍历的应用,树的遍历,图的遍历是最基本的操作,他们和数组的遍历是一样的,线性结构的问题都是在数组遍历的基础上进行操作,同样树的问题和图的问题也都是在其遍历的基础上操作,我们所要做的是在遍历的基础上添加数据的操作。

# 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:新复制的结点,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 rootclass Solution2:# @param node, a undirected graph node# @return a undirected graph nodedef 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个,一是新建结点(未更新邻接表),二是更新自己邻接表,三是被用作更新其他结点的

邻接表。我们操作过程一直都是在原图上遍历,也就是指针是指向原图的结点,新图对应的在哪里

我们不知道,把原结点和新结点一一对应起来,就相当于一个指针同时指向了原图和新图。

类似的可以扩展,可以把任意的遍历看成最简单的数组遍历,就是指针按照一定方式走,假如两个数组

可以关联起来,可以使用一个指针同时遍历两个数组,简单化遍历之后,一般的问题都只是添加

遍历过程的处理。

=============================================================================

递归方式,更加能从整体考察问题:

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# 还有一种思路:不是从子图来思考问题,而是从子图延申到子问题,这个问题是克隆子图,
# 克隆子图里面的每一个结点,并返回克隆的始顶点
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)

图形结构:克隆图,图的遍历的应用,递归和迭代相关推荐

  1. 详解二叉树的三种遍历方式(递归、迭代、Morris算法)

    详解二叉树的三种遍历方式(递归.迭代.Morris算法) 最重要的事情写在前面:遍历顺序不一定就是操作顺序!!! 递归解法 首先,一颗二叉树它的递归序列是一定的,导致其前中后序不同的原因只不过是访问节 ...

  2. html递归遍历,图的深度遍历是一个递归过程

    数据结构问题:图的深度优先遍历中有递归的应用,数据结构问题:图的深度优先遍历中有递归的应用,要用到栈,图中顶点是首先你得明白函数调用本身就是通过栈来实现的. 调用函数是入栈,而函数返回是出栈. 为什么 ...

  3. 一起学DNS系列(十)图、例详解DNS递归和迭代查询原理及过程 (1)

    上节中提到了一些有关递归查询的内容,但说的很少,也很笼统,本节将会从原理和实例两方面入手分析DNS的递归以及迭代查询. 在此之前,我们需要了解一些背景知识,以便于更好的理解今天的主题内容. 在互联网中 ...

  4. LeetCode 145. Binary Tree Postorder Traversal--后序遍历--先序遍历反向输出--递归,迭代--C++,Python解法

    题目地址:Binary Tree Postorder Traversal - LeetCode Given a binary tree, return the postorder traversal ...

  5. [C] 图的广度优先遍历

    图的广度优先遍历 我一直觉得图的遍历没有地图类型的题目难,遍历嘛,每个点都走一遍就行了. 但是给定地图求面积啊,数量啊的那种题目,花样挺多的. 图的遍历真挺难把人绕晕的,关于广度优先,理解好层层递进这 ...

  6. [C] 图的深度优先遍历

    图的DFS遍历 首先我们需要知道什么是图 简单地说,图就是由一些小圆点(称为顶点)和连接这些小圆点的直线(称为边)组成的.例如上图是由五个顶点(编号为1,2,3,4,5)和五条边(1-2,1-3,1- ...

  7. 实验报告C语言实现图的深度遍历,图的深度优先遍历的C语言实现.pdf

    图的深度优先遍历的C语言实现.pdf 维普资讯 九 江 职 业 技 术 学 院 学 报 JournalofJiujiangVocational&TechnicalCollege 2004.2 ...

  8. 邻接表存储图的广度优先遍历

    试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) ); 其中LGraph是邻接表存储 ...

  9. 数据结构 图的广度优先遍历 C++

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Bool ...

  10. 数据结构 图的深度优先遍历 C

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Bool ...

最新文章

  1. Bootstrap系列 -- 34. 按钮下拉菜单
  2. C/C++/动态链接库DLL中函数的调用约定与名称修饰
  3. k8s pod MySQL环境变量,如何使用Kubernetes的configmap通过环境变量注入到pod里
  4. 基于JAVA+SpringMVC+Mybatis+MYSQL的甜品店商城
  5. Python连接MySQL的实例代码
  6. 基于Fisher准则线性分类器设计
  7. 史上最全电脑优化小技巧
  8. 广义线性模型python
  9. database is locked错误
  10. Unity3D 关于材质球自发光_EmissionColor参数,构建后无法动态修改颜色值解决办法
  11. 一些linux和OpenGL的笔记
  12. Pycharm安装打包工具
  13. 如何在线合并视频?合并视频这样做
  14. 获取android 用到的所有开发包文件
  15. 绵阳现在买房怕房价跌,不买又怕房价涨!到底是跌是涨?
  16. webpack入门学习笔记10 —— 在项目中使用图片资源
  17. PLC是怎么工作和扫描的
  18. Linux7.5 安装mysql8.0.13教程
  19. 面试题一(计算机基础、逻辑)
  20. Python实现新版正方教务系统爬虫(二)

热门文章

  1. http访问不到服务器_HTTP及会话技术解析:大魏Java记4
  2. 微信机、网络和java的相关知识点
  3. 中文表示什么_越南水果摊贴出中文标语,看清文字内容后,中国游客:不再吃了...
  4. python读取字典元素笔记_python学习笔记:字典的使用示例详解
  5. html自动刷新 idea_IDEA设置热部署
  6. mybatis是什么_为什么SpringMVC可以正确解析方法参数名称,但MyBatis却不行?
  7. 双目摄像头 三维坐标 python_时间编码单像素三维成像:挑战三维成像的速度极限...
  8. 上下文保存 中断_Linux性能优化(CPU篇)(5)——CPU的上下文切换有几种类型?什么是进程上下文切换?...
  9. 【Centos 8】【Centos 7】【Docker】 安装 RabbitMQ
  10. java concurrency_GitHub - CL0610/Java-concurrency: Java并发知识点总结