数据结构实验——图(校园导游和无向图遍历)

该文介绍了两个程序设计实验,涉及图的遍历和最短路径计算。实验一是一个校园导游程序,使用无向图表示校园景点,实现了查询景点信息和最短路径的佛洛伊德算法。实验二则通过邻接表实现无向图的深度优先遍历。程序提供了创建图、遍历图和求解最短路径的功能。
摘要由CSDN通过智能技术生成

1、实验目的:

1、熟悉图遍历的两种方法:深度优先与广度优先;

2、掌握编程实现图遍历具体算法;

3、掌握图的概念和结构特征,以及各种存储结构的特点及适用范围;

4、了解最小生成树有关算法。

二、实验内容:

选题1: 校园导游程序

用无向网表示你所在学校的校园景点的平面图,图中顶点表示主要景点如图书馆、教学楼、实验楼、办公楼、学生活动中心和学生宿舍楼等,顶点的Info域存放景点的编号、名称、简介等信息,图中的边表示景点间的道路,存放路径长度等信息。

要求实现以下功能:

1、查询各景点的相关信息;

2、查询图中任意两个景点间的最短路径。

选题2: 无向图的遍历程序

以邻接表为存储结构,以递归形式实现无向连通图的深度优先遍历。以用户指定的结点为起点,输出深度优先遍历下的结点访问序列和相应生成树的边集。

三、数据类型定义及功能模块声明

选题1: 校园导游程序

#define MaxInt 32767
#define MVNum 100

typedef struct message
{
    int num;          //景点代码
    char name[100];    //景点名称
    char pro[500];      //简介
} Ciceroni;

typedef Ciceroni VerTexType;
typedef int ArcType;
typedef struct
{
    VerTexType vexs[MVNum];
    ArcType arcs[MVNum][MVNum];
    int vexnum, arcnum;
} AMGraph;

选题2: 无向图的遍历程序

#define MAX_VERTEX_NUM 30           //图的最大顶点数不超过30个
#define MAXQSIZE 40                 //队列的最大容量


typedef struct ArcNode
{
	int adjvex;                      //顶点位置
	struct ArcNode* nextarc;         //指向下一条弧的指针
}ArcNode;                            //弧结点

typedef struct {
	ArcNode* AdjList[MAX_VERTEX_NUM];            //指向第一条依附该顶点的弧的指针
	int vexnum, arcnum;                          //图的当前顶点和弧数
}Graph;

typedef struct                       //队列结构
{
	int elem[MAXQSIZE];              //数据域
	int front;                       // 队头指针
	int rear;                       // 队尾指针
}SqQueue;

四、主要算法

选题1: 校园导游程序

//地图的创建
void CreatMap(AMGraph& G)
{
    int i, j;
    G.vexnum = 10;
    G.arcnum = 12;
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
            G.arcs[i][j] = MaxInt;
    //已知路线长度
    G.arcs[0][1] = 150;
    G.arcs[0][2] = 100;
    G.arcs[1][9] = 200;
    G.arcs[2][3] = 200;
    G.arcs[2][9] = 300;
    G.arcs[2][4] = 300;
    G.arcs[3][6] = 200;
    G.arcs[4][5] = 100;
    G.arcs[4][7] = 50;
    G.arcs[5][6] = 100;
    G.arcs[7][8] = 50;
    G.arcs[8][9] = 100;

    for (i = 0; i < 10; i++)
        G.vexs[i] = school[i];
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
            G.arcs[j][i] = G.arcs[i][j];
}
//佛洛伊德算法求vi,vj之间最短距离
void ShortestPath_Floyd(AMGraph G)
{
    int i, j, k, D[MVNum][MVNum], path[MVNum][MVNum];
    int place[MVNum];
    int v0, v1;
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
        {
            D[i][j] = G.arcs[i][j];
            if (D[i][j] < MaxInt && i != j)
                path[i][j] = i;//j前驱为i
            else
                path[i][j] = -1;//j前驱为-1
        }
    for (k = 0; k < G.vexnum; k++)
        for (i = 0; i < G.vexnum; i++)
            for (j = 0; j < G.vexnum; j++)
                if (D[i][k] + D[k][j] < D[i][j])//从i到k,再到j路径更短
                {
                    D[i][j] = D[i][k] + D[k][j];
                    path[i][j] = path[k][j];
                }
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
            if (i == j)
                D[i][j] = D[j][i] = 0;
    cout << "请输入起点:";
    cin >> v0;
    cout << "请输入终点:";
    cin >> v1;
    v0--;
    v1--;//下标从0开始
    int t = v1;//v1接下来会改变,寄存给t
    i = 0;
    cout << "【" << G.vexs[v0].name << "】到【" << G.vexs[v1].name << "】的最短距离为 " << D[v0][v1] << " m\n";
    cout << "\n其最短路线为 :【" << G.vexs[v0].name << "】<->";
    while (path[v0][v1] != v0)
    {
        place[i] = path[v0][v1];
        i++;
        v1 = path[v0][v1];
    }
    i--;
    for (i; i >= 0; i--)
        cout << "【" << G.vexs[place[i]].name << "】<->";
    cout << "【" << G.vexs[t].name << "】" << endl;
}

