图的遍历:DFS和BFS
图的遍历一般由两者方式:深度优先搜索(DFS),广度优先搜索(BFS),深度优先就是先访问完最深层次的数据元素,而BFS其实就是层次遍历,每一层每一层的遍历。
1.深度优先搜索(DFS)
我一贯习惯有举例的方法来讲,示例如下:红色代表的是正搜索,蓝色代表回溯,最下面为标志数组。

注意:DFS的搜索出来的序列不是每个人都是一样的,根据具体的程序可能出现不同的顺序。
程序设计:由对深度优先搜索的理解,我们可以知道我们从根节点的开始向下搜索,注意题目中给出的是连通的图,在实际情况下可能有非连通的图,图中根节点v1的子节点为v2,v3,我们可以访问它的子节点按照从左到右也可以从右到左,我们这里选择从左到右的方向,先访问v2,访问v2后又以v2作为子节点开始从左到右访问,但是我们可能注意到访问到v5时,如果我们仅仅从图的相关节点的连通性来判断是否应该继续深入的话,我们会在v5节点形成一个环,从而造成程序的死循环,这里就需要一个标志数组来标志哪些节点是已经访问了的,这样不仅仅能够保证不形成环也可以为节点回溯提供保证。说到这里我们基本已经解决了连通图的DFS,我们主要到如果是非连通图我们不能通过子图的连通性来访问到所有的节点,所以下面一段代码就是必须的了;
for(i=0; i<n; i++)
if(!color[i])
{
printf(" V%d ", i+1);
DFS_Visit(G,i,n);
printf("\n");
}
这段代码从第一个节点测试到最后一个节点测试是否已经访问过,如果是非连通图,中间一定会有在第一次访问完成之后还有节点没有访问,所有利用标志数组就可以轻易的达到这个目的。
上图测试用例.txt
1 2
1 3
2 4
2 5
4 8
5 8
3 6
3 7
6 7
测试程序:
#include <stdio.h>
#include <string.h> const int GNumber = 8;
int G[GNumber][GNumber];
int color[GNumber]; void DFS_Visit(int G[][GNumber], int i, int n)
{
int j;
color[i] = 1; for(j=0; j< n; j++)
{
if(G[i][j] && !color[j])
{
printf(" V%d ", j+1);
color[j] = 1;
DFS_Visit(G, j, n);
}
} } void DFS(int G[][GNumber], int n)
{
int i;
memset(color, 0, sizeof(color)); for(i=0; i<n; i++)
{
if(!color[i])
{
printf(" V%d ", i+1);
DFS_Visit(G,i,n);
printf("\n");
}
} } int main()
{
FILE *fr;
int i,j;
fr = fopen("图的遍历测试用例.txt","r");
if(!fr)
{
printf("fopen failed\n");
return -1;
}
while(fscanf(fr,"%d%d", &i, &j) != EOF)
{
G[i-1][j-1] = 1;
G[j-1][i-1] = 1;
}
DFS(G,GNumber); getchar();
return 0;
}
程序结果:
V1 V2 V4 V8 V5 V3 V6 V7
请按任意键继续. . .
2.广度优先搜索(BFS)
示例如下:红色代表的是正搜索,最下面为标志数组。

