【C语言|DFS+BFS】无向图的邻接表遍历非递归算法-用栈实现深度优先(DFS)以及用队列实现广度优先(BFS)遍历(文件读写操作)

目录

实验课题:​

实验代码(C):

实验思路:

实验代码解释:

申明相关变量:

初始化数据 

主函数部分:

算法核心

实验代码(全):

 实验效果:


实验课题:

现有一组无向图,要求用DFS和BFS遍历图,依次输出相关值。

实验代码(C):

实验思路:

采用读取text文件,第一阶段依次读取文件中的顶点表数量和边表的数量,第二阶段读取各个顶点的名称,第三阶段读取各边表的两个下标位置。(注意:若是构建有向图的,可以在赋予边表时候只赋给一边,本案例是按照无向图双边赋值)。

实验代码解释:

申明相关变量:

申明变量(链表、节点、队列)

#include<stdio.h>
#include<stdlib.h>
//#include<malloc.h>
#define _CRT_SECURE_NO_WARNINGS
#define MaxVertices 100 
#define MaxVertNum 100
#define MAX 10 

typedef int VertextType;//顶点类型应由用户定义
//typedef int EdgeType;//边上的权值类型应由用户定义
/*边表结点*/
typedef struct EdgeNode {//边表结点  边表
	int adjvex;//邻接点域,存储该顶点对应的下标
	//EdgeType weight;//用于存储权值,对于非网图可以不需要
	struct EdgeNode* next;//链域,指向下一个邻接点
}EdgeNode;

typedef struct VertextNode {//顶点表结点 顶点表
	VertextType data;//顶点域,存储顶点信息
	EdgeNode* firstedge;//边表头指针
}VertexNode;

typedef VertexNode AdjList[MaxVertices];//顶点表数组 

typedef struct {
	//VertexNode adjList[MaxVertices];
	AdjList adjList;//存放所有顶点表的数组-> VertexNode adjList[MaxVertices]
	int numVertexes, numEdges;//图中当前顶点数和边数
}GraphAdjList;
typedef GraphAdjList* GraphAdj;


typedef struct LoopQueue{ //定义循环队列结构体
	int data[MAX];
	int front;
	int rear;   //注意每次队尾标记指向最后一个元素的下一个位置
}Queue, *LQueue;

void InitQueue(LQueue &Q){  //初始化队列
	Q->front = Q->rear = 0;
}

bool QueueisFull(LQueue &Q){ //判断队列是否满了
	if((Q->rear + 1) % MAX == Q->front){
		return true;  //已满
	}
	else{
		return false;
	}
}

bool QueueisEmpty(LQueue &Q){//判断队列是否为空
	if(Q->front == Q->rear){
		return true;
	}
	return false;
}


void EnQueue(LQueue &Q, int i){ //入队列
	if(!QueueisFull(Q)){
		Q->data[Q->rear] = i;
		Q->rear = (Q->rear + 1) % MAX;  //队尾指针后移
	}
}

void DeQueue(LQueue &Q, int *k){ //出队列
	if(!QueueisEmpty(Q)){
		*k = Q->data[Q->front];
		Q->front = (Q->front + 1) % MAX;
	}
}

初始化数据 

int InitGraph(GraphAdj G) {

	int i, j;
	EdgeNode* s;//新的边结点
	FILE* fp = NULL;
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList2.txt", "rb");
	if (fp == NULL) {
		printf("ERROR");
		return -1;
	}
	fscanf(fp, "%d %d", &G->numVertexes, &G->numEdges);//顶点数,边数

	/*******************创建顶点表**************************/
	for (i = 0; i < G->numVertexes; i++) {
		fscanf(fp, "%d", &G->adjList[i].data);
		G->adjList[i].firstedge = NULL;//注意将边表置空
	}

	/******************创建边表****************************/
	for (int k = 0; k < G->numEdges; k++) {
		fscanf(fp, "%d %d", &i, &j);//"输入边(Vi,Vj)上的顶点序号

		//对于直接相连的进行编入(即对输入“0 1”时,在0对应的边表中编入1) 
		s = (EdgeNode*)malloc(sizeof(EdgeNode));
		s->adjvex = j;//边表赋值
		s->next = G->adjList[i].firstedge;
		G->adjList[i].firstedge = s;

		//对于间接相连的进行编入(即对输入“0 1”时,在1对应的边表中编入0)
		s = (EdgeNode*)malloc(sizeof(EdgeNode));
		s->adjvex = i;
		s->next = G->adjList[j].firstedge;
		G->adjList[j].firstedge = s;
	}

	fclose(fp);
}



