数据结构实验三

学生实验报告

开课学院及实验室: 年 月 日
学院 年级、专业、班 姓名 学号
实验课程名称 数据结构 成绩
实验项目名称 图的操作与实现 指导老师
评语:
一、实验目的
1、图的邻接表和邻接矩阵存储
2、图的各种遍历算法实现
3、最小生成树的算法实现
4、最短路径的算法实现
二、使用仪器、器材
微机一台
编程软件:C++

三、实验内容及原理
<简要描述具体任务;填写程序设计中使用的数据结构及算法(算法思路和程序框架)>
利用图的邻接表或邻接矩阵存储结构设计并实现各种操作算法(任选一种存储结构来实现算法)。
1、图的邻接表和邻接矩阵存储
建立下图的邻接表或邻接矩阵,并输出之;

2、图的各种遍历算法实现
以0结点为起点实现上述图的深度优先和广度优先遍历算法;
3、最小生成树的算法实现
利用普里姆(Prim)算法或克鲁斯卡尔(Kruskal)算法求上图的最小生成树,算法实现代码必须有注释。
共有六个步骤:

4、最短路径的算法实现
利用狄克斯特拉(Dijkstra)算法求上图中0结点到其它结点的最短路径,算法实现代码必须有注释。
原理图:

四、实验过程原始数据记录
<代码/程序执行结果/操作结果>

根据上图做以下四个实验:
1、图的邻接表和邻接矩阵存储
建立下图的邻接表或邻接矩阵,并输出之;
代码部分:
#define MAXINT 32767
#define MVNum 100
typedef int VerTexType;
typedef int ArcType;
#define MAXSIZE 100
#include
using namespace std;
typedef struct
{
VerTexType vexs[MVNum];
ArcType arcs[MVNum][MVNum];
int vexnum, arcnum;
}AMGraph;
typedef struct LinkQueue
{
int* base;
int front;
int rear;
}LinkQueue;
typedef struct
{
VerTexType adjvex;//最小边
ArcType lowcost;
}close;
close closedge[MVNum];
int LocateVex(AMGraph G, VerTexType u)
{
int i = 0;
for (i = 0; i < G.vexnum; i++)
{
if (u == G.vexs[i])
{
return i;
}
}
return -1;
}
void CreateUDN(AMGraph& G)
{
cout << “Please Input G.vexnum && G.arcnum of Graph:” << endl;
cin >> G.vexnum >> G.arcnum;
cout << “Please Input Information of Vertex:” << ‘\n’;
for (int i = 0; i < G.vexnum; i++)
{
cin >> G.vexs[i];
}
for (int i = 0; i < G.vexnum; i++)
{
for (int j = 0; j < G.vexnum; j++)
{
G.arcs[i][j] = MAXINT;
}
}
cout << “Please Input vertices and weights attached to an edge:” << endl;
int i, j = 0;
for (int k = 0; k < G.arcnum; k++)
{
int v1, v2, w;
cin >> v1 >> v2 >> w;
i = LocateVex(G, v1);
j = LocateVex(G, v2);
G.arcs[i][j] = w;
G.arcs[j][i] = G.arcs[i][j];
}
}
void Show_Graph(AMGraph G)
{
for (int i = 0; i < G.vexnum; i++)
{
for (int j = 0; j < G.vexnum; j++)
{
if (G.arcs[i][j] == MAXINT)
{
cout << “∞” << ‘\t’;
}
else
{
cout << G.arcs[i][j] << ‘\t’;
}
if (j == G.vexnum - 1)
{
cout << ‘\n’;
}
}
}
}
程序运行结果:

2、图的各种遍历算法实现
以0结点为起点实现上述图的深度优先和广度优先遍历算法;
1.深度优先算法:
代码部分:
在前面的代码中,加入这部分函数:
bool visited[7];
void DFS(AMGraph G, int v)
{
cout << v << “->”;
visited[v] = true;
for (int w = 0; w < G.vexnum; w++)
{
if ((G.arcs[v][w] != 0) && (visited[w] == 0))
{
DFS(G,w);
}
}
}
int main()
{
AMGraph G;
CreateUDN(G);
cout << endl;
bool visited[7];
for (int i = 0; i < 7; i++)
{
visited[i] = false;
}
cout << “Depth first Traversal:” << endl;
DFS(G, 0);
cout << endl;
}
程序运行结果:

2.广度优先算法:
代码部分:
void InitQueue(LinkQueue& Q)
{
Q.base = new int[MAXSIZE];
if (Q.base == 0)
{
return ;
}
Q.front = Q.rear = 0;
}
void EnQueue(LinkQueue& Q,int e)
{
if ((Q.rear + 1) % MAXSIZE == Q.front)
{
return;
}
else
{
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXSIZE;
}
}
void DeQueue(LinkQueue& Q, int& e)
{
if (Q.front != Q.rear)
{
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXSIZE;
}
}
void BFS(AMGraph G, int v)
{
cout << v << “->”;
visited[v] = true;
LinkQueue Q;
InitQueue(Q);
EnQueue(Q, v);
int u = 0;
while (Q.front != Q.rear)
{
DeQueue(Q, u);
for (int w = 0; w < G.vexnum; w++)
{
if (visited[w] == 0)
{
cout << w << “->”;
visited[w] = true;
EnQueue(Q, w);
}
}
}
}
int main()
{
AMGraph G;
CreateUDN(G);
for (int i = 0; i < 7; i++)
{
visited[i] = false;
}
cout << “Breadth first Traversal:” << endl;
BFS(G, 0);
}
程序运行结果:

