利用邻接矩阵用递归和栈分别实现DFS

本文介绍了如何使用邻接矩阵实现无向图的深度优先搜索(DFS)。从创建无向图的邻接矩阵开始,详细阐述了DFS的递归和非递归遍历过程,并提供了C语言的实现代码。通过示例展示了DFS遍历的过程,从顶点A出发,访问所有未访问过的邻接顶点,直至所有顶点都被访问。最后,给出了递归和非递归DFS的运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家好,今天给大家分享一下DFS的实现。DFS指的是从某一节点开始,树的深度遍历。

首先创建邻接矩阵,创建邻接矩阵时:

  1. 定义无向图的结构体
  2. 输入顶点个数
  3. 分别输入顶点
  4. 对邻接矩阵初始化,初始化边的权值为无穷大
  5. 输入边的个数n,分别输入n次两顶点及其所连的边的权值,并且找到顶点位置给边赋值

之后便可以进行深度遍历了。创建无向图的过程本人不再赘述。

创建后结果如图:(边权值的最大值为500)

其无向图如下:

 

邻接矩阵如下:

我们以A为起点,进行DFS遍历,先DFS(A顶点),访问A顶点,再找出A的未访问过的邻接顶点,分别为BCD,但B顶点是A的第一个没有被访问的邻接顶点,所以就访问B,如图:

在邻接矩阵中则如下图表示:

之后将A顶点标记为已经访问,用布尔类型,(因为C语言中没有内置的bool,所以需要自己定义,用int类型也可以,部分代码段如下:)

#define bool char
#define true 1
#define false 0


//布尔类型访问标记
bool visited[VERTEXMAXSIZE];

再DFS(B顶点)并置B为已访问......以此类推,无向图过程如下:

 

 

 

 

 

 就此,所有顶点都标红,都访问完毕,函数执行完成。

用无向图来表示,即从一个顶点开始,一直访问此顶点的第一个没有被访问的邻接顶点,直到这样的邻接顶点不存在,之后回溯到上一个顶点,寻找下一个未被访问的邻接顶点......

如果要用非递归遍历,我们可以用栈来进行操作。方法与中序法遍历二叉树类似,完整代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef char VertexType;
typedef int EdgeType;
#define WEIGHTMAXSIZE 500
#define VERTEXMAXSIZE 100
#define bool char
#define true 1
#define false 0
typedef struct AdjaencyMatrix{
	VertexType vertex[VERTEXMAXSIZE];
	EdgeType edge[VERTEXMAXSIZE][VERTEXMAXSIZE];
	int VertexNum;
	int EdgeNum;
}AMGraph;
//获取定点的位置
int LocateV(AMGraph *G,VertexType v){
	int i;
	for(i = 0;i<G->EdgeNum;i++){
		if(G->vertex[i] == v)
			return i;
	}
	return -1;
}
//创建无向图的邻接矩阵
void CreatAM(AMGraph *G){
	//输入顶点个数
	int vertexnum,edgenum,i,j;
	char v1,v2;
	printf("输入顶点个数:");
	scanf("%d",&vertexnum);
	getchar();
	G->VertexNum = vertexnum;
	//分别输入顶点
	printf("分别输入顶点:(中间不留空格)");
	for(i = 0;i<vertexnum;i++){
		scanf("%c",&G->vertex[i]);
	}
	getchar();
	//所有边的权初始化
	for(i = 0;i<G->VertexNum;i++){
		for(j = 0;j<G->VertexNum;j++)
			G->edge[i][j] = WEIGHTMAXSIZE;
	}
	//输入边的个数
	printf("输入边的个数:");
	scanf("%d",&edgenum);
	getchar();
	G->EdgeNum = edgenum;
	//分别输入两顶点以及边的权值
	printf("分别输入两顶点以及边的权值:\n");
	for(i = 0;i<edgenum;i++){
		int m,n,e;
		//输入两个顶点和权值
		scanf("%c%c%d",&v1,&v2,&e);
		getchar();
		//获取定点v1,v2的位置
		m = LocateV(G,v1);
		n = LocateV(G,v2);
		//赋值
		G->edge[m][n] = e;
		G->edge[n][m] = e;
	}
}
//布尔类型访问标记
bool visited[VERTEXMAXSIZE];
//访问函数
void visit(AMGraph G,int Location){
	printf("%c--",G.vertex[Location]);
}

//DFS递归遍历
void DFS(AMGraph G,int VLocation){
	int i;
	//访问v结点,标记结点已经访问
	visit(G,VLocation);
	visited[VLocation] = true;
	//循环访问v顶点的邻接顶点
	for(i = 0;i<G.VertexNum;i++){
		//顶点没有被访问过,且与v邻接
		if((!visited[i]) && G.edge[VLocation][i] != WEIGHTMAXSIZE)
			DFS(G,i);
	}
}
//找第一个没有被访问的邻接顶点的函数
int FindNotVisit(AMGraph G,int v){
	int i;
	for(i = 0;i<G.VertexNum;i++){
		if(visited[i] == false && G.edge[v][i] != WEIGHTMAXSIZE){
			return i;
		}
	}	
	return -1;
}
//利用栈进行DFS深度遍历
void StackDFS(AMGraph G,int VLocation){
	int stack[VERTEXMAXSIZE];
	int w;
	int top = 0;
	w = VLocation;
	visit(G,w);
	visited[w] = true;
	//找到w的第一个未被访问的邻接顶点,将顶点位置赋给w的位置
	while(FindNotVisit(G,w) != -1 || top != 0){
		while(FindNotVisit(G,w) != -1){
			//找到w的第一个未被访问的邻接顶点
			w = FindNotVisit(G,w);
			//访问并标记
			visit(G,w);
			visited[w] = true;
			//入栈
			stack[top++] = w;
		}
		if(top != 0){//栈不为空
			//出栈
			w = stack[--top];
			//找顶点的第一个未被访问的邻接顶点
			w = FindNotVisit(G,w);
		}
	}
}

void test01(){
	//输入格式如下:
/*
6
ABCDEF
9
BE24
CD5
AC20
CE3
EF9
AD15
CF40
AB11
DF19
*/
	int i,j,start;
	AMGraph *G;
	G = (AMGraph*)malloc(sizeof(AMGraph));
	CreatAM(G);
	for(i = 0;i<G->VertexNum;i++){
		for(j = 0;j<G->VertexNum;j++)
			printf("%9d",G->edge[i][j]);
		printf("\n");
	}
	printf("\n\n\n\n递归DFS:\n");
	//DFS深度遍历
	start = 0;
	printf("从第%d个顶点开始:\n",start);
	DFS(*G,start);
	printf("\n");
	//利用栈进行DFS
	printf("非递归DFS:\n");
	start = 0;
	for(i = 0;i<=G->VertexNum;i++)
		visited[i] = false;
	StackDFS(*G,start);
	printf("\n");
}
int main(){
	test01();
	return 0;
}

运行结果如下:

 有错误在品论区留言哦~~~谢谢各位小伙伴!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷酷的-Alan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值