前言
图的遍历是一个非常重要的知识点,今天花几分钟时间帮助大家彻底解决图的两种遍历
图的深度优先遍历(DFS)
算法流程
我们借助一张图来理解
首先采取我们之前学的建立邻接表的方法存储这个图,什么才是深度优先遍历呢?
1.例如从V1出发,我们找到V1为头结点的单链表,看看指针下一个指向的是2
(2是指哪一个顶点在数组中下标为2)很明显是V2,我们就遍历到了V2
2.来到V2所在单链表发现1遍历过了(使用visit数组判断)那就跳过,看下一个,发现4没有遍历,那么就到了V4,以此类推…
代码实现
step1.构造邻接表存储图
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define Max 20
static int visit[Max];//遍历所有顶点,每个顶点只访问一次,该数组就是用于确定顶点Vi是否被访问
//若visit[Vi]==0,则未访问,为1则已经访问过了,以后不再访问
typedef struct ArcNode {//边结点
int adjvex;//顶点在数组中的下标
struct ArcNode* nextarc;//指向下一条边的指针
}ArcNode;
typedef struct VNode {
int data;
struct VNode* firstarc;
}AdjList[Max];
typedef struct {
AdjList vertices;//定义一个结点类数组,存放顶点
int vexnum;//顶点数
int arcnum;//边数
}ALGraph;
step2.初始化邻接表
void InitGraph(ALGraph* G, int vexnum, int arcnum) {
G->vexnum = vexnum;
G->arcnum = arcnum;
for (int i = 0; i < G->vexnum; i++) {
scanf("%d", &G->vertices[i].data);//顶点数据初始化
G->vertices[i].firstarc = NULL;//防止出现野指针问题
}
for (int i = 0; i < G->arcnum; i++) {
int v1 = 0;//每一条边关联两个顶点
int v2 = 0;
scanf("%d%d", &v1, &v2);
int i = LocateVex(G, v1);//确定两个顶点在顶点数组中的位置
int j = LocateVex(G, v2);
ArcNode* newNode1 = (ArcNode*)malloc(sizeof(ArcNode));
newNode1->adjvex = i;
newNode1->nextarc = G->vertices[j].firstarc;//头插法
G->vertices[j].firstarc = newNode1;
//对称
ArcNode* newNode2 = (ArcNode*)malloc(sizeof(ArcNode));
newNode2->adjvex = j;
newNode2->nextarc = G->vertices[i].firstarc;
G->vertices[i].firstarc = newNode2;
}
}
step3.实现LocateVex函数
int LocateVex(ALGraph* G, int u)//查找顶点在顶点数组中的下标
{
/* 初始条件: 图G存在,u和G中顶点有相同特征*/
/* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
for (int i = 0; i < G->vexnum; ++i) {
if (u == (G->vertices[i].data)) {
return i;
}
}
return -1;
}
step4.实现深度优先遍历算法
1.visit数组可以表示当前结点是否访问过
2.深度优先遍历主要是采取递归的方式来遍历
void DFS(ALGraph* G, int v) {//v为遍历的第一个结点在顶点数组中的下标
visit[v] = 1;//遍历过该节点,则置为1
printf("%d ", G->vertices[v].data);//打印当前结点的值
ArcNode* q = G->vertices[v].firstarc;
while (q != NULL) {
if (visit[q->adjvex] == 0) {//若未访问过该节点,那就递归
DFS(G, q->adjvex);
}
q = q->nextarc;
}
}
step5.main函数测试
int main() {
int vexnum;
int arcnum;
int v;
scanf("%d%d", &vexnum, &arcnum);
ALGraph* G = (ALGraph*)malloc(sizeof(ALGraph));
InitGraph(G, vexnum, arcnum);
scanf("%d", &v);
printf("===============\n");
DFS(G, LocateVex(G, v));
return 0;
}
8 个顶点 9 条边
顶点值依次为0…7
0 2表示0和2有公共边,以此类推
最后一行0表示从0开始深度优先遍历
图的广度优先遍历(BFS)
代码几乎和深度优先遍历一样,唯一不同的点就在于BFS函数的实现
void BFS(ALGraph* G,int v,int visit[MaxV]) {
ArcNode* p = NULL;
int que[MaxV];//定义一个队列,用于广度优先遍历
int front = 0;//头指针
int rear = 0;//尾指针
int j;
printf("%d ", G->vertices[v].data);//打印当前结点的值
visit[v] = 1;//并设置为已访问
rear = (rear + 1) % MaxV;//入队
que[rear] = v;
while (front != rear) {
front = (front + 1) % MaxV;
j = que[front];//出队一个顶点给j
p = G->vertices[j].firstarc;//刚开始是v1与v2的公共边
while (p != NULL) {//当前结点还有子结点
if (visit[p->adjvex] == 0) {//刚开始就是判断二有没有被访问过
printf("%d ", G->vertices[p->adjvex].data);
visit[p->adjvex] = 1;
rear = (rear + 1) % MaxV;
que[rear] = p->adjvex;
}
p = p->nextarc;
}
}
}
完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define MaxV 20
typedef struct ArcNode {
int adjvex;
struct ArcNode* nextarc;
}ArcNode;
typedef struct VNode {
int data;
struct VNode* firstarc;
}AdjList[MaxV];
typedef struct {
AdjList vertices;
int vexnum;
int ascnum;
}ALGraph;
int LocateVex(ALGraph* G, int u)
{
/* 初始条件: 图G存在,u和G中顶点有相同特征*/
/* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
for (int i = 0; i < G->vexnum; ++i) {
if (u == (G->vertices[i].data)) {
return i;
}
}
return -1;
}
void InitGraph(ALGraph* G,int vexnum,int ascnum) {
G->vexnum = vexnum;
G->ascnum = ascnum;
for (int i = 0; i < G->vexnum; i++) {//顶点的初始化
G->vertices[i].data = i + 1;
G->vertices[i].firstarc = NULL;
}
for (int k = 0; k < G->ascnum; k++) {
int v1 = 0;
int v2 = 0;
scanf("%d%d", &v1, &v2);
int i = LocateVex(G, v1);
int j = LocateVex(G, v2);
ArcNode* newNode1 = (ArcNode*)malloc(sizeof(ArcNode));
newNode1->adjvex = j;
newNode1->nextarc = G->vertices[i].firstarc;
G->vertices[i].firstarc = newNode1;
ArcNode* newNode2 = (ArcNode*)malloc(sizeof(ArcNode));
newNode2->adjvex = i;
newNode2->nextarc = G->vertices[j].firstarc;
G->vertices[j].firstarc = newNode2;
}
}
//深度
void DFS(ALGraph* G,int v) {
visit[v] = 1;//遍历过该节点,则置为1
printf("%d ", G->vertices[v].data);
ArcNode* q = G->vertices[v].firstarc;
while (q != NULL) {
if (visit[q->adjvex] == 0) {//若未访问过该节点,那就递归
DFS(G, q->adjvex);
}
q = q->nextarc;
}
}
//广度
void BFS(ALGraph* G,int v,int visit[MaxV]) {
ArcNode* p = NULL;
int que[MaxV];//定义一个队列,用于广度优先遍历
int front = 0;//头指针
int rear = 0;//尾指针
int j;
printf("%d ", G->vertices[v].data);//打印当前结点的值
visit[v] = 1;//并设置为已访问
rear = (rear + 1) % MaxV;//入队
que[rear] = v;
while (front != rear) {
front = (front + 1) % MaxV;
j = que[front];//出队一个顶点给j
p = G->vertices[j].firstarc;//用p取和第一个顶点相邻的第一条边
while (p != NULL) {
if (visit[p->adjvex] == 0) {
printf("%d ", G->vertices[p->adjvex].data);
visit[p->adjvex] = 1;
rear = (rear + 1) % MaxV;
que[rear] = p->adjvex;
}
p = p->nextarc;
}
}
}
int main() {
int vexnum;
int arcnum;
int v;
int visit[MaxV] = {0};
scanf("%d%d", &vexnum, &arcnum);
ALGraph* G = (ALGraph*)malloc(sizeof(ALGraph));
InitGraph(G, vexnum, arcnum);
scanf("%d", &v);
printf("============\n");
DFS(G, LocateVex(G, v));
printf("============\n");
BFS(G, LocateVex(G, v),visit);
return 0;
}