一、实验目的
(1)掌握图的逻辑结构。
(2)掌握图的邻接矩阵存储结构。
(3)掌握图在邻接矩阵存储结构上遍历算法的实现。
(4)掌握图的邻接表存储结构。
(5)掌握图的邻接表存储结构上遍历算法的实现。
(6)理解图的最小生成树求解算法。
(7)理解拓扑排序算法。
(8)理解关键路径问题算法。
(9)理解图的最短路径求解算法。
二、实验环境(实验设备)
硬件: 微型计算机P4
软件: Windows 7 + Microsoft Visual Studio2019
三、实验内容(包括题目和要求、源码、运行结果截图等)
题目1. 统计有向图各顶点的度
实验要求:
- 实现一个模板函数StatDegree统计有向图各顶点的度;
- 利用编程模板中提供的主函数,测试算法正确性。
源码:
for (int v = 0; v < g.GetVexNum(); v++)
{
Degree[v] = 0;
}
for (int v1 = 0; v1 < g.GetVexNum(); v1++)
{
for (int v2 = g.FirstAdjVex(v1); v2 != -1; v2 = g.NextAdjVex(v1, v2))
{
Degree[v2]++;
Degree[v1]++;
}
}
运行结果截图:
题目2. 非递归深度优先遍历
实验要求:
(1)给无向图的邻接表类模板AdjListUndirGraph添加实现一个模板函数NonRecurDFS实现从一个顶点开始对无向图进行深度优先遍历,不使用递归。
(2)利用编程模板中提供的主函数,测试算法正确性。
源码:
template <class ElemType>
void AdjListUndirGraph<ElemType>::NonRecurDFS(int v, void (*visit)(const ElemType& e)) const
// 初始条件:存在图
// 操作结果:从顶点v出发对图进行深度优先遍历
{
SetTag(v, true);
ElemType e;
GetElem(v, e);
(*visit)(e);
for (int w = FirstAdjVex(v); w >= 0; w = NextAdjVex(v, w))
{
if (!GetTag(w)) NonRecurDFS(w, visit);
}
}
template <class ElemType>
void AdjListUndirGraph<ElemType>::NonRecurDFSTraverse(void (*visit)(const ElemType& e)) const
// 初始条件:存在图
// 操作结果:对图进行深度优先遍历
{
int v;
for (v = 0; v < GetVexNum(); v++)
{ // 对每个顶点设置访问标志
SetTag(v, false);
}
for (v = 0; v < GetVexNum(); v++)
{ // 对尚未访问的顶点按DFS进行深度优先搜索
if (!GetTag(v)) NonRecurDFS(v, visit);
}
}
运行结果截图:
题目3:距离最远的顶点
实验要求:
- 实现一个模板函数FathestVex返回距离索引为v的顶点最远的顶点索引;
- 利用编程模板中提供的主函数,测试算法正确性。
源码:
template <class ElemType>
int FarthestVex(const AdjListUndirGraph<ElemType>& g, int v)
// 操作结果:返回距离索引为v的顶点最远的顶点索引
{
int nums[100];
int n = int(g.GetVexNum());
for (int i = 0; i < n; i++) {
nums[i] = 0;
}
int Max = 0;
g.SetTag(v, true);
LinkQueue<int> queue;
queue.InQueue(v);
while (!queue.Empty())
{
int u, w;
queue.OutQueue(u);
for (w = g.FirstAdjVex(u); w >= 0; w = g.NextAdjVex(u, w))
{
if (!g.GetTag(w))
{
nums[w] = nums[u] + 1;
Max = max(Max, nums[w]);
g.SetTag(w, true);
queue.InQueue(w);
}
}
}
for (int i = 0; i < n; i++) {
g.SetTag(i, false);
if (nums[i] == Max) {
return i;
}
}
return v;
}
运行结果截图:
题目4.:判断有向图是否存在回路
实验要求:
- 实现一个模板函数HasCycle判断有向图g是否存在回路
- 利用编程模板中提供的主函数中测试算法正确性。
源码:
template <class ElemType>
bool HasCycle(const AdjListDirGraph<ElemType> g)
// 操作结果:判断有向图g是否存在回路
{
int n = g.GetVexNum();
int In[100];
int Out[100];
int visited[100];
for (int i = 0; i < n; i++) {
In[i] = 0;
Out[i] = 0;
visited[i] = 0;
}
for (int i = 0; i < n; i++) {
for (int w = g.FirstAdjVex(i); w >= 0; w = g.NextAdjVex(i, w)) {
Out[i]++;
In[w]++;
}
}
LinkQueue<int>queue;
for (int i = 0; i < n; i++) {
if (In[i] == 0) {
queue.InQueue(i);
visited[i] = 1;
}
}
int idx;
while (!queue.Empty()) {
queue.OutQueue(idx);
visited[idx] = 1;
for (int w = g.FirstAdjVex(idx); w >= 0; w = g.NextAdjVex(idx, w)) {
In[w]--;
if (In[w] == 0) {
queue.InQueue(w);
}
}
}
for (int i = 0; i < n; i++) {
if (!visited[i]) {
return true;
}
}
return false;
}
运行结果截图:
题目5. 判断两个顶点间是否存在路径
实验要求:
(1)实现一个模板函数ExistPath判断有向图g中两个顶点i和j之间是否存在路径。
(2)利用编程模板中提供的主函数,测试算法正确性。
源码:
template <class ElemType>
bool ExistPath(const AdjListDirGraph<ElemType> g, int i, int j)
// 操作结果:判断有向图g中两个顶点i和j之间是否存在路径
{
int n = g.GetVexNum();
for (int i = 0; i < n; i++) {
g.SetTag(i, false);
}
g.SetTag(i, true);
LinkQueue<int> queue;
queue.InQueue(i);
while (!queue.Empty())
{
int u, w;
queue.OutQueue(u);
for (w = g.FirstAdjVex(u); w >= 0; w = g.NextAdjVex(u, w))
{
if (w == j) {
return true;
}
if (!g.GetTag(w))
{
g.SetTag(w, true);
queue.InQueue(w);
}
}
}
return false;
}
运行结果截图:
四、实验小结(包括实验过程中遇到问题和解决方法、心得体会等)
通过做图结构实验,我们可以得到以下总结:
1. 图形的拓扑结构:对于一组给定的节点和它们之间的边,可以确定它们之间的拓扑关系,例如是否为连通图、是否存在环、是否为树状结构等。
2. 组成图形的基本元素:图形由节点和边组成。通过实验可以了解两者的性质和特点。
3. 对节点和边进行操作:在图形上,我们可以包括删除、添加、连接、断开等一系列操作,这些操作会影响整个图形的结构和性质。
4. 搜索算法:在拓扑结构中,搜索是一个非常重要的问题,因为它涉及到从起始节点遍历到目标节点的路径问题。实验可以帮助我们了解不同的搜索算法,并比较它们之间的优缺点。
5. 培养了分析问题和解决问题的思维能力:通过解决问题来分析和理解不同数据结构,训练自己独立解决实际问题的能力。
总之,通过做图结构实验,我们可以更深入地了解图形结构的本质和基本原则,这对于许多领域的理论研究和实际应用都具有重要的价值。