void DisplayGraph(GraphAdjList* G) {
	int i;
	FILE *fp;
	/**文档输出     ***/
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result.txt", "w");
	if (fp == NULL) {
		printf("ERROR");
		//	return -1;
	}
	fprintf(fp, "Enter contents to store in file : \n");
	EdgeNode* p;
	for (int i = 0; i < G->numVertexes; i++) {
		p = G->adjList[i].firstedge;
		printf("%d->", i);
		fprintf(fp, "%d->", i);
		while (1) {
			if (p == NULL) {
				printf("^");
				fprintf(fp, "^");
				break;
			}
			printf("%d->", p->adjvex);//输出边表的下标,但这里可以表示原有的 数 
			fprintf(fp, "%d->", p->adjvex);
			p = p->next;
		}
		printf("\n");
		fprintf(fp, "\n");
	}

	fclose(fp);//??? 
}

主函数部分:

int main() {
	int index, flage = 1;
	GraphAdjList* G = (GraphAdjList*)malloc(sizeof(GraphAdjList));
	InitGraph(G);
	printf("现有无向图的链表存储:\n");
	DisplayGraph(G);

	while (flage) {
		printf("现有无向图的DFS(按1):\n");
		printf("现有无向图的BFS(按2):\n");
		printf("退出遍历(按3):\n");
		//DFSTraverse(G);
		scanf("%d", &index);
		switch (index) {
		case 1:
			DFS(G, 0);
			break;
		case 2:
			BFS(G,0);
			break;
		case 3:
			flage = 0;
			break;
		}
	}
	return 0;
}

算法核心:

DFS部分。运用。将head后面依次放入栈中,并选取栈头的visit为1置为新的head,遍历其后面的依次放入栈中,直到栈为空结束。

void DFS(GraphAdjList* G, int v0) { //图,下标位置 
	int stack[MaxVertNum];
	EdgeNode* p;
	int visited[MaxVertNum] = { 0 }, top = -1, v;
	printf("此图的DFS遍历:\n");
	//p = G->adjList[v0].firstedge;
	stack[++top] = v0;//top=0,存储第一个数v0(下标) 

	FILE *fp;	/**文档输出     ***/
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_DFS.txt", "w");
	if (fp == NULL) {
		printf("ERROR");
		//	return -1;
	}
	fprintf(fp, "此图的DFS遍历:\n");

	while (top != -1)//判断栈有无有空 
	{
		v = stack[top--];//出栈 v(数值data/下标)
		if (!visited[v]) {//v 未被访问 
			printf("%d ", G->adjList[v].data);
			fprintf(fp, "%d ", G->adjList[v].data);
			visited[v] = 1;
		}
		p = G->adjList[v].firstedge;//边结点指针 
		while (p) {
			if (!visited[p->adjvex]) {//p边结点的下标有无访问到 
				stack[++top] = p->adjvex;
			}
			p = p->next;
		}
	}
	fclose(fp);
	printf("\n");
}

BFS部分。运用队列。将head后面依次放入队列中,并选取队头的取出,其visit为1置为新的head,遍历其后面的依次放入队列中,直到队列为空结束。

