一、广度优先遍历-BFS

顾名思义,BFS总是先访问完同一层的结点,然后才继续访问下一层结点,它最有用的性质是可以遍历一次就生成中心结点到所遍历结点的最短路径,这一点在求无权图的最短路径时非常有用。广度优先遍历的核心思想非常简单,用python实现起来也就十来行代码。下面就是超精简的实现,用来理解核心思想足够了:

1 importqueue2

3 defbfs(adj, start):4 visited =set()5 q =queue.Queue()6 q.put(start) #把起始点放入队列7 while notq.empty():8 u =q.get()9 print(u)10 for v inadj.get(u, []):11 if v not invisited:12 visited.add(v)13 q.put(v)14

15

16 graph = {1: [4, 2], 2: [3, 4], 3: [4], 4: [5]}17 bfs(graph, 1)

上面的代码:

1. 创建一个队列,遍历的起始点放入队列

2. 从队列中取出一个元素,打印它,并将其未访问过的子结点放到队列中

3. 重复2,直至队列空

时间复杂度:基本与图的规模成线性关系了,比起图的其它算法动不动就O(n^2)的复杂度它算是相当良心了

空间复杂度:我们看到程序中使用了一个队列,这个队列会在保存一层的结点,当图规模很大时占用内存还是相当可观的了,所以一般会加上一些条件,比如遍历到第N层就停止

关于图的理解的一个技巧

上面提到,BFS遍历会由近及远,同一层会先遍历完。这里随便提一个关于图的展示问题,或者说当你拿到一个图,当你要对它进行分析时,这个图在你的脑海里会一个什么形态呢?比较一下下面两种形态,你觉得哪一种更加清晰

其实你仔细看,上下两张图其实数据是一样的,只是布局不一样罢了,上面的图使用了一种无规律凌乱的布局,而下面假设出了一个中心点,将与它直接相连的结点放在第一层上,与它距离为2的结点放在第二层了,这样会有什么好处呢?好处就是这样布局后边只会在相邻层或者同一层间的结点间相连,这样就不会出现很长或者交叉的边了,整个图会感觉有序得多,在思考图的一些性质的时候也会清晰得多。

回过头来,这种布局不说是BFS形成的吗。

二、深度优先遍历-DFS

深度优先遍历算法DFS通俗的说就是“顺着起点往下走,直到无路可走就退回去找下一条路径,直到走完所有的结点”。这里的“往下走”主是优先遍历结点的子结点。BFS与DFS都可以完成图的遍历。DFS常用到爬虫中,下面是最精简的代码:

1 defdfs(adj, start):2 visited =set()3 stack =[[start, 0]]4 whilestack:5 (v, next_child_idx) = stack[-1]6 if (v not in adj) or (next_child_idx >=len(adj[v])):7 stack.pop()8 continue

9 next_child =adj[v][next_child_idx]10 stack[-1][1] += 1

11 if next_child invisited:12 continue

13 print(next_child)14 visited.add(next_child)15 stack.append([next_child, 0])16

17

18 graph = {1: [4, 2], 2: [3, 4], 3: [4], 4: [5]}19 dfs(graph, 1)

上面的代码是dfs的非递归实现,其实递归的代码更简单,但是我觉得使用了函数的递归调用隐含了对栈的使用但是却没有明确出来,这样不太利于对dfs核心思想的理解,所以这里反而选择了更复杂的非递归实现。

整个程序借助了一个栈,由于python没有直接的实现栈,这里使用了list来模拟,入栈就是向列表中append一个元素,出栈就是取列表最后一个元素然后pop将最后一个元素删除。

下面来分析实现过程,还是按之前的那句话“顺着起点往下走,直到无路可走就退回去找下一条路径,直到走完所有的结点”,整个程序都蕴含在这句话中:

首次是“顺着起点往下走”中的起点当然就是函数传进来的参数start,第三行中我们把起点放到了栈中,此时栈就是初始状态,其中就只有一个元素即起点。那么栈中元素表示的语义是:下一次将访问的结点,没错就这么简单,那么为什么我们一个结点和一个索引来表示呢?理由是这样的,由于我们使用邻接表来表示图,那么要表示一个结点表可以用<这个结点的父结点、这个结是父结点的第几个子结点>来决定,至于为什么要这么表示,就还是前面说的:由这们这里使用的图的存储方式-邻接表决定了,因为这样我们取第N个兄弟结点要容易了。因为邻接表中用list来表示一个结点的所有子结点,我们就用一个整数的索引值来保存下次要访问的子结点的list的下标,当这个下标超过子结点list的长度时意味着访问完所有子结点。

接着,“往下走”,看这句:next_child = adj[v][next_child_idx]就是我们在这个while循环中每次访问的都是一个子结点,访问完当前结点后stack.append([next_child, 0])将这个结点放到栈中,意思是下次就访问这个结点的子结点,这样就每次都是往下了。

“直到无路可走”,在程序中的体现就是 if (v not in adj) or (next_child_idx >= len(adj[v])):,栈顶元素表示即将要访问的结点的父结点及其是父结点的第N个子结点(有点绕),这里的意思是如果这个父结点都没有子结点了或者是我们想要访问第N个子结点但是父结点并没有这么多子结点,表示已经访问完了一个父结点的所有子结点了。

