从键盘输入的数据建立图,并进行深度优先搜索和广度优先搜索(验证性实验)

广度优先和深度优先【搜索】(验证性实验)

1. 需求分析

要求:很多涉及图上操作的算法都是以图的遍历操作为基础的。试编写一个程序,演示无向图的遍历操作。
在主程序中提供下列菜单:
(1)“1”代表图的建立;
(2)“2”代表深度优先遍历图;
(3)“3”代表广度优先遍历图;
(4)“0”代表结束。
基本要求
以邻接表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列和相应生成树的边集。
分析:
(1) 输入的形式和输入值的范围:字符与int型数字
(2) 输出的形式:输出对应遍历的结果字符串。
(3) 程序所能达到的功能:建立图,深度优先遍历图,广度优先遍历图。
(4) 测试数据:
· DG 9 15
· A B C D E F G H I
· AB AF BG BC CD BI CI DI DG DH DE EH EF FG GH

2. 概要设计

  1. 为了实现程序功能,需要定义图的抽象数据类型。
ADT:图(Graph) 
Data:顶点的有穷非空集合和边集合 
Operation:

Graph(V):按照顶点集 VV 初始化图。
addVex(v):在图 G 中添加新顶点 vv。
deleteVex(v):删除图 G 中顶点 vv 及其相关弧。
addEdge(v1,v2):在图 G 中添加弧<v1,v2><v1,v2>,若 G 是无向图,则还需要增添对称弧 <v2,v1><v2,v1>deleteEdge(v1,v2):在图 G 中删除弧<v1,v2><v1,v2>,若 G 是无向图,则还需要删除对称弧 <v2,v1><v2,v1>DFSTraverse(v):从顶点 vv 开始对图 G 进行深度优先遍历。
BFSTraverse(v):从顶点 vv 开始对图 G 进行广度优先遍历。

3.具体代码

  • 队列.h:
#define MAXQSIZE 31 
#define qelemtype int
#define OVERFLOW -1
#define OK 1
#define ERROR 0

typedef struct{
	qelemtype *base;//队列基准地址 
	int front;//头部 
	int rear;//尾部 
}sqqueue;


void initqueue(sqqueue *q)       //创建队列
{
	q->base = (qelemtype *)malloc(MAXQSIZE*sizeof(qelemtype));
	if(!q->base)
	{
		exit(OVERFLOW);
	} 
	q->front = q->rear = 0;
}
int enqueue(sqqueue *q,qelemtype e)  //添加队列节点
{
	if((q->rear + 1) % MAXQSIZE == q->front)
	{
		return(ERROR);
	}
	q->base[q->rear] = e;
	q->rear = (q->rear + 1) % MAXQSIZE;
	return OK;
}
int dequeue(sqqueue *q,qelemtype *e)   //移出队列节点
{
	if(q->front == q->rear)
	{
		return ERROR;
	}
	*e = q->base[q->front];
	q->front = (q->front + 1) % MAXQSIZE;
	return OK;
}

int queueempty(sqqueue q)  //判断队列是否为空
{
	if(q.front == q.rear)
	{
		return OK;
	}
	else 
	{
		return ERROR;
	}
}


  • 主程序.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"队列.h" 

#define VertexType char
#define GraphKind char

//使用邻接表储存,优点很多
//如果用邻接矩阵来存的话,进行遍历的时候不方便,要把一整行全部扫描完才能确定连接的节点有多少 
//而这个题目要求只要进行广度和深度优先遍历 ,不需要增加和删除节点,同时无向图也不需要考虑入度问题 

//DG,DN,UDG,UDN分别表示 有向图,有向网,无向图,无向网 


typedef struct ArcNode{
	int adjvex;//边节点 
	struct ArcNode *nextarc;//下一个边节点 
}ArcNode;      //邻接表节点 

typedef struct VNode{
	VertexType vexdata;//顶点 
	ArcNode *firstarc;//边 
}VNode;     //邻接表结结构 


typedef struct{
	VNode *vertices;//vertices为vertex的复数,指向顶点【但由于是指针形式,所以可以当作数组基准地址】 
	int vexnum;//定点数 
	int arcnum;//边数 
	GraphKind kind[4];//图的种类 
}ALGraph;     //图结构 

void visit(VNode v)   //打印图节点 
{
	printf("%c ",v.vexdata);
}

int LocateVex(ALGraph *a,char ch)    //查找图节点 
{
	int i = 0;//用于for循环 
	for(;i < a->vexnum;++i)//遍历所有节点 
	{
		if(a->vertices[i].vexdata == ch)//如果某个节点数值等于查找值 
		{
			return i;//返回节点序号i 
		}
	}
	exit(-1);//否则返回错误 
}

