一:图的遍历——深度优先搜索

在本文其他内容中只是大体概括了主要的图论内容,更加详细的代码实现及算法分析在此给出。

深度优先搜索(DFS)类似树的先序遍历。

假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可从图中某个顶点发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中阶和V有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问则另选图中一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

以下图为例,假设从V1出发开始搜索,在访问了V1之后选择邻接点V2,因为V2未被访问,

则从V2出发进行搜索。依次类推,接着从V4\V8V5出发进行搜索。在访问了V5之后,由于V5的邻接点都已被访问,则搜索回到V1。此时由于V1的另一个邻接点未被访问,则搜索又从V1到V3,再继续进行下去。由此,得到的顶点访问序列为:

V1->V2->V4->V8->V5->V3->V6->V7;
显然,这是一个递归的过程。为了在遍历过程中便于区分顶点是否已被访问需附设访问标志数组visited[n-1]其初值为false一 且某个顶点被访问,则其相应的分量置"true"。

具体代码用C语言实现如下:

 #include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函数结果状态代码 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */#define MAX_NAME 5 /* 顶点字符串的最大长度 */typedef int InfoType;typedef char VertexType[MAX_NAME]; /* 字符串类型 *//* 图的邻接表存储表示 */#define MAX_VERTEX_NUM 20typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */typedef struct ArcNode{int adjvex; /* 该弧所指向的顶点的位置 */struct ArcNode *nextarc; /* 指向下一条弧的指针 */InfoType *info; /* 网的权值指针) */}ArcNode; /* 表结点 */typedef struct{VertexType data; /* 顶点信息 */ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */}VNode,AdjList[MAX_VERTEX_NUM]; /* 头结点 */typedef struct{AdjList vertices;int vexnum,arcnum; /* 图的当前顶点数和弧数 */int kind; /* 图的种类标志 */}ALGraph;Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */void(*VisitFunc)(char* v); /* 函数变量(全局量) */void DFS(ALGraph G,int v){ /* 从第v个顶点出发递归地深度优先遍历图G。算法7.5 */int w;VertexType v1,w1;strcpy(v1,*GetVex(G,v));visited[v]=TRUE; /* 设置访问标志为TRUE(已访问) */VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,*GetVex(G,w))))if(!visited[w])DFS(G,w); /* 对v的尚未访问的邻接点w递归调用DFS */}void DFSTraverse(ALGraph G,void(*Visit)(char*)){ /* 对图G作深度优先遍历。算法7.4 */int v;VisitFunc=Visit; /* 使用全局变量VisitFunc,使DFS不必设函数指针参数 */for(v=0;v<G.vexnum;v++)visited[v]=FALSE; /* 访问标志数组初始化 */for(v=0;v<G.vexnum;v++)if(!visited[v])DFS(G,v); /* 对尚未访问的顶点调用DFS */printf("\n");}

二:广度优先搜索

广度优先搜索(BFS)遍历类似于树的层序遍历。

假设从图中某顶点V出发,在访问了V之后依次访问V的未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。换句话说广度优先搜索遍历图的过程是以V为起始点,由近至远.依次访问和V有路径相通且路径长度为1,2,...的顶点。
对上图得到的顶点访问序列为V1->V2->V3->V4->V5->V6->V7->v8。 

具体代码用C语言实现如下:

