图的遍历(BFS、DFS)
前文使用邻接矩阵法和邻接链表法实现了图结构(MatrixGraph 、ListGraph ),本节使用两种算法进行图的遍历
目录
1、定义与概括
2、广度优先搜索算法
3、深度优先搜索算法
4、小结
1、定义与概括
图的遍历:从图中的某一顶点出发,沿着一些边访问图中的其它顶点,使得每个顶点最多被访问一次
注意:从某个顶点出发进行遍历,不一定能够访问到图中的所有顶点
图的遍历方式
-广度优先搜索(Breadth First Search)
☛ 以二叉树层次遍历的思想对图进行遍历
-深度优先搜索(Depth First Search)
☛ 以二叉树先序遍历的思想对图进行遍历
2、广度优先搜索算法
广度优先(BFS)
-按层次对图中的顶点进行访问
算法思路
-原料: class LinkQueue<T>;
- 步骤
1. 将起始顶点压入队列中
2. 队头顶点v弹出,判断是否已经标记(标记:转2, 未标记:转3)
3. 标记顶点 v ,并将顶点 v 的邻接顶点压入队列中
4 判断队列是否为空(非空:转2, 空:结束)
广度优先算法示例
编程实验
广度优先算法 Graph::BFS
Graph.h
// V:与顶点相关联数据元素类型,E:与边相关联数据元素(权值)类型
template < typename V, typename E >
class Graph : public Object
{
protected:/* 将队列转换为数组 */template < typename T >DynamicArray<T>* toArray(LinkQueue<T>& queue){DynamicArray<T>* ret = new DynamicArray<T>(queue.length());if( ret ){for(int i=0; i<ret->length(); i++, queue.remove()){ret->set(i, queue.front());}}else{THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create ret object ...");}return ret;}public:// ...SharedPointer< Array<int> > BFS(int i){DynamicArray<int>* ret = NULL;if((0 <= i) && (i < vCount())){LinkQueue<int> q;LinkQueue<int> r;DynamicArray<bool> visited(vCount());for(int k=0; k<visited.length(); k++){visited[k] = false;}q.add(i); // 往q队列加入初始顶点while(q.length() > 0){int v = q.front(); // 将队列头部的顶点拿出来q.remove();if( !visited[v] ) // 没有被访问过{SharedPointer< Array<int> > aj = getAdjacent(v); // 获取v顶点邻接顶点放到数组里for(int j=0; j<aj->length(); j++){q.add((*aj)[j]); // 将邻接顶点放到q队列}r.add(v); // 将v放到return队列visited[v] = true; // 标记该顶点已被访问过}}ret = toArray(r);}else{THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ...");}return ret;}};
main.cpp
#include <iostream>
#include "MatrixGraph.h"using namespace std;
using namespace DTLib;int main()
{MatrixGraph<9, char, int> g;const char* VD = "ABEDCGFHI";for(int i=0; i<9; i++){g.setVertex(i, VD[i]);}g.setEdge(0, 1, 0);g.setEdge(1, 0, 0); // 有向图表示无向图,权值0代表无权值g.setEdge(0, 3, 0);g.setEdge(3, 0, 0);g.setEdge(0, 4, 0);g.setEdge(4, 0, 0);g.setEdge(1, 2, 0);g.setEdge(2, 1, 0);g.setEdge(1, 4, 0);g.setEdge(4, 1, 0);g.setEdge(2, 5, 0);g.setEdge(5, 2, 0);g.setEdge(3, 6, 0);g.setEdge(6, 3, 0);g.setEdge(4, 6, 0);g.setEdge(6, 4, 0);g.setEdge(6, 7, 0);g.setEdge(7, 6, 0);g.setEdge(7, 8, 0);g.setEdge(8, 7, 0);SharedPointer< Array<int> > sa = g.BFS(0);for(int i=0; i<sa->length(); i++){cout << (*sa)[i] << " "; // 0 1 3 4 2 6 5 7 8}return 0;
}
3、深度优先搜索算法
深度优先(DFS)
深度优先算法 (方法一)
-原料: class LinkStack<T>;
-步骤
1. 将起始顶点压入栈中
2. 弹出栈顶顶点 v, 判断是否已经标记(标记:转2, 未标记:转3)
3. 标记顶点,并将顶点 v 的邻接顶点压入栈中
4. 判断栈是否为空(非空:转2, 空:结束)
深度优先算法示例
编程实验
深度优先算法 Graph::DFS
Graph.h
SharedPointer< Array<int> > DFS(int i){DynamicArray<int>* ret = NULL;if((0 <= i) && (i < vCount())){LinkStack<int> s;LinkQueue<int> r;DynamicArray<bool> visited(vCount());for(int j=0; j<visited.length(); j++){visited[j] = false;}s.push(i);while(s.size() > 0){int v = s.top();s.pop();if( !visited[v] ){SharedPointer< Array<int> > aj = getAdjacent(v);for(int j=aj->length()-1; j>=0; j--){s.push((*aj)[j]); // 最先获取到的邻接顶点最后入栈,最先出栈}r.add(v);visited[v] = true;}}ret = toArray(r);}else{THROW_EXCEPTION(NoEnoughMemoryException, "Index i is invalid ...");}return ret;}
main.cpp
#include <iostream>
#include "MatrixGraph.h" using namespace std;
using namespace DTLib; int main()
{ MatrixGraph<9, char, int> g; const char* VD = "ABEDCGFHI"; for(int i=0; i<9; i++) { g.setVertex(i, VD[i]); } g.setEdge(0, 1, 0); g.setEdge(1, 0, 0); // 有向图表示无向图,权值0代表无权值 g.setEdge(0, 3, 0); g.setEdge(3, 0, 0); g.setEdge(0, 4, 0); g.setEdge(4, 0, 0); g.setEdge(1, 2, 0); g.setEdge(2, 1, 0); g.setEdge(1, 4, 0); g.setEdge(4, 1, 0); g.setEdge(2, 5, 0); g.setEdge(5, 2, 0); g.setEdge(3, 6, 0); g.setEdge(6, 3, 0); g.setEdge(4, 6, 0); g.setEdge(6, 4, 0); g.setEdge(6, 7, 0); g.setEdge(7, 6, 0); g.setEdge(7, 8, 0); g.setEdge(8, 7, 0); SharedPointer< Array<int> > sa = g.DFS(0); for(int i=0; i<sa->length(); i++) { cout << (*sa)[i] << " "; } return 0;
}
问题 :如何使用二叉树先序遍历的思想遍历图?
递归版深度优先(方法二)
-原图 被划分为 起始顶点 和 子图 G',深度优先遍历原图 就是先访问 再 深度优先遍历子图
定义功能: DFS(graph, vex)
功能: 以顶点 vex 为起始顶点深度优先遍历 graph
编程实验
递归版深度优先算法 DFS(graph, vex)
#include <iostream>
#include "MatrixGraph.h" using namespace std;
using namespace DTLib; template < typename V, typename E >
void DFS(Graph<V, E>& g, int v, Array<bool>& visited)
{ if((0 <= v) && (v < g.vCount())) { cout << v << endl; visited[v] = true; SharedPointer< Array<int> > aj = g.getAdjacent(v); for(int i=0; i<aj->length(); i++) // v 没有邻接顶点就不会递归调用 { if( !visited[(*aj)[i]]) { DFS(g, (*aj)[i], visited); // 从邻接顶点开始深度优先遍历子图 } } } else { THROW_EXCEPTION(InvalidParameterException, "Index v is invalid ..."); }
} template < typename V, typename E >
void DFS(Graph<V, E>& g, int v)
{ DynamicArray<bool> visited(g.vCount()); for(int i=0; i<visited.length(); i++) { visited[i] = false; } DFS(g, v, visited);
} int main()
{ MatrixGraph<9, char, int> g; const char* VD = "ABEDCGFHI"; for(int i=0; i<9; i++) { g.setVertex(i, VD[i]); } g.setEdge(0, 1, 0); g.setEdge(1, 0, 0); // 有向图表示无向图,权值0代表无权值 g.setEdge(0, 3, 0); g.setEdge(3, 0, 0); g.setEdge(0, 4, 0); g.setEdge(4, 0, 0); g.setEdge(1, 2, 0); g.setEdge(2, 1, 0); g.setEdge(1, 4, 0); g.setEdge(4, 1, 0); g.setEdge(2, 5, 0); g.setEdge(5, 2, 0); g.setEdge(3, 6, 0); g.setEdge(6, 3, 0); g.setEdge(4, 6, 0); g.setEdge(6, 4, 0); g.setEdge(6, 7, 0); g.setEdge(7, 6, 0); g.setEdge(7, 8, 0); g.setEdge(8, 7, 0); SharedPointer< Array<int> > sa = g.DFS(0); for(int i=0; i<sa->length(); i++) { cout << (*sa)[i] << " "; } DFS(g, 0); return 0;
}
4、小结
广度优先按照 “层次的方式” 对顶点进行访问
广度优先算法的核心是队列的使用
深度优先按照“先序遍历的方式”对顶点进行访问
深度优先算法的核心是栈的使用
深度优先和广度优先的唯一不同在于栈或队列的使用
深度优先算法可以使用递归的方式实现
图的遍历(BFS、DFS)相关推荐
- LeetCode 547. 朋友圈(图的遍历BFS DFS)
文章目录 1. 题目 2. 解题 2.1 BFS 广度优先 2.2 DFS 深度优先 1. 题目 问有几个连通网络 2. 解题 2.1 BFS 广度优先 参考图的数据结构 class Solution ...
- 【数据结构笔记21】图的遍历,DFS与BFS,连通图
本次笔记内容: 6.2.1 图的遍历 - DFS 6.2.2 图的遍历 - BFS 6.2.3 图的遍历 - 为什么需要两种遍历 6.2.4 图的遍历 - 图连不通怎么办? 文章目录 深度优先搜索(D ...
- 7.9模拟赛T1图的遍历(dfs)
图的遍历(dfs) [题目描述] 对于一个有向图G来说,我们存在一个经典的遍历算法,就是DFS (深度优先搜索遍历).将G以1号点为起点进行DFS后,我们可以 得到G的一棵DFS遍历树T.就此,我们可 ...
- 图的遍历 BFS遍历(深学思维)
前言: 这篇文章还是是为了帮助一些 像我这样的菜鸟 找到简单的题解 问题描述: 马上到寒假了,JXY准备去n大城市游玩.这些城市之间有些有航线,有些没有.由于JXY特别懒,现在他想请一个更蒟蒻的人AY ...
- 【图的存储(二维数组方法)+图的遍历(dfs)】案例6-1.3 哥尼斯堡的“七桥问题”
欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录) 文章字体风格: 红色文字表示:重难点 蓝色文字表示:思路以及想法 图的存储+遍历+度的判断 处 ...
- 数据结构 笔记:图的遍历(DFS)
深度优先(DFS) 深度优先算法 -原料:class LinkStack<T>; -步骤: -将起始顶点压入栈中 -弹出栈顶顶点v,判断是否已经标记(标记:转2,为标记:转3) -标记顶点 ...
- 刷题笔记(十四)--二叉树:层序遍历和DFS,BFS
目录 系列文章目录 前言 题录 102. 二叉树的层序遍历 BFS DFS_前序遍历 107. 二叉树的层序遍历 II BFS DFS 199. 二叉树的右视图 BFS DFS 637. 二叉树的层平 ...
- python 遍历_python实现图广度优先遍历、深度优先遍历
一.广度优先遍历-BFS 顾名思义,BFS总是先访问完同一层的结点,然后才继续访问下一层结点,它最有用的性质是可以遍历一次就生成中心结点到所遍历结点的最短路径,这一点在求无权图的最短路径时非常有用.广 ...
- python回溯方法的模板_实例讲解Python基于回溯法子集树模板实现图的遍历功能
这篇文章主要介绍了Python基于回溯法子集树模板实现图的遍历功能,结合实例形式分析了Python使用回溯法子集树模板针对图形遍历问题的相关操作技巧与注意事项,需要的朋友可以参考下 本文实例讲述了Py ...
- 数据结构与算法(7-2)图的遍历(深度优先遍历DFS、广度优先遍历BFS)(分别用邻接矩阵和邻接表实现)
目录 深度优先遍历(DFS)和广度优先遍历(BFS)原理 1.自己的原理图 2.官方原理图 一.邻接矩阵的深度优先遍历(DFS) 1.原理图 2. 过程: 3.总代码 二.邻接表的深度优先遍历(DFS ...
最新文章
- css中position的几个值
- java读取excel并替换占位符_正则表达式 – 有没有一种简单的方法来替换Excel中的占位符?...
- Android与JS混编(js调用android相机扫描二维码)
- oracle count null 0,oracle count()函数对null值的处理
- Linux 下如何安装软件?
- mysql的几种插入语句_Mysql 几种常见的插入 Insert into,Replace Into,Insert ignore
- 【UVA - 1335】Beijing Guards (贪心,二分)
- 人工智能 深度学习(Deep learning)开源框架
- volatile工作原理学习总结
- oracle lgt,第 2 章 Fortran 95 内函数
- samkoon触摸屏用什么软件编程_samdraw3.3软件下载
- Sonic 开源移动端云真机测试平台 - 用例编写与回放流程实例演示,任务定时执行、图像相似度定位、公共步骤、公共参数、测试套件等
- 常用邮箱SMTP、POP3域名及其端口号
- 太阳能供电锂电充电IC
- 34、CSS高频前端面试题之CSS基础
- 追加审批人样式html,更新 | 你的审批打印模板真丑!看别人用html模板怎么玩
- vs java_VSCode搭建Java开发运行环境
- Scrum 项目 3.0
- 飞利浦linux手机,飞利浦手机768
- visit 安装说明
热门文章
- Amoeba数据库代理 实现mysql读写分离
- Java多线程-实现Callable接口的call()方法,示例
- linux给红米note4x刷机,红米Note4X 刷机LineageOs 14.1全过程讲解
- Mysql创建多表视图view
- java共享锁和排他锁的区别_排他锁和共享锁分别是什么?有什么不同?
- 【华为中央硬件部】最新社会招聘公告!
- Hank Paulson Is A National Hero
- Android自定义library上传到JitPack
- 服务器系统浏览器打不开,W7系统浏览器打不开怎么办
- Linux实用的快捷键