void CreateGraph(ALGraph *a)        //建图 
{
	printf("请输入图类,顶点数和边数:");
    scanf("%s",&a->kind[0]);//%[^ ]s表示输入非空字符串,存在kind数组中【4位长度】 
//	getchar();
	scanf("%d%d",&a->vexnum,&a->arcnum);//定点数和边数 
	getchar();
	a->vertices = (VNode*)malloc(a->vexnum * sizeof(VNode));//足够的节点分配空间 
	printf("请输入顶点:");
	int i = 0;//用于for循环 
	for(;i < a->vexnum;++i)//遍历所有节点 来做初始化 
	{
		scanf("%c",&(a->vertices[i].vexdata));
		getchar();
		a->vertices[i].firstarc = NULL;//边先全部设置为null 
	}
	printf("请输入各边:");
	i = 0;//用于for循环 
	for(;i < a->arcnum;++i)//遍历所有边 
	{
		char sv,tv;//两个字符用于接收边 
		scanf("%c%c",&sv,&tv);
		getchar();
		int j = LocateVex(a,sv);//用查找定位到sv节点位置 
		int k = LocateVex(a,tv);//用查找定位到tv节点位置 
		ArcNode *p = (ArcNode*)malloc(sizeof(ArcNode));//创建一个边节点并且分配内存空间 
		//使用头插法 
		p->adjvex = k;//先把边取成k 
		p->nextarc = a->vertices[j].firstarc;//指向首个边节点 
		a->vertices[j].firstarc = p;//再将首个边节点指向p 
		if(a->kind[0] == 'U'&&a->kind[1] == 'D')//如果是无向图 
		{
			ArcNode *q = (ArcNode*)malloc(sizeof(ArcNode));//创建新节点q,对另一部分做类似操作 
			q->adjvex = j;
			q->nextarc = a->vertices[k].firstarc;
			a->vertices[k].firstarc = q;
		} 
	}
}

void DFS(ALGraph a,int *sign,int v,void (*visit)(VNode v))   //连通图深度优先遍历 
{
	sign[v] = 1;//先把当前节点访问成功 
	visit(a.vertices[v]);//访问当前节点 
	ArcNode *p = a.vertices[v].firstarc;//用于for循环 
	for(;p != NULL;p = p->nextarc)//遍历p的所有相连的节点 
	{
		if(!sign[p->adjvex])//只要未被访问则被重新访问 
		{
			DFS(a,sign,p->adjvex,visit);//传入下一个节点 p->adjvex
		}
	}
} 

void DFSTraverse(ALGraph a,void (*visit)(VNode v))   //非连通图深度优先遍历
{
	int sign[a.vexnum];//定义标记数组 
	memset(sign,0,sizeof(sign)); //清空数组 
	int v = 0;
	for(;v < a.vexnum;++v)//遍历全部的节点 
	{
		if(!sign[v])//如果这个节点还没被标记,则对其进行DFS 
		{
			DFS(a,sign,v,visit);
		}
	}
}

void BFS(ALGraph a,int *sign,int v,sqqueue *q,void (*visit)(VNode v))   //连通图广度优先遍历 
{
	sign[v] = 1;//先把当前节点访问成功 
	visit(a.vertices[v]);//访问当前节点 
	enqueue(q,v);//当前节点入队 
	for(;queueempty(*q) != 1;)//只要队列不空 
	{
		int w;//定义w用来储存出队的元素 
		dequeue(q,&w);//出队 
		ArcNode *p = a.vertices[w].firstarc;//定义p指向w的邻接节点 的首节点 
		for(;p != NULL;p = p->nextarc)  //遍历w邻接节点 
		{
			if(sign[p->adjvex] == 0)//只要未被访问 
			{
				sign[p->adjvex] = 1;//标记访问 
				enqueue(q,p->adjvex);//入队 
				visit(a.vertices[p->adjvex]);//访问 
			}
		}
	}
} 

void BFSTraverse(ALGraph a,void (*visit)(VNode v))     //非连通图广度优先遍历 
{
	int sign[a.vexnum];//定义标记数组 
	memset(sign,0,sizeof(sign)); //清空数组 
	sqqueue q;//创建一个辅助队列,用于广度优先 
	initqueue(&q); //队列初始化 
	int v = 0;
	for(;v < a.vexnum;++v)//遍历全部的节点 
	{
		if(!sign[v])
		{
			BFS(a,sign,v,&q,visit);//如果这个节点还没被标记,则对其进行BFS 
		}
	}
}

int main()
{
	ALGraph UDG;//先创建无向图 
	for(;;)
	{
		printf("\n请选择 1.建立图  2.深度优先遍历图  3.广度优先遍历图  0.结束:\n");
		int n;//用于接收输入 
		scanf("%d",&n);
//		getchar();
		switch(n)
		{
			case 1:
				{
					CreateGraph(&UDG);//创建无向图 
					printf("建立成功。\n");
					break;
				}
			case 2:
				{
					DFSTraverse(UDG,visit);//深度优先遍历 
					printf("\n深度优先遍历成功。\n");
					break;
				}	
			case 3:
				{
			    	BFSTraverse(UDG,visit);
			    	printf("\n广度优先遍历成功。\n");
			    	break;	
				}
			case 0:
				return 0;
				break;
				
			default:{
				printf("你输入的请求不符合规范,请重新输入!\n");
				break;
			}
		}
	}
}
  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值