接着“就退回去找下一条路径”中的“退回去”,怎么退回去,很简单将栈顶元素弹出,新的栈顶元素就是它的父结点,那么就是退回去了,“去找下一条路径”就是弹出栈顶后下一次while中会沿着父结点继续探索,也就是去找下一条路径了。

最后“直到走完所有的结点“当然就是栈为空了,栈为空表示已经回退到起点,即所有结点已经访问完了,整个算法结束。

python 遍历_python实现图广度优先遍历、深度优先遍历相关推荐

  1. 【图数据结构的遍历】java实现广度优先和深度优先遍历

    [图数据结构的遍历]java实现广度优先和深度优先遍历 宽度优先搜索(BFS)遍历图需要使用队列queue数据结构: 深度优先搜索(DFS, Depth First Search)的实现 需要使用到栈 ...

  2. 三十二、图的创建深度优先遍历(DFS)广度优先遍历(BFS)

    一.图的基本介绍 为什么要有图 前面我们学了线性表和树 线性表局限于一个直接前驱和一个直接后继的关系 树也只能有一个直接前驱也就是父节点 当我们需要表示多对多的关系时, 这里我们就用到了图. 图的举例 ...

  3. 图的遍历(搜索)算法 之 深度优先遍历算法

    图的遍历的定义: 从图中的某个顶点出发访问遍图中的所有顶点,并且每个顶点仅仅被访问一次. 图的遍历算法我们常见的而且用的最多的就有两种:其一是图的深度优先遍历算法:其二是图的广度优先遍历算法.这里我们 ...

  4. 邻接矩阵存储图并进行深度优先遍历

    内容: 采用邻接矩阵的形式存储图,进行图的深度优先遍历 步骤: 算法分析: 首先,图的邻接矩阵存储结构,就是用一维数组存储图中顶点的信息,用矩阵表示图中各顶点之间的邻接关系.假设图G=(V,E)有n个 ...

  5. python 遍历_Python手撕广度优先遍历

    在谈广度优先遍历之前,我们需要知道图是什么. 1.图  图(graph)是表示物件与物件之间关系的数学对象,是图论的基本研究对象,图由节点(node)和边(edge)组成.图分为两种:1.有向图.2. ...

  6. python爬虫算法深度优先遍历_爬虫的广度优先和深度优先算法

    广度优先算法介绍 整个的广度优先爬虫过程就是从一系列的种子节点开始,把这些网页中的"子节点"(也就是超链接)提取出来,放入队列中依次进行抓取.被处理过的链接需要放 入一张表(通常称 ...

  7. 图 邻接矩阵的深度优先遍历

    void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) ) {//访问当前位置 然后递归寻找//当前访问的是V这个结点if (!Visited[ ...

  8. 图 深度优先遍历 广度优先遍历 非递归遍历 图解算法过程

    图的邻接矩阵表示 通常图的表示有两种方法:邻接矩阵,邻接表. 本文用邻接矩阵实现,一是代码量更少,二是代码风格也更贴近C语言.但不论是图的哪种实现方式,其基本的实现思想是不变的. 1:节点的信息,我们 ...

  9. C语言数据结构_图、图的深度优先遍历、广度优先遍历

    图 图是一种多对多的关系,可以有零个或多个直接前驱,也可以有零个或多个直接后驱.相较于线性表和树,图的结点可以是任意的,而线性表有头结点,只要知道了头结点,那么整个线性表就可以直接访问,树有根结点,可 ...

最新文章

  1. Mybatis源码阅读之三
  2. Oracle 优化器_表连接
  3. rpmdb open failed 的解决办法
  4. 让Team Foundation Server/TFS自动记住用户名密码解决方案
  5. pgsql thinkphp5_thinkphp 连接postgresql
  6. 【转】syslog服务和syslogd守护进程
  7. 2008版计算机基础,计算机应用基础2008版各章课后习题解析
  8. violate原理,java内存模型,可见性,cache二级内存模型
  9. 二级域名和一级域名的区别
  10. Apache Pulsar PMC 成员翟佳:开源和 Apache 社区是个带有魔法的宝库
  11. git基础教程(11) git checkout命令,掌握这些足以
  12. Unity中实现相机的跟随
  13. CRC循环冗余校验(计算机网络)
  14. 做好每周工作总结很重要
  15. 88-Spring Boot详解
  16. 计算机科学核心知识体系
  17. 小型水库雨水情测报和大坝安全监测
  18. 参考文献管理软件Jabref和Zotero使用笔记
  19. excel根据条件列转行_Excel列转行,80%的人不知道这个方法!
  20. 从大专生到蚂蚁金服CTO,他写下“支付宝”第一行代码:逆风的方向,更适合飞翔!...

热门文章

  1. 什么是聚簇索引与非聚簇索引(转)
  2. c语言版计算坐标方位角,C语言辛普森道路测量正反算,秒杀5800计算器
  3. PCB封装创建(CHIP类)
  4. 自己总结的故障分析及我这些年修电脑的经验
  5. Mybatis的mapper.xml文件对大于号和小于号进行处理
  6. 深度学习 --- 循环神经网络RNN详解(BPTT)
  7. Unit2-电梯调度
  8. 成为Java的Yoda大师应学的知识
  9. C语言 函数类型
  10. 剖析国内安卓应用市场 新商业逻辑能否上演“绝地求生”