typedef int QElemType; /* 队列类型 *//* c3-2.h 单链队列--队列的链式存储结构 */typedef struct QNode{QElemType data;struct QNode *next;}QNode,*QueuePtr;typedef struct{QueuePtr front,rear; /* 队头、队尾指针 */}LinkQueue;
/* bo3-2.c 链队列(存储结构由c3-2.h定义)的基本操作(9个) */Status InitQueue(LinkQueue *Q){ /* 构造一个空队列Q */(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));if(!(*Q).front)exit(OVERFLOW);(*Q).front->next=NULL;return OK;}Status DestroyQueue(LinkQueue *Q){ /* 销毁队列Q(无论空否均可) */while((*Q).front){(*Q).rear=(*Q).front->next;free((*Q).front);(*Q).front=(*Q).rear;}return OK;}Status ClearQueue(LinkQueue *Q){ /* 将Q清为空队列 */QueuePtr p,q;(*Q).rear=(*Q).front;p=(*Q).front->next;(*Q).front->next=NULL;while(p){q=p;p=p->next;free(q);}return OK;}Status QueueEmpty(LinkQueue Q){ /* 若Q为空队列,则返回TRUE,否则返回FALSE */if(Q.front==Q.rear)return TRUE;elsereturn FALSE;}int QueueLength(LinkQueue Q){ /* 求队列的长度 */int i=0;QueuePtr p;p=Q.front;while(Q.rear!=p){i++;p=p->next;}return i;}Status GetHead_Q(LinkQueue Q,QElemType *e) /* 避免与bo2-6.c重名 */{ /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */QueuePtr p;if(Q.front==Q.rear)return ERROR;p=Q.front->next;*e=p->data;return OK;}Status EnQueue(LinkQueue *Q,QElemType e){ /* 插入元素e为Q的新的队尾元素 */QueuePtr p=(QueuePtr)malloc(sizeof(QNode));if(!p) /* 存储分配失败 */exit(OVERFLOW);p->data=e;p->next=NULL;(*Q).rear->next=p;(*Q).rear=p;return OK;}Status DeQueue(LinkQueue *Q,QElemType *e){ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */QueuePtr p;if((*Q).front==(*Q).rear)return ERROR;p=(*Q).front->next;*e=p->data;(*Q).front->next=p->next;if((*Q).rear==p)(*Q).rear=(*Q).front;free(p);return OK;}Status QueueTraverse(LinkQueue Q,void(*vi)(QElemType)){ /* 从队头到队尾依次对队列Q中每个元素调用函数vi()。一旦vi失败,则操作失败 */QueuePtr p;p=Q.front->next;while(p){vi(p->data);p=p->next;}printf("\n");return OK;}void BFSTraverse(ALGraph G,void(*Visit)(char*)){/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。算法7.6 */int v,u,w;VertexType u1,w1;LinkQueue Q;for(v=0;v<G.vexnum;++v)visited[v]=FALSE; /* 置初值 */InitQueue(&Q); /* 置空的辅助队列Q */for(v=0;v<G.vexnum;v++) /* 如果是连通图,只v=0就遍历全图 */if(!visited[v]) /* v尚未访问 */{visited[v]=TRUE;Visit(G.vertices[v].data);EnQueue(&Q,v); /* v入队列 */while(!QueueEmpty(Q)) /* 队列不空 */{DeQueue(&Q,&u); /* 队头元素出队并置为u */strcpy(u1,*GetVex(G,u));for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))if(!visited[w]) /* w为u的尚未访问的邻接顶点 */{visited[w]=TRUE;Visit(G.vertices[w].data);EnQueue(&Q,w); /* w入队 */}}}printf("\n");}

欢迎关注本博主

