C语言数据结构与算法之深度、广度优先搜索
一、深度优先搜索(Depth-First-Search 简称:DFS)
1.1 遍历过程:
(1)从图中某个顶点v出发,访问v。
(2)找出刚才第一个被顶点访问的邻接点。访问该顶点。以这个顶点为新的顶点,重复此步骤,直到访问过的顶点没有未被访问过的顶点为止。
(3)返回到步骤(2)中的被顶点v访问的,且还没被访问的邻接点,找出该点的下一个未被访问的邻接点,访问该顶点。
(4)重复(2) (3) 直到每个点都被访问过,遍历结束。
例无权图:(默认为字母顺序)
(1)从顶点A出发,访问该图
(2)A的邻接点为BEF 以B为顶点开始访问 B的邻接点有FDC
(3)B的所有的点均被访问结束,访问顶点C 顶点C还有F没有被访问
,结束遍历。
故遍历结果为 A->B->C->D->E->F
有向图:(默认为字母顺序)
(1)从顶点A出发,访问该图
(2)A 的出路顶点为B、D ,从顶点B 开始访问, B的出路只有E 结束此路;
(3)开始访问顶点D,D的出路为顶点C和F 此时所有顶点都被遍历了,结束;
故遍历结果为: A->B->E->D->C->F
1.2 算法描述
自然语言:从图中的某个顶点v出发,访问v,并将visited[v]的值为true。
一次检查v的所有邻接点w,如果visited[w]的值为flase,再从w出发进行递归遍历,直到图中的所有顶点都被访问过。
伪代码:
递归算法:
visited[MVNum] <-- false
count<--v,visited[v]<--true;
for(w<--FirstAdjVex(G,v);w>=0;w<--NextAdjVex(G,v,w))
if(!visited[w] DFS[G,w]);
采用邻接矩阵表示:
//输入图G(V,E),w表示v的邻接点
//输出邻接矩阵
count<--v; visited[v]<--true;
for(w<--0;w<G.vexnum;w++)
if( (G.arcs[v][w]!=0)&&(!visited[w]) )
DFS(G,w);
采用邻接表:
count<--v; visited[v]<--true;
p<--G.vertices[v].firstarc;
while(p!=NULL) do
w<--p->adjvex;
if(!visited[w]) do DFS(G,w)
p<-- p->nextarc;
1.3用途:检查图的连通性和无环性
1.4总结:每个顶点至多进一次队列。遍历图的过程实质上市通过边找邻接点的过程。因此DFS时间复杂度,当用邻接矩阵表示图时为O(n2),其中n为图中的顶点数,当以邻接表做图的存储结构时,时间复杂度为O(e)这里e为 图中的边数,因此,当以邻接表为存储结构时,DFS时间复杂度为O(n+e)。
二、广度优先搜索(Breadth-First-Search 简称:BFS)
2.1遍历过程如下:
(1)从图中某个顶点v出发,访问v。
(2)依次访问v邻接各个未访问过的的所有顶点
(3)接着从这些邻接顶点中继续访问它们的邻接顶点,遵循原则 先被访问的顶点的邻接点 先于 后被访问的顶点的邻接点 被访问。重复(3)步骤,直至所有的顶点都被访问过。
这里的“先被访问的顶点的邻接点 ”指的是在第二步骤先访问的顶点然后再先访问他的邻接点,包括后来的第三步骤也是这个意思,均为上一步骤 先访问的顶点然后再先访问他的邻接点。
例:图还是上面的那张无权图
我们按照字母ABCDEF这样的顺序来排列
(1)以A为顶点,开始遍历
(2)A的三个邻接点BEF
(3)根据字母顺序 从点B开始访问 B的临界点有CD 此时,所有的顶点均被访问
故,遍历后的结果为 A ->B-> E-> F-> C-> D
若为有向图
(1)根据字母顺序,先从顶点A开始访问
(2)看顶点A的出路,邻接点为B,D 。根据字母顺序,下一个顶点从B开始
(3)顶点B的出路为E ,且E没有出路了,故此路结束
(4)回到和B点同一级的 还有顶点D还没有被访问 D的出路有两条,分别为邻接点C 和F ,此时所有的顶点都被访问过。
故 遍历后的顺序为 A->B->D->E->C->F
2.2算法描述
自然语言:从图 中的某个顶点v出发,访问v,并将visited[v]的值为true,然后将v进队
只要队列不空,则重复下述处理:
队头顶点u出队
依次检查u的所有邻接点w,如果visited[w]的值为false,则访问w,并将visited[w]的数值为true,然后将w入队;
伪代码: //BFS算法描述
//输入:图G=<V,E>
//输出:图G的BFS遍历后的先后次序
visited[v] <--true
InitQueue(Q);
EnQueue(Q,v);
while(!QueueEmpty(Q)) do
DeQueue(Q,u);
for(w <--FirstAdjVex(G,u);w>=0;w<--NextAdjVex(G,u,w))
if(!visited[w]) do
count<<w; visited[w] <--true;
EnQueue(Q,w);
2.3用途:计算最短路径问题
2.4.总结:每个顶点至多进一次队列。遍历图的过程实质上市通过边找邻接点的过程。因此BFS时间复杂度,当用邻接矩阵表示图时为O(n2),其中n为图中的顶点数,当以邻接表做图的存储结构时,时间复杂度为O(e)这里e为 图中的边数,因此,当以邻接表为存储结构时,BFS时间复杂度为O(n+e)。
具体的代码实现如下所示:
#include<stdio.h>
#define N 20
#define TRUE 1
#define FALSE 0
int visited[N]; /*访问标志数组*/
typedef struct /*队列的定义*/
{
int data[N];
int front,rear;
}queue; typedef struct /*图的邻接矩阵*/
{
int vexnum,arcnum;
char vexs[N];
int arcs[N][N];
}
graph; void createGraph(graph *g); /*建立一个无向图的邻接矩阵*/
void dfs(int i,graph *g); /*从第i个顶点出发深度优先搜索*/
void tdfs(graph *g); /*深度优先搜索整个图*/
void bfs(int k,graph *g); /*从第k个顶点广度优先搜索*/
void tbfs(graph *g); /*广度优先搜索整个图*/
void init_visit(); /*初始化访问标识数组*/ /*建立一个无向图的邻接矩阵*/
void createGraph(graph *g)
{
int i,j;
char v;
g->vexnum=;
g->arcnum=;
i=;
printf("\n输入顶点序列(以#结束):\n");
while ((v=getchar())!='#')
{
g->vexs[i]=v; /*读入顶点信息*/
i++;
}
g->vexnum=i; /*顶点数目*/
for (i=;i<g->vexnum;i++) /*邻接矩阵初始化*/
for (j=;j<g->vexnum;j++)
g->arcs[i][j] = ;/*(1)-邻接矩阵元素初始化为0*/
printf("\n输入边的信息(顶点序号,顶点序号),以(-1,-1)结束:\n");
scanf("%d,%d",&i,&j); /*读入边(i,j)*/
while (i!=-) /*读入i为-1时结束*/
{
g->arcs[i][j] = ; /*(2)-i,j对应边等于1*/
g->arcnum++;
scanf("%d,%d",&i,&j);
}
}/* createGraph */ /*(3)---从第i个顶点出发深度优先搜索,补充完整算法*/
void dfs(int i,graph *g)
{
int j;
printf("%c", g->vexs[i]);
visited[i] = TRUE;
for (j = ; j < g->vexnum; j++)
if (g->arcs[i][j] == && !visited[j])
dfs(j, g);
}/* dfs */ /*深度优先搜索整个图*/
void tdfs(graph *g)
{
int i;
printf("\n从顶点%C开始深度优先搜索序列:",g->vexs[]);
for (i=;i<g->vexnum;i++)
if (visited[i] != TRUE) /*(4)---对尚未访问过的顶点进行深度优先搜索*/
dfs(i,g);
printf("\n");
}/*tdfs*/ /*从第k个顶点广度优先搜索*/
void bfs(int k,graph *g)
{
int i,j;
queue qlist,*q;
q=&qlist;
q->rear=;
q->front=;
printf("%c",g->vexs[k]);
visited[k]=TRUE;
q->data[q->rear]=k;
q->rear=(q->rear+)%N;
while (q->rear!=q->front) /*当队列不为空,进行搜索*/
{
i=q->data[q->front];
q->front=(q->front+)%N;
for (j=;j<g->vexnum;j++)
if ((g->arcs[i][j]==)&&(!visited[j]))
{
printf("%c",g->vexs[j]);
visited[j]=TRUE;
q->data[q->rear] = j; /*(5)---刚访问过的结点入队*/
q->rear = (q->rear + ) % N; /*(6)---修改队尾指针*/
}
}
}/*bfs*/ /*广度优先搜索整个图*/
void tbfs(graph *g)
{
int i;
printf("\n从顶点%C开始广度优先搜索序列:",g->vexs[]);
for (i=;i<g->vexnum;i++)
if (visited[i]!=TRUE)
bfs(i,g); /*从顶点i开始广度优先搜索*/
printf("\n");
}/*tbfs*/ void init_visit() /*初始化访问标识数组*/
{
int i;
for (i=;i<N;i++)
visited[i]=FALSE;
} int main()
{
graph ga;
int i,j;
printf("***********图邻接矩阵存储和图的遍历***********\n");
printf("\n1-输入图的基本信息:\n");
createGraph(&ga);
printf("\n2-无向图的邻接矩阵:\n");
for (i=;i<ga.vexnum;i++)
{
for (j=;j<ga.vexnum;j++)
printf("%3d",ga.arcs[i][j]);
printf("\n");
}
printf("\n3-图的遍历:\n");
init_visit(); /*初始化访问数组*/
tdfs(&ga); /*深度优先搜索图*/
init_visit();
tbfs(&ga); /*广度优先搜索图*/
return ;
}
运行结果(输入的为本节中一直用到的无向图)
深度和广度查找不同之处在于对顶点的访问顺序不同。
第一次写博客,应该还是有点问题的(虽然也查了一些资料~.~)
参考资料:
《数据结构(C语言版)》 严蔚敏 李冬梅 吴伟民著 人民邮电出版社
《程序设计中实用的数据结构 》 王建德 吴永辉著 人民邮电出版社
C语言数据结构与算法之深度、广度优先搜索的更多相关文章
- python数据结构与算法——图的广度优先和深度优先的算法
根据维基百科的伪代码实现: 广度优先BFS: 使用队列,集合 标记初始结点已被发现,放入队列 每次循环从队列弹出一个结点 将该节点的所有相连结点放入队列,并标记已被发现 通过队列,将迷宫路口所有的门打 ...
- 算法竞赛——BFS广度优先搜索
BFS 广度优先搜索:一层一层的搜索(类似于树的层次遍历) BFS基本框架 基本步骤: 初始状态(起点)加到队列里 while(队列不为空) 队头弹出 扩展队头元素(邻接节点入队) 最后队为空,结束 ...
- Leetcode之深度+广度优先搜索(DFS+BFS)专题-934. 最短的桥(Shortest Bridge)
Leetcode之广度优先搜索(BFS)专题-934. 最短的桥(Shortest Bridge) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary ...
- [C语言] 数据结构-衡量算法的标准
1.衡量算法的标准 算法 解题的方法和步骤 衡量算法的标准 1.时间复杂度 大概程序要执行的次数,而非执行的时间,不同的机器运行时间肯定不一样. 2.空间复杂度 算法执行过程中大概所占用的最大内存 3 ...
- c语言数据结构和算法库--cstl---王博--相关网站和博客
1.官网 http://libcstl.org/download.html 2.下载地址 http://www.pudn.com/downloads171/sourcecode/os/detail79 ...
- python数据结构与算法
最近忙着准备各种笔试的东西,主要看什么数据结构啊,算法啦,balahbalah啊,以前一直就没看过这些,就挑了本简单的<啊哈算法>入门,不过里面的数据结构和算法都是用C语言写的,而自己对p ...
- 为什么我要放弃javaScript数据结构与算法(第九章)—— 图
本章中,将学习另外一种非线性数据结构--图.这是学习的最后一种数据结构,后面将学习排序和搜索算法. 第九章 图 图的相关术语 图是网络结构的抽象模型.图是一组由边连接的节点(或顶点).学习图是重要的, ...
- 用python语言讲解数据结构与算法
写在前面的话:关于数据结构与算法讲解的书籍很多,但是用python语言去实现的不是很多,最近有幸看到一本这样的书籍,由Brad Miller and David Ranum编写的<Problem ...
- 数据结构C语言版 弗洛伊德算法实现
/* 数据结构C语言版 弗洛伊德算法 P191 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h>#include <limits.h> # ...
随机推荐
- Oracle 检查表的数据变动
本知识点仅适用于Oracle 9i以上的版本. 查看表的数据变动情况请使用SQL语句:select * from user_tab_modifications; user_tab_modificati ...
- Javascript 中 true 和 false
"" == false // true "0" == false // true "" == "0" //false 以 ...
- Java学习---Excel读写操作
1.1.1. 简介 Apache POI 使用Apache POI 完成Excel读写操作 Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API ...
- Connection to linux server with ORACLE SQL DEVELOPER
1.Link name is random 2.username and password is database account 3.host name is ip address ifconf ...
- Using shared access signatures (SAS) From Microsoft
A shared access signature (SAS) provides you with a way to grant limited access to objects in your s ...
- December 28th 2016 Week 53rd Wednesday
Knowledge is a treasure, but practice is the key to it. 知识是珍宝,而实践是获取她的钥匙. I know a lot, but what I r ...
- ab 压测工具使用
转自:http://www.cnblogs.com/lemtree/articles/1676641.html 就是APACHE自带的测试工具AB(apache benchmark).在APACHE的 ...
- ZT --- extern "C"用法详解 2010-08-21 19:14:12
extern "C"用法详解 2010-08-21 19:14:12 分类: C/C++ 1.前言: 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus ...
- iOS自动化-iOS录屏xrecord及解决iPhone设备不显示的问题
github地址:https://github.com/WPO-Foundation/xrecord 安装方法: git clone https://github.com/WPO-Foundation ...
- eclipse 自动生成get/set方法
Shift+Alt+S 会弹出一个对话框 选择Generate Getters and Setters