破圈法求最小生成树 实验
4.1 实验内容
根据书P262习题10给定的无向带权图,用破圈法构造其最小生成树。
所谓“破圈法”就是“任取一圈,去掉圈上权最大的边”,反复执行这一步骤,直到没有圈为止。请给出用“破圈法”求解给定的带权连通无向图的一最小生成树的详细算法,并用程序实现所给出的算法(注:圈就是回路)。
4.2开发环境等说明
开发环境版本 | VisualStudio 2022 | 工程文件名 | ex2_2_prim.sln |
头文件个数 | 5个 | 源程序文件个数 | 1个 |
文件名 | 文件类型 | 功能简介 | 备注 |
AdjMatrixUndirNetwork.h | 头文件 | 无向图的邻接矩阵类类模板头文件,包括数据成员及成员函数的声明与定义 | |
Edge.h | 头文件 | 边结点类模板头文件,包括数据成员及成员函数的声明与定义 | |
Assistance.h | 头文件 | 辅助软件包 | |
MaxHeap.h | 头文件 | 最大堆类模板头文件,包括数据成员及成员函数的声明与定义 | |
MiniSpanTreeTearCycle.h | 头文件 | 破圈法构造最小生成树 | |
text.cpp | 源文件 | 测试文件 |
4.3实现技术
1、邻接矩阵作为存储结构
在AdjMatrixUndirNetwork.h头文件中,用邻接矩阵类作为图的存储结构,该头文件中包含了邻接矩阵类的数据成员及成员函数的声明与定义(这里不做代码展示)。
2、最大堆存放边
在破圈法中,以边的权值为关键字构造一个最大堆(这里不做堆类的代码展示)
3、边结点类模板
在这个边类中定义了一条边依附的两个顶点vertexl、vertex2以及边的权weight。另外,除了构造函数外,重载了赋值运算、>=、<=、>、<四个关系运算。
template <class ElemType, class WeightType>
class Edge
{
public:
ElemType vertex1, vertex2;
WeightType weight;
Edge(ElemType v1, ElemType v2, WeightType w);
Edge() { vertex1 = 0; vertex2 = 0; weight = 0; };
Edge<ElemType, WeightType>& operator=(const Edge<ElemType, WeightType>& Ed);
bool operator >=(const Edge<ElemType, WeightType>& Ed);
bool operator <=(const Edge<ElemType, WeightType>& Ed);
bool operator >(const Edge<ElemType, WeightType>& Ed);
bool operator <(const Edge<ElemType, WeightType>& Ed);
};
4、判断无向网是否连通
在邻接矩阵类中声明并定义了函数IsConnect(),利用DFS遍历该无向图,遍历到的顶点就将其状态设为VISITED,后再用for循环遍历所有顶点,如果都为VISITED则该图连通,反之。
template <class ElemType, class WeightType>
bool AdjMatrixUndirNetwork<ElemType, WeightType>::IsConnect()
{
int p1 = 1;
DFSTraverse(Write<ElemType>);
for (int v = 0; v < this->GetVexNum(); v++)
if (this->GetTag(v) == UNVISITED)
p1 = 0;
return p1;
}
5、破圈法
连通图的生成树包括图中的全部n个顶点和足以使图连通的n-1条边,最小生成树是边上权值之和最小的生成树。故可按权值从大到小对边进行排序,然后从大到小将边
删除。每删除一条当前权值最大的边后,就测试图是否仍连通,若不再连通,则将该边恢复。不断重复上述过程,选取边进行删除,直到图中剩下n-1条边为止。
template <class ElemType,class WeightType>
void MiniSpanTreeTearCycle(AdjMatrixUndirNetwork<ElemType, WeightType>& g)
{
int count, VexNum = g.GetVexNum(), EdgeNum = g.GetEdgeNum();
Edge<ElemType, WeightType>edge;
MaxHeap< Edge<ElemType, WeightType>>ha(g.GetEdgeNum());//以边的权值为关键字建立一个最大堆
ElemType v1, v2;
int u, v;
for(v=0;v<g.GetVexNum();v++)
for(u=g.FirstAdjVex(v);u>=0;u=g.NextAdjVex(v,u))
if (v < u)
{
g.GetElem(v, v1);
g.GetElem(u, v2);
edge.vertex1 = v1;
edge.vertex2 = v2;
edge.weight = g.GetWeight(v, u);
ha.Insert(edge);
}
count = 0;
while ((EdgeNum - count) > VexNum - 1) {
ha.DeleteTop(edge);
v1 = edge.vertex1;
v2 = edge.vertex2;
v = g.GetOrder(v1);
u = g.GetOrder(v2);
g.DeleteArc(v, u);
if (g.IsConnect()) {
count++;
cout << "删除的第" << count << "边:(" << v1 << ", " << v2 << " )权:" << edge.weight << endl;
}
else
g.InsertArc(v, u, edge.weight);
}
}
4.4测试结果
1、测试实例
2、邻接矩阵作为存储结构
3、破圈法得到最小生成树
完整代码可看资源区
创作不易~麻烦点个赞~~谢谢大家~~~