图的遍历——深度优先搜索+广度优先搜索相关推荐

  1. 6.1 图的深度优先和广度优先搜索

    图的广度优先搜索 图的的搜索算法主要分为广度优先搜索(breadth-first search或BFS)和深度优先搜索(depth-first search或DFS).首先讨论广度优先搜索算法. 称之 ...

  2. Python 实现图的深度优先和广度优先搜索

    在介绍 python 实现图的深度优先和广度优先搜索前,我们先来了解下什么是"图". 1 一些定义 顶点 顶点(也称为"节点")是图的基本部分.它可以有一个名称 ...

  3. 深度优先和广度优先搜索

    目录 前言 1 深度优先搜索 2 广度优先搜索 3 深度优先和广度优先的比较 前言 最近面试,被问到了深度优先和广度优先搜索,这个我似曾相识,曾经大学的时候学到过,但是由于这几年的工作都未接触到,所以 ...

  4. 深度优先搜索 广度优先搜索理解

    深度优先搜索广度优先搜索 1. 什么是 "搜索" 算法 我们知道,算法都是作用于某种具体的数据结构上的,而深度优先搜索算法和广度优先搜索算法就是作用于图这种数据结构的. 图上的搜索 ...

  5. 深度优先搜索广度优先搜索

    1 概述 算法是作用于具体的数据结构之上的,深度优先搜索算法和广度优先搜索算法都是基于图这种数据结构的.主要原因是因为图的这种数据结构表达能力很强,大部分涉及搜索的场景都可以抽象成图. 图上的搜索算法 ...

  6. 邻接矩阵的深度优先和广度优先搜索

    c语言中图的邻接矩阵的深度优先和广度优先搜索 #include<stdio.h> #include<stdlib.h> typedef struct {int vexs[7]; ...

  7. 数据结构(廿五) -- C语言版 -- 图 - 图的遍历 -- 邻接矩阵 - 深度/广度优先遍历/搜索(DFS、BFS)

    内容预览 零.读前说明 一.概 述 二.深度优先遍历(DFS) 2.1.无向图的遍历过程 2.2.有向图的遍历过程 2.3.总结说明 2.4.实现源代码 三.广度优先遍历(BFS) 3.1.广度优先的 ...

  8. 图的遍历——深度优先搜索和广度(宽度)优先搜索(含例题)

    专栏导读及目录https://blog.csdn.net/createprogram/article/details/86741044 深度优先搜索 DFS基本思想 基本步骤: 1.从图中某个顶点v0 ...

  9. 数据结构 图 简单入门 最小生成树 深度优先搜索 广度优先搜索

    早上上班路上,看到一则新闻,广州的.新闻说的是一个辅警在路边查过往路人的身份证,其中有一个记者,就询问,根据哪条法律要查询他的身份证.辅警当然不知道(事后据说,就是闲着无聊,查着玩的!),也肯定不会认 ...

最新文章

  1. 我有一个很好的思维习惯-反思
  2. 五分钟搞懂后缀数组!
  3. java查询数组中元素的索引
  4. mysql format 格式化 返回值
  5. string 转 json_手写Json解析器学习心得
  6. php如何只删去汉字,php如何删除字符串中的中文
  7. mysql中on关键字和where关键字
  8. 开发者论坛一周精粹(第六期):阿里B2B研发管理难题如何应对?打造强有力的技术中台...
  9. Python安装包下载、环境配置与工具包安装教程(详细版)
  10. 经典数据结构视频教程下载 (清华大学 严蔚敏)
  11. 高项_第六章项目进度管理
  12. Android network基础知识 — IPv4和IPv6的区别
  13. Shape Shifter——制作简单动画
  14. 运维审计系统是堡垒机么?跟堡垒机有啥区别?
  15. .vimrc快捷键设置
  16. 立波 iphone3gs越狱教程:成功把iphone3gs手机升级成ios6.1.3系统,完美越狱,解决no service和耗电量大的问题
  17. “脚本小子”和真正黑客的区别是什么?
  18. 我的挣扎 与 TBtools 的开发
  19. 1357. 路径总和 II
  20. vue 数组 unshift push shift pop

热门文章

  1. 产品狗,工作三年,转行AI应该怎样规划?
  2. go设置后端启动_为什么 Rubyists 应该考虑学习 Go
  3. linux开发板作为蓝牙音箱,USB 蓝牙适配器在ARM 开发板下的使用
  4. javascript犀牛书_犀牛书作者:最该忘记的JavaScript特性
  5. PackagesNotFoundError: The following packages are not available from current channels:
  6. LeetCode MySQL 626. 换座位
  7. LeetCode 1186. 删除一次得到子数组最大和(DP)
  8. 程序员面试金典 - 面试题 17.07. 婴儿名字(并查集)
  9. 程序员面试金典 - 面试题 08.11. 硬币(背包DP)
  10. LintCode 795. 4种独特的路径(DFS)