3、最小生成树的算法实现
利用普里姆(Prim)算法或克鲁斯卡尔(Kruskal)算法求上图的最小生成树,算法实现代码必须有注释。
由于Prim算法是归并顶点,与边数无关,适于稠密网。而该图还差两条边就到完全图了,所以我用prim算法。
代码部分:
int Min(close closeedge[])
{
int t = MAXINT;
int index = 0;
for (int i = 0; i < MVNum; i++)
{
if (closedge[i].lowcost != 0)
{
if (closedge[i].lowcost < t)
{
t = closedge[i].lowcost;
index = i;
}
}
}
return index;
}
void MiniSpanTree_Prim(AMGraph G, VerTexType u)
//无向网G以邻接矩阵形式存储,从顶点U出发构造G的最小生成树,输出T的各条边
{
int k = LocateVex(G, u);//k为顶点u的下标
for (int j = 0; j < G.vexnum; j++)//对V-U的每一个顶点vj,初始化closedge[j]
{
if (j != k)
{
closedge[j] = { u,G.arcs[k][j] };//{adjvex,lowcost}
}
}
closedge[k].lowcost = 0;//初始,U={u}
for (int i = 0; i < G.vexnum; i++)
{//选择其余n-1个顶点,生成n-1条边
k = Min(closedge);//求出T的下一个结点:第k个顶点,closedge[k]中存有当前最小边
VerTexType u0 = closedge[k].adjvex;//u0为最小边的一个顶点,u0∈u
VerTexType v0 = G.vexs[k];//v0为最小边的一个顶点,v0∈V-U
cout << u0 << “-” << v0 << " weight:" << closedge[k].lowcost << endl;
//输出当前最小边{u0,v0}
closedge[k].lowcost = 0;//第k个顶点并入u集
for (int j = 0; j < G.vexnum; j++)
{
if (G.arcs[k][j] < closedge[j].lowcost)//新顶点并入u后重新选择最小边
{
closedge[j] = { G.vexs[k],G.arcs[k][j] };
}
}
}
}
int main()
{
AMGraph G;
CreateUDN(G);
cout << “minimum spanning tree:” << endl;
MiniSpanTree_Prim(G, 0);
cout << endl;
}
程序运行结果:

4、最短路径的算法实现
利用狄克斯特拉(Dijkstra)算法求上图中0结点到其它结点的最短路径,算法实现代码必须有注释。
代码部分:
void ShortestPath_DIJ(AMGraph G, int v0)
//用Dijkstra算法求有向网G的v0顶点顶点到其余顶点的最短路径
{
int n = G.vexnum;//n为G中顶点的个数
bool S[MVNum];
int Path[MVNum];
int D[MVNum];
int v = 0;
for (v = 0; v < n; v++)//n个顶点依次初始化
{
S[v] = false;//S初始为空集
D[v] = G.arcs[v0][v];//将v0到各个终点的最短路径长度初始化为弧上的权值
if (D[v] < MAXINT)//如果v0和v有弧,则将v的前驱置为v0
{
Path[v] = v0;
}
Else//如果v0和v无弧,则将v的前驱置为-1
{
Path[v] = -1;
}
}
S[v0] = true;//将v0加入S
D[v0] = 0;//源点到源点的距离为0
for (int i = 1; i < n; i++)//对其余n-1个顶点,依次进行计算
{
int min = MAXINT;
for (int w = 0; w < n; w++)
{
if (!S[w] && D[w] < min)//选择一条当前的最短路径,终点为v
{
v = w;
min = D[w];
}
}
S[v] = true;//将v加入S
for (int w = 0; w < n; w++)//更新从v0出发到集合V-S上所有顶点的最短路径长度
{
if (!S[w] && (D[v] + G.arcs[v][w] < D[w]))
{
D[w] = D[v] + G.arcs[v][w];//更新D[w]
Path[w] = v;//更改w的前驱未v
}
}
}
for (int i = 0; i < n; i++)
{
cout << G.vexs[i] << “Shortest Path Length:” << D[i] << endl;
}
}
int main()
{
AMGraph G;
CreateUDN(G);
cout << “The shortest path from 0 node to other nodes:” << endl;
ShortestPath_DIJ(G, 0);
cout << endl;
}
代码运行部分:

五、实验结果及分析
<逐条列出代码编写过程中出现的错误,及改正的方案>
问题1:
在输出图的过程中,出现了以下问题:

怎么也找不到问题,后来发现我的LocateVex函数在建立邻接矩阵的下面,所以其无法调用。调整一下顺序就好了。
问题2:
输出矩阵时,出现以下问题:

发现除1个数不为正无穷,其它都是正无穷。而且这个数也是不对的。
刚开始以为是全局变量导致的:

后来全改为了局部变量,发现还是这样。
最后在检查LocateVex函数时发现,那个判断符号被我改成了赋值符号。

这样就可以了:

问题三:
在广度优先遍历时,出现了以下问题:

后来在BFS函数发现了一个错误,由于BFS算法类似于树的层序遍历,不需要递归。
所以要加上这些语句:
int p = 0;
p = LocateVex(G, v);
visited[p] = true;
需记录顶点在顶点数组中的位置,并返回v在G中的位置,执行循环时,若该顶点被访问过,则为1,否则为0.
可遍历后还是原样:

后来我以为我没重置visited数组,后来发现不是的。
最终我的解决方案是:
程序分开执行,先执行深度遍历:

再执行广度遍历:

但是我不太明白,深度遍历应该与广度遍历是不一样的
广度遍历大致应该是:
0->(1 5)->(2 4 6)->3//其中括号内的顺序可以任意调整;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值