选题2: 无向图的遍历程序

void DFSTraverse(Graph G)
{
	
	int i;
	cout << "深度优先遍历结果为:" << endl;
	for (i = 1; i <= G.vexnum; i++)
		visited[i] = false;               //访问标志数组初始化
	for (i = 1; i <= G.vexnum; i++)
		if (!visited[i]) DFS(G, i);
	cout << endl;
}
//从第i个顶点出发递归地深度遍历图G
void DFS(Graph G, int i) {
	
	int w;
	visited[i] = true;                                             //访问第i个顶点
	cout << i << "  ";
	for (w = firstAdjVex(G, i); w > 0; w = NextAdjVex(G, i, w))
		if (!visited[w]) DFS(G, w);                                    //对尚未访问的邻接顶点w调用DFS
}
//在图G中寻找第v个顶点的第一个邻接顶点
int firstAdjVex(Graph G, int v)
{
	
	if (!G.AdjList[v])
		return 0;
	else
		return(G.AdjList[v]->adjvex);
}
//在图中寻找第v个顶点的相对于u的下一个邻接顶点
int NextAdjVex(Graph G, int v, int u)
{
	
	ArcNode* p;
	p = G.AdjList[v];
	while (p->adjvex != u) p = p->nextarc;                    //在顶点v的弧链中找到顶点u
	if (p->nextarc == NULL)
		return 0;                                             //若已经是最后一个结点,返回0
	else
		return(p->nextarc->adjvex);                           //返回下一个邻接顶点的序号
}

五、测试数据及运行结果

选题1: 校园导游程序

 

选题2: 无向图的遍历程序

 六、源代码

选题1: 校园导游程序

#include <iostream>
using namespace std;

#define MaxInt 32767
#define MVNum 100

typedef struct message
{
    int num;          //景点代码
    char name[100];    //景点名称
    char pro[500];      //简介
} Ciceroni;

typedef Ciceroni VerTexType;
typedef int ArcType;
typedef struct
{
    VerTexType vexs[MVNum];
    ArcType arcs[MVNum][MVNum];
    int vexnum, arcnum;
} AMGraph;

//存储地点基本信息
Ciceroni  school[20] = { {1,"北苑13栋","修仙者永不关灯"},{2,"食堂","干饭人的天堂"},{3,"博雅楼","考研人永不言败"},
    {4,"西操场","足球网又该换了"},{5,"明德楼","早八噩梦之地"},{6,"求真楼","打疫苗,来根针吧"},{7,"图书馆","好久没去了,忘记里面啥样了"},
    {8,"广学楼","新装修就是不一样"},{9,"慎思楼","它的六楼好难爬"},{10,"博文楼","博雅楼我兄弟"}
};

//地图的创建
void CreatMap(AMGraph& G)
{
    int i, j;
    G.vexnum = 10;
    G.arcnum = 12;
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
            G.arcs[i][j] = MaxInt;
    //已知路线长度
    G.arcs[0][1] = 150;
    G.arcs[0][2] = 100;
    G.arcs[1][9] = 200;
    G.arcs[2][3] = 200;
    G.arcs[2][9] = 300;
    G.arcs[2][4] = 300;
    G.arcs[3][6] = 200;
    G.arcs[4][5] = 100;
    G.arcs[4][7] = 50;
    G.arcs[5][6] = 100;
    G.arcs[7][8] = 50;
    G.arcs[8][9] = 100;

    for (i = 0; i < 10; i++)
        G.vexs[i] = school[i];
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
            G.arcs[j][i] = G.arcs[i][j];
}
void PrintMap()
{
    cout << "\n";
    cout << "                【学校地图】\n";
    cout << "食堂(2)--------北苑13栋(1)                      \n";
    cout << " |                 |                             \n";
    cout << "博文楼(10)------博雅楼(3)------------ 西操场(4) \n";
    cout << " |                  |                     |      \n";
    cout << "慎思楼(9)-广学楼(8)-明德楼(5)-求真楼(6)-图书馆(7)\n\n";
}

