最小生成树是数据结构中图的一种重要应用,它的要求是从一个带权无向完全图中选择n-1条边并使这个图仍然连通(也即得到了一棵生成树),同时还要考虑使树的权最小。 为了得到最小生成树,人们设计了很多算法,最著名的有prim算法和kruskal算法。时间复杂度分别为O(n2)和O(eloge)
假设V是途中顶点的集合,E是边的集合,T是最小生成树的边的集合。U为在最小生成树上点的集合,那么V-U为不在最小生成树上的点的集合。
Prim算法的基本思想:
1.首先选取一个点作为起始点,比如说1顶点,加入到U集合中
2.在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u,v),将此边加进集合T中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边以后,把这条边放到边集T中,并把这条边上不在U中的那个顶点加入到U中。
3:如果U=V,则算法结束;否则重复步骤2。可以把本步骤看成循环终止条件。我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。
代码实现:
总共需要3个数组,U【i】,标记节点是否已经加入到最小生成树当中
d【i】,记录U集合中到达V-U集合中顶点的最小边的权值
b【i】,记录最小权值边的顶点,即是从哪个点过来的边
#include <iostream>
using namespace std;
int edge[5][5]={{0,11,3,10,17},{11,0,12,2,1},{3,12,0,8,5},{10,2,8,0,1},{17,1,5,1,0}};
int u[5]={0}; //0表示都不在最小生成树中
int d[5]; //存放不在最小生成树上的节点到树上节点的最小的距离
int b[5]; //存放源节点,即最小生成树上的节点
int count=0;
void Print();
void Prim()
{
u[0]=1;
count++;
for(int i=1;i<5;i++)
{
d[i]=edge[0][i];
b[i]=0;
}
while(count<5)
{
int Max=10000;
int p;
for(int i=0;i<5;i++)
{
if(!u[i]&&d[i]<Max)
{
Max=d[i];
p=i;
}
}
u[p]=1;
count++;
for(int i=0;i<5;i++)
{
if(!u[i]&&d[i]>edge[p][i])
{
d[i]=edge[p][i];
b[i]=p;
}
}
}
}
int main()
{
int i;
Print();
Prim();
for(i=0;i<5;i++)
{
cout<<b[i]<<"";
}
cout<<endl;
for(i=0;i<5;i++)
{
cout<<u[i]<<"";
}
cout<<endl;
for(i=0;i<5;i++)
{
cout<<d[i]<<"";
}
cout<<endl;
system("pause");
return 0;
}
void Print()
{
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
cout<<edge[i][j]<<"";
cout<<endl;
}
}