【C语言】图的深度优先遍历&广度优先遍历(算法,代码一步到位)

前言

图的遍历是一个非常重要的知识点,今天花几分钟时间帮助大家彻底解决图的两种遍历

图的深度优先遍历(DFS)

算法流程
我们借助一张图来理解
【C语言】图的深度优先遍历&广度优先遍历(算法,代码一步到位)_第1张图片
首先采取我们之前学的建立邻接表的方法存储这个图,什么才是深度优先遍历呢?
1.例如从V1出发,我们找到V1为头结点的单链表,看看指针下一个指向的是2
(2是指哪一个顶点在数组中下标为2)很明显是V2,我们就遍历到了V2
2.来到V2所在单链表发现1遍历过了(使用visit数组判断)那就跳过,看下一个,发现4没有遍历,那么就到了V4,以此类推…

代码实现

step1.构造邻接表存储图

#define _CRT_SECURE_NO_WARNINGS 
#include
#include
#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;
}

【C语言】图的深度优先遍历&广度优先遍历(算法,代码一步到位)_第2张图片
【C语言】图的深度优先遍历&广度优先遍历(算法,代码一步到位)_第3张图片

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
#include
#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;
}

你可能感兴趣的:(算法,c语言,宽度优先)