数据结构实验七

南昌航空大学实验报告

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循环从0n(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;

}

posted @ 2022-03-14 23:18  安良  阅读(956)  评论(0)    收藏  举报