void PrintPlace(AMGraph G, int num)
{
    cout << "【景点编码】:" << G.vexs[num - 1].num << "\n【景点名称】:" << G.vexs[num - 1].name << "\n【景点简介】:" << G.vexs[num - 1].pro << endl;
}



void Menu()                                
{
    cout << "┍---------------------------------------┑"<<endl;
    cout << " *************校园导游程序】************** " <<endl;
    cout << " **********【1】--查看学校平面图**********"<<endl;
    cout << " **********【2】--求两景点之间的最短路径**"<<endl;
    cout << " **********【3】--查看指定景点信息********"<<endl;
    cout << " **********【0】--退出程序****************"<<endl;
    cout << "┕----------------------------------------┙"<<endl;
    cout << "请输入指令(0-3):";
}
//查找地点
int CheckNum(int num, AMGraph G)
{
    for (int i = 0; i < G.vexnum; i++)
        if (G.vexs[i].num == num)
            return 1;
    return 0;
}



//佛洛伊德算法求vi,vj之间最短距离
void ShortestPath_Floyd(AMGraph G)
{
    int i, j, k, D[MVNum][MVNum], path[MVNum][MVNum];
    int place[MVNum];
    int v0, v1;
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
        {
            D[i][j] = G.arcs[i][j];
            if (D[i][j] < MaxInt && i != j)
                path[i][j] = i;//j前驱为i
            else
                path[i][j] = -1;//j前驱为-1
        }
    for (k = 0; k < G.vexnum; k++)
        for (i = 0; i < G.vexnum; i++)
            for (j = 0; j < G.vexnum; j++)
                if (D[i][k] + D[k][j] < D[i][j])//从i到k,再到j路径更短
                {
                    D[i][j] = D[i][k] + D[k][j];
                    path[i][j] = path[k][j];
                }
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; j++)
            if (i == j)
                D[i][j] = D[j][i] = 0;
    cout << "请输入起点:";
    cin >> v0;
    cout << "请输入终点:";
    cin >> v1;
    v0--;
    v1--;//下标从0开始
    int t = v1;//v1接下来会改变,寄存给t
    i = 0;
    cout << "【" << G.vexs[v0].name << "】到【" << G.vexs[v1].name << "】的最短距离为 " << D[v0][v1] << " m\n";
    cout << "\n其最短路线为 :【" << G.vexs[v0].name << "】<->";
    while (path[v0][v1] != v0)
    {
        place[i] = path[v0][v1];
        i++;
        v1 = path[v0][v1];
    }
    i--;
    for (i; i >= 0; i--)
        cout << "【" << G.vexs[place[i]].name << "】<->";
    cout << "【" << G.vexs[t].name << "】" << endl;
}


void Order(AMGraph G)
{
    while (1)
    {
        int x, num, visited[MVNum] = { 0 };;
        Menu();
        cin >> x;
        switch (x)
        {
        case 0:
            cout << "成功退出程序...爱你呦...欢迎下次光临"<<endl;
            return;
            break;
        case 1:
            PrintMap();      
            break;
        case 2:
            ShortestPath_Floyd(G);
            break;
        case 3:
            cout << "请输入查找景点编码:";
            cin >> num;
            if (!CheckNum(num, G))
                cout << "无效编码!" << endl;
            else
                PrintPlace(G, num);                   
            break;
        default:
            cout << "无效指令!" << endl; 
            system("cls");
        }
    }
}
int main()
{
    AMGraph G;
    CreatMap(G);
    Order(G);
    return 0;
}

选题2: 无向图的遍历程序

 

#include<iostream>
using namespace std;

#define MAX_VERTEX_NUM 30           //图的最大顶点数不超过30个
#define MAXQSIZE 40                 //队列的最大容量

enum BOOL { False, True };

typedef struct ArcNode
{
	int adjvex;                      //顶点位置
	struct ArcNode* nextarc;         //指向下一条弧的指针
}ArcNode;                            //弧结点

typedef struct {
	ArcNode* AdjList[MAX_VERTEX_NUM];            //指向第一条依附该顶点的弧的指针
	int vexnum, arcnum;                          //图的当前顶点和弧数
}Graph;

typedef struct                       //队列结构
{
	int elem[MAXQSIZE];              //数据域
	int front;                       // 队头指针
	int rear;                       // 队尾指针
}SqQueue;

