算法及结构
Prim算法分析
从连通网N=(VE)中的某一顶点U0出发,选择与它关联的具有最小权值的边(U0,v),将 其顶点加入到生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u,v),把它的顶点加入到集合U中。如此继续下去, 直到网中的所有顶点都加入到生成树顶点集合U中为止。
假设网中有n个顶点,则第一个进行初始化的循环语句的频度为n,第二个循环语句的频度为n-1;其中有两个内循环:其一是在closedge[v].lowcost中求最小值,其频度为n-1;其二是重新选择具有最小代价的边,其频度为n。由此普里姆算法的空间复杂度为O(n),时间复杂度为O(n^2),与网中的边数无关,因此适用于求边稠密的网的最小生成树。
Kruskal算法分析
从另一途径求网的最小生成树。假设连通网N=(V{E}),则令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V0),图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。以此类推,直至T中所有顶点都在同一连通分量上为上。
该算法至多对e条边各扫描一次,则每次选择最小代价的边仅需O(loge)的时间(第一次需O(e))。又生成树T的每个连通分量可以看成是一个等价类,则构造T加入新的边的过程类似于求等价类的过程,构造T的过程仅需O(eloge)的时间,由此,克鲁斯卡尔算法的时间复杂度为O(eloge)。
算法比较
代码实现
#include<stdio.h>
#include<iostream>
using namespace std;
#define Maxint 999 // 权值
#define Mvnum 100 //最大点数
typedef char Vertextype; //顶点
typedef int Arctype; //边权
typedef struct
{
Vertextype vexs[Mvnum]; //顶点表
Arctype arcs[Mvnum][Mvnum]; //邻接矩阵
int vexum, arcnum; //当前点数和边数
}AMGraph;
struct a
{
char adjvex; //最小边在U中的那个顶点
int lowcost; //最小边上的权值
};
struct a closedge[Mvnum];
struct
{
char Head;
char Tail;
int lowcost;
}Edge[Mvnum];
//转换
int locat(AMGraph G, char v)
{
int i=0;
for ( i= 0; i <G.vexum; i++)
{
if (G.vexs[i] == v)
return i;
}
}
void Createudn(AMGraph& G)
{
char v1, v2;
int i, j,w;
cout<<"请输入邻接矩阵的点数和边数:";
cin >> G.vexum >> G.arcnum;
cout<<"输入点 :";
for (i = 0; i <G.vexum; ++i)
{
cin >> G.vexs[i];
}
for ( i = 0; i <G.arcnum; i++)
{
for ( j = 0; j <G.arcnum; j++)
{
G.arcs[i][j] = Maxint;
}
}
cout<<"输入边与权值"<<endl;
for (int k = 0; k <G.arcnum; k++)
{
cin >> v1 >> v2 >>w;
i = locat(G, v1);
j = locat(G, v2);
G.arcs[i][j] = w;
G.arcs[j][i] = w;
Edge[k].Head=v1;
Edge[k].Tail=v2;
Edge[k].lowcost=w;
}
}
int Min(AMGraph G,a closedge[]) //返回最小代价边
{
int min = 999;
int index = -1;
for (int i = 0; i <G.vexum;i++)
{
if (closedge[i].lowcost < min && closedge[i].lowcost !=0)
{
min = closedge[i].lowcost;
index = i;
}
}
return index;
}
void PRIM(AMGraph G)
{
char u='B';
char u0,v0;
int sum=0;
int k,i,j;
// cout<<"input u :";
// cin>>u;
k=locat(G,u);
for(j=0;j<G.vexum;++j)
if(j!=k)
{
// cout<<u<<endl;
closedge[j].adjvex=u;
// cout<<"closedge[j].adjvex "<<closedge[j].adjvex<<endl;
closedge[j].lowcost=G.arcs[k][j];
// cout<<"closedge[j].lowcost "<<closedge[j].lowcost<<endl;
}
closedge[k].lowcost=0;
for(i=1;i<G.vexum;++i)
{
k=Min(G,closedge);
// cout<<"K="<<k<<endl;
u0=closedge[k].adjvex;
// cout<<"u0="<<u0<<endl;
v0=G.vexs[k];
// cout<<"v0="<<v0<<endl;
cout<<u0<<"—"<<v0<<" 边权为 "<<closedge[k].lowcost<<endl;
sum+=closedge[k].lowcost;
// cout<<endl;
closedge[k].lowcost=0;
for(j=0;j<G.vexum;++j)
{
if(G.arcs[k][j]<closedge[j].lowcost)
{
closedge[j].adjvex=G.vexs[k];
// cout<<"closedge[j].adjvex "<<closedge[j].adjvex<<endl;
closedge[j].lowcost=G.arcs[k][j];
// cout<<"closedge[j].lowcost "<<closedge[j].lowcost<<endl;
}
}
}
cout<<"边权总值为 :"<<sum<<endl;
}
void show(AMGraph &G)
{
for(int i=0;i<G.vexum;i++)
{
cout<<"* ";
for(int j=0;j<G.vexum;j++)
{
if(G.arcs[i][j]==999)
printf("∞ ");
// cout<<"∞"<<" ";
else
printf("%02d ",G.arcs[i][j]);
// cout<<G.arcs[i][j]<<" ";
}
cout<<" *"<<endl;
}
}
void kruskal(AMGraph &G)
{
int Vexset[Mvnum];
int i,j;
int sum=0;
char v1,v2;
int vs1,vs2;
for(i=0;i<G.vexum;i++) Vexset[i]=i;
for(i=0;i<G.arcnum-1;i++)
{
for(j=i+1;j<G.arcnum;j++)
{
if(Edge[j].lowcost<Edge[i].lowcost)
{
Edge[G.arcnum].Head=Edge[j].Head;
Edge[G.arcnum].Tail=Edge[j].Tail;
Edge[G.arcnum].lowcost=Edge[j].lowcost;
Edge[j].Head=Edge[i].Head;
Edge[j].Tail=Edge[i].Tail;
Edge[j].lowcost=Edge[i].lowcost;
Edge[i].Head=Edge[G.arcnum].Head;
Edge[i].Tail=Edge[G.arcnum].Tail;
Edge[i].lowcost=Edge[G.arcnum].lowcost;
}
}
}
for(i=0;i<G.arcnum;i++)
{
v1=locat(G,Edge[i].Head);
v2=locat(G,Edge[i].Tail);
vs1=Vexset[v1];
vs2=Vexset[v2];
if(vs1!=vs2)
{
cout<<Edge[i].Head<<"—"<<Edge[i].Tail<<" 边权为 "<<Edge[i].lowcost<<endl;
// printf("%c %c %d\n",Edge[i].Head,Edge[i].Tail,Edge[i].lowcost);
sum+=Edge[i].lowcost;
for(j=0;j<G.vexum;j++) if(Vexset[j]==vs2) Vexset[j]=vs1;
}
}
cout<<"边权总值为 :"<<sum<<endl;
}
main()
{
int x;
AMGraph G;
Createudn(G);
printf("*********************************************************************\n");
printf("* 最小生成树模拟程序 *\n");
printf("* *\n");
show(G);//printf("* show(G); *\n");
printf("* *\n");
printf("* *\n");
printf("* 1、普里姆(Prim)算法构造最小生成树 *\n");
printf("* 2、克鲁斯卡尔(Kruscal)算法构造最小生成树 *\n");
printf("* *\n");
printf("*********************************************************************\n");
while(1)
{
printf("请选择:");
scanf("%d",&x);
switch(x)
{
case 1:
PRIM(G);
break;
case 2:
kruskal(G);
break;
}
}
}
测试用例
6 10
A B C D E F
A B 6
A C 1
A D 5
B C 5
B E 3
C D 5
C E 6
C F 4
D F 2
E F 6
实现效果图
最后的最后 xdjmm 点个赞叭