程序设计:一个图如果要层次遍历的话,那么他应该是连通图,不然层次没法分,对一个连通图进行层次遍历,我们模拟一下就知道,如上图,当访问了v1节点后,我们就应该访问第二层都为它的子节点,我们这里以顺序从左到右访问,那么应该访问的是v2,v3,为了能够表示访问的顺序,我们这里设置一个先进先出的结构,很明显就是一个队列了,要访问前v1将它放入队列,然后访问v1,并将他的子节点放到队列中:v1,v2,v3;访问了v1后出队输出,我们继续访问队列中的元素,以队列中的元素为根节点找他的子节点并加入到队列中,知道队列为空。这里的标志数组标志着节点是否进入过队列,这里由于元素很少而且队列中的元素肯定不会超过顶点个数,所以我直接使用的数组来模拟队列。
测试程序:
#include <stdio.h>
#include <string.h> const int GNumber = 8;
int G[GNumber][GNumber];
int color[GNumber];// 防止回环 struct Queue//用数组模拟队列
{
int queue[GNumber];
int start;
int end;
}MyQueue; void BFS(int G[][GNumber], int n)
{
int j;
MyQueue.queue[MyQueue.end++] = 0;
color[0] = 1; /*
for(j=0; j<n; j++)
{
if(G[i][j] && !color[j])
{
printf(" V%d ", j+1);
color[j] = 1;
MyQueue.queue[MyQueue.end++] = j;
}
}
*/ while(MyQueue.end != MyQueue.start)
{
//color[MyQueue.start] = 1;
for(j=0; j<n; j++)
{
if(G[MyQueue.start][j] && !color[j])
{
color[j] = 1;
MyQueue.queue[MyQueue.end++] = j;
}
}
printf(" V%d ", MyQueue.queue[MyQueue.start++]+1);
}
} int main(int argc, char **argv)
{
FILE *fr;
int i,j;
fr = fopen("图的遍历测试用例.txt","r");
if(!fr)
{
printf("fopen failed\n");
return -1;
}
while(fscanf(fr,"%d%d", &i, &j) != EOF)
{
G[i-1][j-1] = 1;
G[j-1][i-1] = 1;
}
memset(&MyQueue, 0, sizeof(MyQueue));
memset(color, 0, sizeof(color)); BFS(G,GNumber); getchar();
return 0;
}
程序结果:
V1 V2 V3 V4 V5 V6 V7 V8 请按任意键继续. . .
图的遍历:DFS和BFS的更多相关文章
- 图的遍历——DFS和BFS模板(一般的图)
关于图的遍历,通常有深度优先搜索(DFS)和广度优先搜索(BFS),本文结合一般的图结构(邻接矩阵和邻接表),给出两种遍历算法的模板 1.深度优先搜索(DFS) #include<iostrea ...
- 图的遍历(DFS、BFS)
理论: 深度优先搜索(Depth_Fisrst Search)遍历类似于树的先根遍历,是树的先根遍历的推广: 广度优先搜索(Breadth_First Search) 遍历类似于树的按层次遍历的过程: ...
- 图的遍历DFS
图的遍历DFS 与树的深度优先遍历之间的联系 树的深度优先遍历分为:先根,后根 //树的先根遍历 void PreOrder(TreeNode *R){ if(R!=NULL){ visit(R); ...
- 图的遍历[DFS][BFS]
#include<iostream> #include<iostream> #include<cstring> #include<queue> #inc ...
- 图的遍历——DFS
原创 图的遍历有DFS和BFS两种,现选用DFS遍历图. 存储图用邻接矩阵,图有v个顶点,e条边,邻接矩阵就是一个VxV的矩阵: 若顶点1和顶点5之间有连线,则矩阵元素[1,5]置1,若是无向图[5, ...
- 图的遍历——DFS(矩形空间)
首先,这里的图不是指的我们一般所说的图结构,而是大小为M*N的矩形区域(也可以看成是一个矩阵).而关于矩形区域的遍历问题经常出现,如“寻找矩阵中的路径”.“找到矩形区域的某个特殊点”等等之类的题目,在 ...
- 图的遍历---DFS
类型一:邻接表 题目一:员工的重要性 题目描述 给定一个保存员工信息的数据结构,它包含了员工唯一的id,重要度 和 直系下属的id. 比如,员工1是员工2的领导,员工2是员工3的领导.他们相应的重要度 ...
- 图的遍历——DFS(邻接矩阵)
递归 + 标记 一个连通图只要DFS一次,即可打印所有的点. #include <iostream> #include <cstdio> #include <cstdli ...
- 16.boost图深度优先遍历DFS
#include <iostream> #include <boost/config.hpp> //图(矩阵实现) #include <boost/graph/adjac ...
- 图的数据结构的实现与遍历(DFS,BFS)
//图的存储结构:const int MAXSIZE = 10;//邻接矩阵template<class T>class MGraph {public: MGraph(T a[], ...
随机推荐
- Repository、IUnitOfWork 和 IDbContext
1)领域层不应该直接依赖于仓储实现:如果领域层依赖于仓储实现,一是技术绑定太紧密,二是仓储要对领域对象作操作,会造成循环依赖. 2)将接口定义在领域层,减少技术架构依赖,应用层或领域层要使用某个仓储实 ...
- Linux下(centos6.8)JDK1.8的安装与配置
今天说下在Linux(centos6.8)系统下的JDK安装与配置. 据我所知的jdk安装方式有三种(rpm.yum方式没用过,暂且不提)今天只说解压安装方式: 一.解压jdk安装包: 附上jdk1. ...
- java - day14 - InnerClass
内部类使用 package com.InnerClass; public class Mama { String name; Baby baby; Mama(String name){ this.na ...
- 使用pycharm手动搭建python语言django开发环境(四) django中buffer类型与str类型的联合使用
在django中,如果用到buffer类型时,buffer的编码格式是utf-8类型.使用str()进行转为字符串类型会异常. 异常会有如下提示:'ascii' codec can't decode ...
- Android学习之ItemTouchHelper实现RecylerView的拖拽以及滑动删除功能
今天在群里见大神们提到控件的拖动以及滑动删除的效果实现,就在网上找了资料ItemTouchHelper学习,并实现其功能.不胜窃喜之至,忍不住跟大家分享一下,如今就对学习过程做下简介.帮助大家实现这样 ...
- priority_queue优先队列/C++
priority_queue优先队列/C++ 概述 priority_queue是一个拥有权值观念的queue,只允许在底端加入元素,并从顶端取出元素. priority_queue带有权值观念,权值 ...
- 2017-5-14 湘潭市赛 Partial Sum 给n个数,每次操作选择一个L,一个R,表示区间左右端点,该操作产生的贡献为[L+1,R]的和的绝对值-C。 0<=L<R<=n; 如果选过L,R这两个位置,那么以后选择的L,R都不可以再选择这两个位置。最多操作m次,求可以获得的 最大贡献和。
Partial Sum Accepted : Submit : Time Limit : MS Memory Limit : KB Partial Sum Bobo has a integer seq ...
- 实体框架迁移,EntityFramework
主要就是这个:http://msdn.microsoft.com/zh-cn/data/jj591621.aspx 下面这个是写得不错的,比较详细: 首先打开工具--->>>库程序包 ...
- hdu 1534(差分约束+spfa求最长路)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1534 思路:设s[i]表示工作i的开始时间,v[i]表示需要工作的时间,则完成时间为s[i]+v[i] ...
- react 近期
ECMAScript 6 入门:http://es6.ruanyifeng.com/#docs/destructuring#%E6%95%B0%E7%BB%84%E7%9A%84%E8%A7%A3%E ...