数据结构实验七
南昌航空大学实验报告
二0 21 年 6 月 3 日
课程名称: 数据结构实验 实验名称: 图及应用
班级: 姓名: 同组人:
指导教师评定: 签名:
必做1:
一、 需求分析
题目:设计并验证如下算法:图采用邻接矩阵表示,实现无向图的深度优先搜索与有向图的广度优先搜索。
1、在本次实验中,首先,根据输入创建一个有向图,一个无向图,在进行对无向图的深度优先搜索和对有向图的广度优先搜索,输出遍历结果。
2. 演示程序以用户和计算机对话的方式进行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入图的信息,输出按要求遍历得到的结果。
3. 程序执行的命令包括:
(1) 输入图的信息
(2) 构建有向图与无向图
(3) 无向图深度优先搜索并输出遍历结果
(4) 有向图广度优先搜索并输出遍历结果
4. 测试数据
请输入顶点个数:
5
请输入5个顶点:
abcde
请输入边的数量:
6
请输入6对边:
0 1
1 2
2 4
1 3
0 4
1 2
此边输入有误,请重新输入:
1 4
a b c e d
a b e c d
二、 概要设计
1. 抽象数据类型定义
为实现上述程序功能,需要一个抽象数据类型:图。
ADT Graph{
基本操作:
InitQueue(queue &a)
操作结果:队列初始化
InQueue(queue &a,int m)
操作结果:m入队列
GetFront(queue a)
操作结果:取队头元素
OutQueue(queue &a)
操作结果:出队列
length(queue a)
操作结果:返回队列长度
panduan(Mgraph m,int s1,int s2)
操作结果:判断是否输入成功
creat(Mgraph *m,Mgraph *m1)
操作结果:操作m无向图,m1有向图
panduan1(int n,int visit1[])
操作结果:判断是否经过遍历
DFS(Mgraph m,int i,int visit[])
操作结果:深度优先遍历(部分)
DFS_1(Mgraph m,int visit[])
操作结果:深度优先搜索(部分)
BFS(Mgraph m,int visit1[])
操作结果:广度优先搜索
2.程序模块
(1)主程序流程
void main{
创建两个邻接表;
创建有向图和无向图;
无向图深度优先搜索;
有向图广度优先搜索;
}
(2)无向图深度优先搜索;
(3)有向图广度优先搜索;
3.程序结构图
各模块之间的调用关系如图所示。
图1 模块之间调用关系图
三、 详细设计
1.数据类型及结构体
typedef struct{
int adj;//判断是否有弧
}AdjMatrix[20][20];//邻接矩阵
typedef struct{
char vexs[20];//顶点
AdjMatrix Matrix;
int vexnum,arcnum;//顶点数,弧数
}Mgraph;
typedef struct{
int data[20];
int front,rear;//队尾_rear和队头_front
}queue;
int InitQueue(queue &a){//初始化队列
void InQueue(queue &a,int m){//入队
int GetFront(queue a){//获取队头元素
int OutQueue(queue &a){//出队
int length(queue a){//返回队伍长度
bool panduan(Mgraph m,int s1,int s2){//判断输入的边是否合法,是否已存在
int creat(Mgraph *m,Mgraph *m1){//m为无向图,m1为有向图
int panduan1(int n,int visit1[]){//判断是否经过遍历
void DFS(Mgraph m,int i,int visit[]){//深度优先搜索
void DFS_1(Mgraph m,int visit[]){//深度优先搜索
void BFS(Mgraph m,int visit1[]){//广度优先搜索
2.主函数
int main(){
Mgraph M,M1;
int visit[20] = {0};//判断是否遍历到
int visit1[20] = {0};
creat(&M,&M1);
DFS_1(M,visit);
printf("\n");
BFS(M1,visit1);
return 0;
}
四、 调试分析
1.在考虑输入边的合法性时,知考虑到了可以存在的边是否输入过,而未考虑到两个不存在顶点的边。经改正bool panduan(Mgraph m,int s1,int s2){//判断输入的边是否合法,是否已存在
if((s1>=0 && s1<m.vexnum) && (s2>=0 && s2<m.vexnum)&&(s1!=s2)){
if(m.Matrix[s1][s2].adj==0){
return true;
}
else{
return false;
}
}
return false;
}
2.第一次遍历时,若图存在不连通的情况,就没遍历过,经改正:深度优先遍历加了个void DFS_1(Mgraph m,int visit[])函数,广度优先遍历加了个for循环从0到n(n为顶点个数).
3.有向图广度优先遍历时间复杂度为:O(n^2)无向图深度优先遍历时间复杂度为:O(n^2)
五、 用户手册
1. 本程序的运行环境为DOS操作系统,执行文件为:main.exe。
2. 进入演示程序后即显示文本方式的用户界面。
3. 程序运行后,按照提示信息输入图的信息
4. 输出结果分别为无向图深度优先搜索,有向图广度优先搜索。
六、 测试结果
测试结果
请输入顶点个数:
5
请输入5个顶点:
abcde
请输入边的数量:
6
请输入6对边:
0 1
1 2
2 4
1 3
0 4
1 2
此边输入有误,请重新输入:
1 4
a b c e d
a b e c d
七、 附录
源代码:#include<stdio.h>
#include<stdlib.h>
#include <memory.h>
typedef struct{
int adj;//判断是否有弧
}AdjMatrix[20][20];//邻接矩阵
typedef struct{
char vexs[20];//顶点
AdjMatrix Matrix;
int vexnum,arcnum;//顶点数,弧数
}Mgraph;
typedef struct{
int data[20];
int front,rear;//队尾_rear和队头_front
}queue;
int InitQueue(queue &a){//初始化队列
//a.data[20]= {0};
memset(a.data,0,sizeof(a.data));
a.front = a.rear = -1;
return 0;
}
void InQueue(queue &a,int m){//入队
if(20 == a.front+1){
printf("队满");
return;
}else{
a.data[a.rear++] = m;
}
}
int GetFront(queue a){//获取队头元素
return a.data[a.front];
}
int OutQueue(queue &a){//出队
if(a.front == a.rear){
printf("队为空");
exit(-1);
}
return a.data[a.front++];
}
int length(queue a){//返回队伍长度
return a.rear-a.front;
}
bool panduan(Mgraph m,int s1,int s2){//判断输入的边是否合法,是否已存在
if((s1>=0 && s1<m.vexnum) && (s2>=0 && s2<m.vexnum)&&(s1!=s2)){
if(m.Matrix[s1][s2].adj==0){
return true;
}
else{
return false;
}
}
return false;
}
int creat(Mgraph *m,Mgraph *m1){//m为无向图,m1为有向图
int num1,num2,i,j;
printf("请输入顶点个数:\n");
scanf("%d",&num1);
if(num1==0)
exit(-1);
m1->vexnum=num1;
m->vexnum=num1;
printf("请输入%d个顶点:\n",num1);
getchar();
char c;
for(i=0;i<num1;i++){
scanf("%c",&c);
m1->vexs[i] = c;
m->vexs[i] = c;
}
printf("请输入边的数量:\n");
scanf("%d",&num2);
m->arcnum = num2;
m1->arcnum = num2;
printf("请输入%d对边:\n",num2);
int s1,s2;
for(i=0;i<m->vexnum;i++){
for(j=0;j<m->vexnum;j++){
m->Matrix[i][j].adj=0;
m1->Matrix[i][j].adj=0;
}
}
for(i=0;i<num2;i++){
scanf("%d %d",&s1,&s2);
if(panduan(*m1,s1,s2)){
m->Matrix[s1][s2].adj=1;
m->Matrix[s2][s1].adj=1;
m1->Matrix[s1][s2].adj=1;
}
else{
printf("此边输入有误,请重新输入\n");
i--;
}
}
}
int panduan1(int n,int visit1[]){
int i;
for(i=0;i<n;i++){
if(visit1[i]==0){
return i;
}
}
return -1;
}
void DFS(Mgraph m,int i,int visit[]){
printf("%c ",m.vexs[i]);
for(int j = 0; j < m.vexnum; j++)
{
if(m.Matrix[i][j].adj && !visit[j])
{
visit[j] = 1;
DFS(m, j,visit);
}
}
}
void DFS_1(Mgraph m,int visit[]){
int i=0;
for(i=0;i<m.vexnum;i++){
if(!visit[i]){
visit[i]=1;
DFS(m,i,visit);
}
}
}
void BFS(Mgraph m,int visit1[]){
queue Q;
InitQueue(Q);
int i=0,j;
while(panduan1(m.vexnum,visit1)!=-1){
InQueue(Q,panduan1(m.vexnum,visit1));
visit1[panduan1(m.vexnum,visit1)] = 1;
while(length(Q)!=0){
int n = GetFront(Q);
for(i=0;i<m.vexnum;i++){
if(visit1[i]==0 && m.Matrix[n][i].adj){
visit1[i] = 1;
InQueue(Q,i);
}
}
j = OutQueue(Q);
if(visit1[j]==1){
printf("%c ",m.vexs[j]);
}
}
}
}
int main(){
Mgraph M,M1;
int visit[20] = {0};//判断是否遍历到
int visit1[20] = {0};
creat(&M,&M1);
DFS_1(M,visit);
printf("\n");
BFS(M1,visit1);
return 0;
}
必做2:
一、 需求分析
题目:设计并验证如下算法:带权图采用邻接表表示,实现无向图的广度优先搜索与有向图深度优先搜索
2、在本次实验中,首先,根据输入创建一个有向图,一个无向图,在进行对无向图的广度优先搜索和对有向图的深度优先搜索,输出遍历结果。
2. 演示程序以用户和计算机对话的方式进行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入图的信息,输出按要求遍历得到的结果。
3. 程序执行的命令包括:
(1) 输入图的信息
(2) 构建有向图与无向图
(3) 无向图广度优先搜索并输出遍历结果
(4) 有向图深度优先搜索并输出遍历结果
4. 测试数据
请输入顶点个数:
5
请输入5个顶点:
abcde
请输入边的数量:
6
请输入6对边:
0 1 1
1 2 1
2 4 1
1 3 1
0 4 1
1 2 1
此边输入有误,请重新输入:
1 4 1
请输入从哪个节点开始遍历:3
无向图广度优先:d b e c a
有向图深度优先:d a e b c
二、 概要设计
1. 抽象数据类型定义
为实现上述程序功能,需要一个抽象数据类型:图。
ADT Graph{
基本操作:
InitQueue(queue &a)
操作结果:队列初始化
InQueue(queue &a,int m)
操作结果:m入队列
can_input(ALGraph m,int s1,int s2)
操作结果:判断s1-s2是否构建过
get_front(queue a)
操作结果:取队头元素
OutQueue(queue &a)
操作结果:出队列
length(queue a)
操作结果:返回队列长度
create(ALGraph &p,ALGraph &m)
操作结果:操作m无向图,m1有向图
panduan(int n,int visit1[])
操作结果:判断是否经过遍历
DFS1(ALGraph m,int i,int visit[])
操作结果:深度优先遍历(部分)
DFS(ALGraph m,int i,int visit[])
操作结果:深度优先搜索(部分)
BFS(ALGraph m,int visit1[],int i)
操作结果:广度优先搜索
2.程序模块
(1)主程序流程
void main{
创建两个邻接表;
创建有向图和无向图;
有向图深度优先搜索;
无向图广度优先搜索;
}
(4)无向图深度优先搜索;
(5)有向图广度优先搜索;
3.程序结构图
各模块之间的调用关系如图所示。
图1 模块之间调用关系图
三、 详细设计
1.数据类型及结构体
typedef struct ArcNode{
int adjvex;//该弧所指向的顶点的位置
struct ArcNode *nextarc;//下一条弧
int info;//权
}ArcNode;
typedef struct{
char data;//顶点信息
ArcNode *firstarc;
}VNode,AdjList[MAX];
typedef struct{
AdjList vertices;
int vexnum,arcnum;//顶点数和弧数
}ALGraph;
typedef struct{
int elem[MAX];
int front,rear;//队尾_rear和队头_front
}queue;
int InitQueue(queue &a){//初始化队列
void InQueue(queue &a,int m){//入队
bool can_input(ALGraph m,int s1,int s2){//判断s1-s2是否已经构建
int get_front(queue a){//获取队头元素
int OutQueue(queue &a){//出队
int length(queue a){//返回队伍长度
void DFS1(ALGraph m,int i,int visit[]){//深度优先搜素
void DFS(ALGraph m,int i,int visit[]){//深度优先搜素
int panduan(int n,int visit1[]){//判断是否遍历过,返回未遍历
void BFS(ALGraph m,int visit1[],int i)//广度优先探索
void create(ALGraph &p,ALGraph &m)//p为无向图,m为有向图
2.主函数
int main(){
int visit[MAX]={0};
int visit1[MAX]={0};
ALGraph M,M1;
int i;
create(M,M1);
printf("请输入从哪个结点开始遍历:");
scanf("%d",&i);
//M无向图M1有向图
printf("无向图的广度优先:");
BFS(M,visit1,i);
printf("\n");
printf("有向图的深度优先为:");
DFS(M1,i,visit);
return 0;
}
四、 调试分析
1.按照老师要求增加一个从任意结点开始遍历:在循环前先从这个节点开始遍历,在进循环从第一个结点开始判断是否遍历过。
2.有向图广度优先遍历时间复杂度为:O(n)无向图深度优先遍历时间复杂度为:O(n)
五、 用户手册
1. 本程序的运行环境为DOS操作系统,执行文件为:main.exe。
2. 进入演示程序后即显示文本方式的用户界面。
3. 程序运行后,按照提示信息输入图的信息
4. 输出结果分别为有向图深度优先搜索,无向图广度优先搜索。
六、 测试结果
测试结果
请输入顶点个数:
5
请输入5个顶点:
abcde
请输入边的数量:
6
请输入6对边:
0 1 1
1 2 1
2 4 1
1 3 1
0 4 1
1 2 1
此边输入有误,请重新输入:
1 4 1
请输入从哪个节点开始遍历:3
无向图广度优先:d b e c a
有向图深度优先:d a e b c
七、 附录
源代码:#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#define MAX 100
typedef struct ArcNode{
int adjvex;//该弧所指向的顶点的位置
struct ArcNode *nextarc;//下一条弧
int info;//权
}ArcNode;
typedef struct{
char data;//顶点信息
ArcNode *firstarc;
}VNode,AdjList[MAX];
typedef struct{
AdjList vertices;
int vexnum,arcnum;//顶点数和弧数
}ALGraph;
typedef struct{
int elem[MAX];
int front,rear;//队尾_rear和队头_front
}queue;
int InitQueue(queue &a){//初始化队列
//a.elem[MAX] = {0};
memset(a.elem,0,sizeof(a.elem));
a.front = a.rear = 0;
return 0;
}
void InQueue(queue &a,int m){//入队
if(MAX == a.front+1){
printf("队满");
return;
}else{
a.elem[a.rear++] = m;
}
}
bool can_input(ALGraph m,int s1,int s2){//判断s1-s2是否已经构建
int i;
ArcNode *p;
p = m.vertices[s1].firstarc;
while(p){
if(p->adjvex==s2){
return false;
}
p = p->nextarc;
}
return true;
}
int get_front(queue a){//获取队头元素
return a.elem[a.front];
}
int OutQueue(queue &a){//出队
if(a.front == a.rear){
printf("队为空");
exit(-1);
}
return a.elem[a.front++];
}
int length(queue a){//返回队伍长度
return a.rear-a.front;
}
void DFS1(ALGraph m,int i,int visit[]){
ArcNode *p;
visit[i]=1;
printf("%c ",m.vertices[i].data);
p=m.vertices[i].firstarc;
while(p!=NULL){
if(visit[p->adjvex]==0){//若p->adjvex 顶点未访问,递归访问它
DFS1(m,p->adjvex,visit);
}
p=p->nextarc;//p指向顶点v的下一个邻接点
}
}
void DFS(ALGraph m,int i,int visit[]){
DFS1(m,i,visit);
int a;
for(a=0;a<m.vexnum;a++)
{
if(visit[a]==0)
{
DFS1(m,a,visit);
}
}
}
int panduan(int n,int visit1[]){//判断是否遍历过,返回未遍历
int i;
for(i=0;i<n;i++){
if(visit1[i]==0){
return i;
}
}
return -1;
}
void BFS(ALGraph m,int visit1[],int i)//广度优先探索
{
ArcNode *p;
int s[MAX];
queue q;
int a=i;
InitQueue(q);
int front = 0;
while(panduan(m.vexnum,visit1)!=-1){
if(a!=-1)
{
InQueue(q,a);
visit1[a] = 1;
a=-1;
}else
{
InQueue(q,panduan(m.vexnum,visit1));
visit1[panduan(m.vexnum,visit1)] = 1;
}
while(length(q)!=0){
int n = get_front(q);
ArcNode *p;
p = m.vertices[n].firstarc;
while(p){
if(!visit1[p->adjvex]){
InQueue(q,p->adjvex);
visit1[p->adjvex] = 1;
}
p = p->nextarc;
}
n = OutQueue(q);
printf("%c ",m.vertices[n].data);
}
}
}
void create(ALGraph &p,ALGraph &m)//p为无向图,m为有向图
{
printf("请输入顶点数: \n");
scanf("%d",&p.vexnum);
m.vexnum=p.vexnum;
getchar();
printf("请输入顶点:\n");
char c;
for(int i=0;i<p.vexnum;i++){
scanf("%c",&c);
p.vertices[i].data = c;
p.vertices[i].firstarc=NULL;
m.vertices[i].data = c;
m.vertices[i].firstarc=NULL;
}
int v1,v2,quan;
printf("请输入边的对数: \n");
scanf("%d",&p.arcnum);
printf("请输入%d条对应的边,以及他们的权:\n",p.arcnum);
for(int i=0;i<p.arcnum;i++){
scanf("%d %d %d",&v1,&v2,&quan);
if(can_input(m,v1,v2)){
//无向图
ArcNode *q = (ArcNode *)malloc(sizeof(ArcNode));
q->adjvex=v2;
q->info=quan;
q->nextarc=p.vertices[v1].firstarc;
p.vertices[v1].firstarc=q;
ArcNode *r = (ArcNode *)malloc(sizeof(ArcNode));
r->adjvex=v1;
r->info=quan;
r->nextarc=p.vertices[v2].firstarc;
p.vertices[v2].firstarc=r;
//有向图
ArcNode *s = (ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=v2;
s->info=quan;
s->nextarc=m.vertices[v1].firstarc;
m.vertices[v1].firstarc=s;
}
else{
printf("该边已存在,请重新输入\n");
i--;
}
}
}
int main(){
int visit[MAX]={0};
int visit1[MAX]={0};
ALGraph M,M1;
int i;
create(M,M1);
printf("请输入从哪个结点开始遍历:");
scanf("%d",&i);
//M无向图M1有向图
printf("无向图的广度优先:");
BFS(M,visit1,i);
printf("\n");
printf("有向图的深度优先为:");
DFS(M1,i,visit);
return 0;
}

浙公网安备 33010602011771号