最小生成树
- 说明:本人还是初学者,以下给出的代码是教材数据结构C语言版第二版(严蔚敏 李冬梅 吴伟民 编著)中关于最小生成树Kruskal算法代码段的整合,本人用于简单的城市间道路网课程设计,仅供参考。
- 完整代码:
#include <iostream>
using namespace std;
#include <fstream>
#define MaxInt 32767 //表示极大值,即 ∞
#define MVNum 100 //最大顶点数
#define OK 1
typedef char VerTexType; //假设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整形
ifstream infile; //定义输入文件流对象
typedef struct
{//图的邻接矩阵存储表示
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵
int vexnum, arcnum; //图的当前点数和边数
}AMGraph;
AMGraph G;
typedef struct Edge
{
VerTexType Head; //边的始点
VerTexType Tail; //边的终点
ArcType lowcost; //边上的权值
};
Edge Edges[MVNum]; //辅助数组Edges和E的定义
Edge E;
int Vexset[MVNum]; //辅助数组Vexset存放
int LocateVex(AMGraph G, char u)
{//返回顶点u在图G中的位置
int i;
for (i = 0; i<G.vexnum; ++i) //输入的顶点u与顶点表中的顶点依次比较
if (u-G.vexs[i]=='\0')
return i;
return OK;
}
int CreateUDN(AMGraph &G)
{//采用邻接矩阵表示法,创建无向图G
infile>> G.vexnum >> G.arcnum; //输入总顶点数,总边数
for (int i = 0; i<G.vexnum; i++) { //依次输入点的信息
infile>> G.vexs[i];
}
for (int i = 0; i<G.vexnum; i++) { //初始化邻接矩阵,边的权值均置为极大值MaxInt
for (int j = 0; j<G.vexnum; ++j) {
G.arcs[i][j] = MaxInt;
}
}
for (int k = 0; k<G.arcnum; ++k) {
char v1, v2;
int i, j, w;
infile >> v1 >> v2 >> w; //输入一条边依附的顶点和权值
i = LocateVex(G, v1); j = LocateVex(G, v2); //确定v1和v2在G中的位置,即顶点数组的下标
G.arcs[i][j] = w; //边<v1,v2>的权值置为w
G.arcs[j][i] = G.arcs[i][j]; //置<v1,v2>的对称边<v2,v1>的权值为w
}
return OK;
}
int Sort(Edge Edges[])
{//将数组Edge中的元素按权值从小到大排序
int i,j,k=0;
for (i = 0; i<G.vexnum; i++) { //边集数组初始化,只考虑上三角矩阵
for (j = i; j<G.vexnum; j++) {
if (G.arcs[i][j]!=MaxInt) {
Edges[k].Head = G.vexs[i];
Edges[k].Tail = G.vexs[j];
Edges[k].lowcost = G.arcs[i][j];
k++;
}
}
}
for (i = 0; i<G.arcnum-1; i++) { //对边集数组进行选择排序
for (j = i + 1; j<G.arcnum; j++) {
if (Edges[i].lowcost > Edges[j].lowcost) {
E = Edges[i];
Edges[i] = Edges[j];
Edges[j] = E;
}
}
}
}
void MiniSpanTree_Kruskal(AMGraph G)
{//无向网G以邻接矩阵形式存储,构造G的最小生成树T,输出T的各条边
int v1, v2, vs1, vs2;
int min=0;
Sort(Edges); //将数组Edge中的元素按权值从小到大排序
for (int i = 0; i<G.vexnum; i++) //辅助数组,表示各顶点自成一个连通分量
Vexset[i] = i;
cout<<"最小生成树中包括的城市间的道路有:"<<endl;
for (int i = 0; i<G.arcnum; i++) { //依次查看数组Edge中的边
v1 = LocateVex(G, Edges[i].Head); //v1为边的始点Head的下标
v2 = LocateVex(G, Edges[i].Tail); //v2为边的终点Tail的下标
vs1 = Vexset[v1]; //获取Edge[i]的始点所在的连通分量vs1
vs2 = Vexset[v2]; //获取Edge[i]的终点所在的连通分量vs2
if (vs1 != vs2) { //边的两个顶点分属不同的连通分量
cout <<"边:"<<Edges[i].Head <<"--"<< Edges[i].Tail
<<",权值:"<<Edges[i].lowcost<<endl; //输出此边和权值
min=min+Edges[i].lowcost; //累加计算最小生成树的代价
for (int j = 0; j<G.vexnum; j++) //合并vs1和vs2两个分量,即两个集合统一编号
if (Vexset[j] == vs2) Vexset[j] = vs1; //集合编号为vs2的都改为vs1
}
}
cout<<"最小生成树的代价为:"<<min<<endl;
}
int sc()
{
cout<<"输出城市间距离网的邻接矩阵:"<<endl;
for (int i = 0; i<G.vexnum; i++) {
for (int j = 0; j<G.vexnum; j++) {
if (G.arcs[i][j] == MaxInt) //将MaxInt的数值替换为字符 ∞
cout<<"∞"<<" ";
else
cout<<G.arcs[i][j]<<" ";
}
cout<<endl;
}
return OK;
}
int main()
{
infile.open("1.txt",ios::in);
if(!infile) {
cerr<<"文件打开失败!"<<endl;
exit(1);
}
CreateUDN(G);
sc();
MiniSpanTree_Kruskal(G);
}
文件格式示例:
结果如下: