贪心法之最小生成树之Prim算法

来源:互联网 发布:什么是微观数据 编辑:程序博客网 时间:2024/05/21 03:16
A,最小生成树:最小生成树在现实生活中有很多重要的应用,它要求从一个带权无向完全图G(假设有n个顶点)中选择n-1条边并使图(没有回路的树)仍然连通,同时还要求生成树的总权重最小,为了构造这样一棵树,通常的算法有Kruskal和Prim算法,上一篇介绍Kruskal算法,下面将介绍Prim算法。
B,普里姆(Prim)算法:和Kruskal算法不同的是,Prim算法操作的对象不是边而是顶点,因此Kruskal算法复杂度和图中边的条数有关,适合稀疏图中构造最小生成树,而Prim适合边密集图,因为它只关心图中有多少个顶点。Prim算法每次从剩下的顶点中选择一个最优的顶点加入已有的顶点集合当中,显然这也是贪心法的思想。下面详细介绍原理和实现。
C,算法处理过程:
1)假设带权无向图有N个顶点;
2)有两个数组U[]和S[],其中U表示已加入的图中的顶点,S=N-U即图中剩下未加入的顶点集合;
3)每次都用贪心法思想,在U中找一点v1,S中找一点v2,满足边v1->v2的权值是所有边中最小的;
4)然后把v2加入到集合U中,并把它从S中去掉;
5)重复步奏3)和 4),直到U中的顶点数为N,算法结束;
6)U中所有的顶点构成一棵满足要求的树。
下图为用Prim算法构造一棵最小生成树的过程:
贪心法之最小生成树之Prim算法

D,算法实现:
#include "iostream"
using namespace std;
#define MAXVEX 50//图中最大节点数
#define MAXIMUN 65535//定义为最大数

typedef struct //定义邻接矩阵的数据结构
{
char vexs[MAXVEX];
int edges[MAXVEX][MAXVEX];
int vexNum, adgeNum;//分别表示图中节点个数和边的条数
}AGraph;
int main()
{
void createAG(AGraph *);
void prim(AGraph*);
AGraph g;
createAG(&g);
prim(&g);
return 0;
}
//Prim算法求解最小生成树
void prim(AGraph *g)
{
int U[MAXVEX], S[MAXVEX], n =0;//U存放以加入的顶点,S存放剩余的顶点,已加入U中的顶点个数
int min = 0;//用于保存生成树的总权值
for(int i = 0; i < g->vexNum;++i)//将图中的顶点存入S中,只存储顶点的编号.
{
S[i] = i;
}
//将任意一个顶点放入集合U中,这里假设放入0号顶点
U[0] = 0;
++n;
//同时从S中去掉0号顶点,这里赋值为-1
S[0] = -1;
cout<<"\n最小生成树由这些边构成:\n";
for(int j = 1; j < g->vexNum; ++j)
{
int mintemp = MAXIMUN;
int indexK, indexP;
//贪心法寻找最优加入顶点并用index记录其位置
for(int k = 0; k < n; ++k)
{
for(int p = 0; p < g->vexNum; ++p)
if((S[p] != -1) && (mintemp >g->edges[U[k]][p]))
{
indexK = U[k];
indexP = p;
mintemp = g->edges[indexK][indexP];
}
}
U[n++] = indexP;//将顶点加入U中
S[indexP] = -1;//将该顶点从S中去掉
min += mintemp;
cout<<g->vexs[indexK]<<"->"<<g->vexs[indexP]<<" ";
}
cout<<"\n最小生成树的总权重为:"<<min<<endl;
}
void createAG(AGraph *g)//创建无向网
{
int vNum, aNum;//分别代表要创建的图的节点数和边数
int start, end;//start->end表示节点start和end之间有一条边
int weight;//边的权重
cout<<"请输入图中节点的个数和边的条数:";
cin>>vNum>>aNum;
printf("\n请输入%d个节点的信息:", vNum);
//创建节点
for(int i = 0; i < vNum; ++i)
{
cin>>g->vexs[i];
}
cout<<"这里输出节点编号及其存储的节点信息"<<endl;
for(int k = 0; k < vNum; ++k)
cout<<k<<":"<<g->vexs[k]<<"";
cout<<endl;
//初始化无向图的边信息
for(int m = 0; m < vNum; ++m)
for(int n = 0; n < vNum; ++n)
{
g->edges[m][n] = MAXIMUN;
}
//创建无向图的边信息
for(int j = 0; j < aNum; ++j)
{
cout<<"\n请输入第"<<j+1<<"条边的start和end节点和边的权重weight:";
cin>>start>>end>>weight;
g->edges[start][end] = weight;
g->edges[end][start] = weight;
}
//初始化vexNum和adgeNum
g->vexNum = vNum;
g->adgeNum = aNum;
}
运行结果:
贪心法之最小生成树之Prim算法

E,复杂度分析
时间复杂度:算法中要逐个将顶点加入到集合U中,而且每一次寻找最优加入顶点式用了两层循环,因此上述算法时间为O(n^3)。
0 0