BOOL visited[MAX_VERTEX_NUM];       //全局变量——访问标志数组
void CreateGraph(Graph&);          //生成图的邻接表
void DFSTraverse(Graph);            //深度优先搜索遍历图
void DFS(Graph, int);
void Initial(SqQueue&);            //初始化一个队列
bool QueueEmpty(SqQueue);           //判断队列是否为空
bool EnQueue(SqQueue&, int);       //将一个元素入队列
bool DeQueue(SqQueue&, int&);     //将一个元素出队列
int firstAdjVex(Graph, int);        //求图中某一顶点的第一个邻接顶点
int NextAdjVex(Graph, int, int);    //求某一顶点的下一个邻接顶点

									
									
//构造邻接表结构的图G
void CreateGraph(Graph& G) {
	
	int i;
	int start, end;
	ArcNode* s;
	for (i = 1; i <= G.vexnum; i++)
		G.AdjList[i] = NULL;                              //初始化指针数组
	if (G.arcnum == 0) {
		cout << "The graph have no edges." << endl;
	}
	else {
		for (i = 1; i <= G.arcnum; i++)
		{
			cin >> start >> end;                              //输入弧的起点和终点
			s = (ArcNode*)malloc(sizeof(ArcNode));           //生成一个弧结点
			s->nextarc = G.AdjList[start];                    //插入到邻接表中
			s->adjvex = end;
			G.AdjList[start] = s;
			{
				s = (ArcNode*)malloc(sizeof(ArcNode));
				s->nextarc = G.AdjList[end];
				s->adjvex = start;
				G.AdjList[end] = s;
			}
		}
	}
}
//深度优先遍历图G
void DFSTraverse(Graph G)
{
	
	int i;
	cout << "深度优先遍历结果为:" << endl;
	for (i = 1; i <= G.vexnum; i++)
		visited[i] = False;               //访问标志数组初始化
	for (i = 1; i <= G.vexnum; i++)
		if (!visited[i]) DFS(G, i);
	cout << endl;
}
//从第i个顶点出发递归地深度遍历图G
void DFS(Graph G, int i) {
	
	int w;
	visited[i] = True;                                             //访问第i个顶点
	cout << i << "  ";
	for (w = firstAdjVex(G, i); w > 0; w = NextAdjVex(G, i, w))
		if (!visited[w]) DFS(G, w);                                    //对尚未访问的邻接顶点w调用DFS
}
//在图G中寻找第v个顶点的第一个邻接顶点
int firstAdjVex(Graph G, int v)
{
	
	if (!G.AdjList[v])
		return 0;
	else
		return(G.AdjList[v]->adjvex);
}
//在图中寻找第v个顶点的相对于u的下一个邻接顶点
int NextAdjVex(Graph G, int v, int u)
{
	
	ArcNode* p;
	p = G.AdjList[v];
	while (p->adjvex != u) p = p->nextarc;                    //在顶点v的弧链中找到顶点u
	if (p->nextarc == NULL)
		return 0;                                             //若已经是最后一个结点,返回0
	else
		return(p->nextarc->adjvex);                           //返回下一个邻接顶点的序号
}
//队列初始化
void Initial(SqQueue& Q)
{
	
	Q.front = Q.rear = 0;
}
//判断队列是否已空,若空返回True,否则返回False
bool QueueEmpty(SqQueue Q) {
	
	if (Q.front == Q.rear)
		return True;
	else
		return False;
}
//入队列,成功返回True,失败返回False
bool EnQueue(SqQueue& Q, int ch)
{
	
	if ((Q.rear + 1) % MAXQSIZE == Q.front)
		return False;
	Q.elem[Q.rear] = ch;
	Q.rear = (Q.rear + 1) % MAXQSIZE;
	return True;
}
//出队列,成功返回True,并用ch返回该元素值,失败返回False
bool DeQueue(SqQueue& Q, int& ch)
{
	
	if (Q.front == Q.rear)
		return False;
	ch = Q.elem[Q.front];
	Q.front = (Q.front + 1) % MAXQSIZE;
	return True;
}
int main() {
	Graph G;                      
	cout << "请输入无向图的顶点数和边数 :" << endl;
	cin >> G.vexnum >> G.arcnum;
	cout << "请输入弧的起点和终点:" << endl;
	CreateGraph(G);
	DFSTraverse(G);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

游天河

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

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

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

打赏作者

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

抵扣说明:

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

余额充值