void BFS(GraphAdjList* G,int i){
	int visited[MaxVertNum] = { 0 };
	//int i = 0;
	Queue *Q =(LQueue)malloc(sizeof(Queue));
	for(int i = 0; i < G->numVertexes; i++){
		visited[i] = 0;
	}

	FILE *fp;	/**文档输出     ***/
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_BFS.txt", "w");
	if (fp == NULL) {
		printf("ERROR");
		//	return -1;
	}
	fprintf(fp, "此图的BFS遍历:\n");

	InitQueue(Q);  //初始化队列

	visited[i] = 1;//从0下标开始
	printf("%d ", G->adjList[i].data);
	fprintf(fp,"%d ", G->adjList[i].data);

	EnQueue(Q, i);//入队?

	while(!QueueisEmpty(Q)){//根据队列遍历全部顶点坐标
		DeQueue(Q, &i);  //这里不断的修改i的值,队头元素出队,改变i值?
		EdgeNode *e = G->adjList[i].firstedge;  //i顶点的邻接链表的第一个结点
		while(e){//e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点
			if(!visited[e->adjvex]){ // adjvex是e所表示的结点下标
				visited[e->adjvex] = 1;
				printf("%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
				fprintf(fp,"%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
				EnQueue(Q, e->adjvex); //将该结点入队
			}
			e = e->next; //遍历i的下一个邻接点
		}
	}
	
	printf("\n");
	fclose(fp);
}

实验代码(全):

#include<stdio.h>
#include<stdlib.h>
//#include<malloc.h>
#define _CRT_SECURE_NO_WARNINGS
#define MaxVertices 100 
#define MaxVertNum 100
#define MAX 10 

typedef int VertextType;//顶点类型应由用户定义
//typedef int EdgeType;//边上的权值类型应由用户定义
/*边表结点*/
typedef struct EdgeNode {//边表结点  边表
	int adjvex;//邻接点域,存储该顶点对应的下标
	//EdgeType weight;//用于存储权值,对于非网图可以不需要
	struct EdgeNode* next;//链域,指向下一个邻接点
}EdgeNode;

typedef struct VertextNode {//顶点表结点 顶点表
	VertextType data;//顶点域,存储顶点信息
	EdgeNode* firstedge;//边表头指针
}VertexNode;

typedef VertexNode AdjList[MaxVertices];//顶点表数组 

typedef struct {
	//VertexNode adjList[MaxVertices];
	AdjList adjList;//存放所有顶点表的数组-> VertexNode adjList[MaxVertices]
	int numVertexes, numEdges;//图中当前顶点数和边数
}GraphAdjList;
typedef GraphAdjList* GraphAdj;

int InitGraph(GraphAdj G) {

	int i, j;
	EdgeNode* s;//新的边结点
	FILE* fp = NULL;
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList2.txt", "rb");
	if (fp == NULL) {
		printf("ERROR");
		return -1;
	}
	fscanf(fp, "%d %d", &G->numVertexes, &G->numEdges);//顶点数,边数

	/*******************创建顶点表**************************/
	for (i = 0; i < G->numVertexes; i++) {
		fscanf(fp, "%d", &G->adjList[i].data);
		G->adjList[i].firstedge = NULL;//注意将边表置空
	}

	/******************创建边表****************************/
	for (int k = 0; k < G->numEdges; k++) {
		fscanf(fp, "%d %d", &i, &j);//"输入边(Vi,Vj)上的顶点序号

		//对于直接相连的进行编入(即对输入“0 1”时,在0对应的边表中编入1) 
		s = (EdgeNode*)malloc(sizeof(EdgeNode));
		s->adjvex = j;//边表赋值
		s->next = G->adjList[i].firstedge;
		G->adjList[i].firstedge = s;

		//对于间接相连的进行编入(即对输入“0 1”时,在1对应的边表中编入0)
		s = (EdgeNode*)malloc(sizeof(EdgeNode));
		s->adjvex = i;
		s->next = G->adjList[j].firstedge;
		G->adjList[j].firstedge = s;
	}

	fclose(fp);
}



void DisplayGraph(GraphAdjList* G) {
	int i;
	FILE *fp;
	/**文档输出     ***/
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result.txt", "w");
	if (fp == NULL) {
		printf("ERROR");
		//	return -1;
	}
	fprintf(fp, "Enter contents to store in file : \n");
	EdgeNode* p;
	for (int i = 0; i < G->numVertexes; i++) {
		p = G->adjList[i].firstedge;
		printf("%d->", i);
		fprintf(fp, "%d->", i);
		while (1) {
			if (p == NULL) {
				printf("^");
				fprintf(fp, "^");
				break;
			}
			printf("%d->", p->adjvex);//输出边表的下标,但这里可以表示原有的 数 
			fprintf(fp, "%d->", p->adjvex);
			p = p->next;
		}
		printf("\n");
		fprintf(fp, "\n");
	}

	fclose(fp);//??? 
}

void DFS(GraphAdjList* G, int v0); //图,下标位置 
void BFS(GraphAdjList* G,int v0);


int main() {
	int index, flage = 1;
	GraphAdjList* G = (GraphAdjList*)malloc(sizeof(GraphAdjList));
	InitGraph(G);
	printf("现有无向图的链表存储:\n");
	DisplayGraph(G);

	while (flage) {
		printf("现有无向图的DFS(按1):\n");
		printf("现有无向图的BFS(按2):\n");
		printf("退出遍历(按3):\n");
		//DFSTraverse(G);
		scanf("%d", &index);
		switch (index) {
		case 1:
			DFS(G, 0);
			break;
		case 2:
			BFS(G,0);
			break;
		case 3:
			flage = 0;
			break;
		}

	}

	return 0;
}

/********************DFS*************************************/
void DFS(GraphAdjList* G, int v0) { //图,下标位置 
	int stack[MaxVertNum];
	EdgeNode* p;
	int visited[MaxVertNum] = { 0 }, top = -1, v;
	printf("此图的DFS遍历:\n");
	//p = G->adjList[v0].firstedge;
	stack[++top] = v0;//top=0,存储第一个数v0(下标) 

	FILE *fp;	/**文档输出     ***/
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_DFS.txt", "w");
	if (fp == NULL) {
		printf("ERROR");
		//	return -1;
	}
	fprintf(fp, "此图的DFS遍历:\n");

	while (top != -1)//判断栈有无有空 
	{
		v = stack[top--];//出栈 v(数值data/下标)
		if (!visited[v]) {//v 未被访问 
			printf("%d ", G->adjList[v].data);
			fprintf(fp, "%d ", G->adjList[v].data);
			visited[v] = 1;
		}
		p = G->adjList[v].firstedge;//边结点指针 
		while (p) {
			if (!visited[p->adjvex]) {//p边结点的下标有无访问到 
				stack[++top] = p->adjvex;
			}
			p = p->next;
		}
	}
	fclose(fp);
	printf("\n");
}
/********************BFS*************************************/


typedef struct LoopQueue{ //定义循环队列结构体
	int data[MAX];
	int front;
	int rear;   //注意每次队尾标记指向最后一个元素的下一个位置
}Queue, *LQueue;

void InitQueue(LQueue &Q){  //初始化队列
	Q->front = Q->rear = 0;
}

bool QueueisFull(LQueue &Q){ //判断队列是否满了
	if((Q->rear + 1) % MAX == Q->front){
		return true;  //已满
	}
	else{
		return false;
	}
}

bool QueueisEmpty(LQueue &Q){//判断队列是否为空
	if(Q->front == Q->rear){
		return true;
	}
	return false;
}


void EnQueue(LQueue &Q, int i){ //入队列
	if(!QueueisFull(Q)){
		Q->data[Q->rear] = i;
		Q->rear = (Q->rear + 1) % MAX;  //队尾指针后移
	}
}

void DeQueue(LQueue &Q, int *k){ //出队列
	if(!QueueisEmpty(Q)){
		*k = Q->data[Q->front];
		Q->front = (Q->front + 1) % MAX;
	}
}

void BFS(GraphAdjList* G,int i){
	int visited[MaxVertNum] = { 0 };
	//int i = 0;
	Queue *Q =(LQueue)malloc(sizeof(Queue));
	for(int i = 0; i < G->numVertexes; i++){
		visited[i] = 0;
	}

	FILE *fp;	/**文档输出     ***/
	fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_BFS.txt", "w");
	if (fp == NULL) {
		printf("ERROR");
		//	return -1;
	}
	fprintf(fp, "此图的BFS遍历:\n");

	InitQueue(Q);  //初始化队列

	visited[i] = 1;//从0下标开始
	printf("%d ", G->adjList[i].data);
	fprintf(fp,"%d ", G->adjList[i].data);

	EnQueue(Q, i);//入队?

	while(!QueueisEmpty(Q)){//根据队列遍历全部顶点坐标
		DeQueue(Q, &i);  //这里不断的修改i的值,队头元素出队,改变i值?
		EdgeNode *e = G->adjList[i].firstedge;  //i顶点的邻接链表的第一个结点
		while(e){//e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点
			if(!visited[e->adjvex]){ // adjvex是e所表示的结点下标
				visited[e->adjvex] = 1;
				printf("%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
				fprintf(fp,"%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
				EnQueue(Q, e->adjvex); //将该结点入队
			}
			e = e->next; //遍历i的下一个邻接点
		}
	}
	
	printf("\n");
	fclose(fp);
}

 实验效果:

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用邻接示无向图BFSDFS的C语言代码。其中,我们假设图中的节点编号从0开始。代码中的注释会帮助您理解算法实现细节。 ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 100 // 最大节点数 /* 邻接节点结构体 */ typedef struct ArcNode{ int adjvex; // 邻接点编号 struct ArcNode* nextarc; // 下一个邻接点指针 }ArcNode; /* 顶点节点结构体 */ typedef struct VertexNode{ int data; // 顶点数据 ArcNode* firstarc; // 第一个邻接点指针 }VertexNode; /* 图结构体 */ typedef struct{ VertexNode vexs[MAX_VERTEX_NUM]; // 顶点数组 int vexnum; // 顶点数 int arcnum; // 边数 }Graph; /* 初始化图 */ void InitGraph(Graph* G){ int i; G->vexnum = 0; G->arcnum = 0; for(i = 0; i < MAX_VERTEX_NUM; i++){ G->vexs[i].data = 0; G->vexs[i].firstarc = NULL; } } /* 插入边 */ void InsertArc(Graph* G, int v1, int v2){ ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode)); ArcNode* p2 = (ArcNode*)malloc(sizeof(ArcNode)); p1->adjvex = v2; p2->adjvex = v1; p1->nextarc = G->vexs[v1].firstarc; p2->nextarc = G->vexs[v2].firstarc; G->vexs[v1].firstarc = p1; G->vexs[v2].firstarc = p2; G->arcnum++; } /* BFS */ void BFS(Graph* G, int start){ int visited[MAX_VERTEX_NUM] = {0}; // 初始化所有节点未被访问 int queue[MAX_VERTEX_NUM]; // 队列 int front = 0; // 队头 int rear = 0; // 队尾 int i, j; ArcNode* p; visited[start] = 1; // 标记起始节点已被访问 printf("%d ", start); // 输出起始节点 queue[rear++] = start; // 起始节点入队 while(front < rear){ // 队列不为空则循环 i = queue[front++]; // 出队 p = G->vexs[i].firstarc; // 获取第一个邻接点 while(p){ // 遍邻接点 j = p->adjvex; if(!visited[j]){ // 如果邻接点未被访问则访问并标记 visited[j] = 1; printf("%d ", j); queue[rear++] = j; // 邻接点入队 } p = p->nextarc; // 处理下一个邻接点 } } } /* DFS */ void DFS(Graph* G, int i, int visited[]){ ArcNode* p = G->vexs[i].firstarc; // 获取第一个邻接点 visited[i] = 1; // 标记节点已被访问 printf("%d ", i); // 输出节点 while(p){ // 遍邻接点 if(!visited[p->adjvex]){ // 如果邻接点未被访问则归访问 DFS(G, p->adjvex, visited); } p = p->nextarc; // 处理下一个邻接点 } } int main(){ Graph G; int start; int i, j; printf("请输入无向图的节点数和边数:"); scanf("%d%d", &G.vexnum, &G.arcnum); printf("请依次输入每个节点的数据:"); for(i = 0; i < G.vexnum; i++){ scanf("%d", &(G.vexs[i].data)); } printf("请依次输入每条边的两个节点编号(从0开始):\n"); for(i = 0; i < G.arcnum; i++){ scanf("%d%d", &j, &start); InsertArc(&G, j, start); } printf("请输入遍开始的节点编号(从0开始):"); scanf("%d", &start); printf("BFS结果为:"); BFS(&G, start); printf("\nDFS结果为:"); int visited[MAX_VERTEX_NUM] = {0}; // 初始化所有节点未被访问 DFS(&G, start, visited); return 0; } ``` 希望这份代码能够帮到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值