引言:
一开始用起始点初始化adjvex数组,表示是起始点到各个顶点, 当有一个顶点P加入生成树,并且这个顶点到另一个顶点Q的权值小于lowcost[]数组中的,则说明生成树到另一个顶点Q的最短路径是通过P顶点,所以更新adjvex[Q]=P, 这就是为什么这样更新adjvex[]数组。
对于一个带权连通无向图 G=(V, E),边的权值之和最小的生成树,称之为最小生成树.
Prim算法时间复杂度为: O(V^2) 复杂度是顶点的平方,所以Prim算法适用于稠密图.
Prim算法操作步骤: Prim算法是先指定一个源点,将源点添加到生成树集合,找到生成树集合中元素到非生成树与那是中权值最小的顶点,将这个顶点添加到生成树集合中,并且更改生成树中辅助数组,之后再找从生成树到非生成树中权值最小的顶点,加入到生成树集合,更新辅助数组,往复操作,直到最后一个顶点都加入到生成树
最小生成树是在图 (邻接矩阵) 中选择出一个权值累加和最小的树,所以自己首先需要构建一个图(邻接矩阵)。如: v0 --> v2 = ∞,说明v0到v2这两个结点没有边 v0-->v0=0,说明是自身结点 v1->v0=10,表示v1->v0结点的权重为10。
Prim算法,即每次选择生成树顶点到非生成树顶点最小的权值,然后辅助数组,更新权值,如此反复,保证每次最优来达到最优解。
思路:
1给定以顶点v开始, 现在用v来初始化辅助数组shortEdge,
2.给定起始结点v,从v结点开始生成树. 首先将v结点加入生成树.并打印信息
3.之后进入循环n-1次循环,因为n个顶点,v结点已经加入生成树了,所以在循环中会少一个结点加入生成树.
4.在辅助数组中找到生成树到邻接顶点权值最小的边,邻接顶点编号记为k,
5.打印出选择出来的结点信息和权值信息
6.将找到的结点加入到生成树中,
7. 更新辅助数组shortEdge的信息。让arc[k][j]去更新lowcost[j], 如果arc[k][j]比lowcost[]的权值更小,则说明从k到达j顶点的权值 更小, 让adjvex[j]=k;adjvex[]数组存放的就是到达顶点最小的顶点。
结点信息:
class node{
public:
int adjvex; //保存邻接点的下标 如 adjvex[2]=3; j->k权值小
int lowcost;
};
class MST{
public:
node shortEdge[MAXSIZE]; //这是一个辅助数组,
};
adjvex[]={0,0,1,0,0,0,1,0,1}表示到达2,6,8 v1->2,6,8这几个顶点的权值更小.
开始生成树:
adjvex[]数组存放的是生成树到非生成树结点权值最小的边
1. 初始化数组,adjvex[] 和lowcost[] 数组,lowcost[start]=0表示v0加入生成树中, adjvex[start]=3,表示是从v3->start边,,想想用起始点初始化,adjvex[i]=start, 说明是start到其他所有顶点。
2. 将start元素添加到生成树中, 并且输出这个点的信息,
3.开始n-1趟遍历, 首先找到非生成树顶点权值最小的边,得到那条边的顶点的索引,输出这个顶点信息,并且将这个顶点添加到生成树集合中,
4.开始n-1趟遍历,除自身顶点外还有n-1个顶点,比较新加入顶点到各个非生成树顶点的权值,如果该顶点到非生成树顶点的权值小于lowcost[]记录的权值,则更新lowcost[j]=arc[k][j], (更新lowcost[]的目的是用来比较生成树顶点到其他顶点的权值,所以lowcost值越来越小),并且将下标为k的顶点存入adjvex, 即adjvex[j] =k;
int sum=0;
void prim(MGraph G,int start){
//初始化shortEdge[]数组
for(int i=0; i<G.vertexNum; i++){
shortEdge[i].lowcost = G.arc[start][i];
shortEdge[i].adjvex = start;
}
//起点start加入U集合
shortEdge[start].lowcost=0;
for(int i=0; i<G.vertexNum-1; i++){
//在shortEdge[]中找到不在生成树顶点的权值最小的邻接点
k = minEdge(shortEdge,G.vertexNum);
//输出顶点k和对应的权值
cout<<shortEdge[k].adjvex<<" "<<shortEdge[k].lowcost<<endl;
shortEdge[k].lowcost=0; //表示k结点加入生成树
判断新加入的顶点到各个边的权值是不是比之前生成树的权值小,现在新顶点已经加入了,
如果新加入顶点权值比生成树权值小,就相当于更新生成树权值
for(int j=1; j<G.vertexNum; j++){ 除去自身顶点,所以遍历vertexNum-1次
if(lowcost[j]!=0 && G.arc[k][j]<shortEdge[j].lowcost){
shortEdge[j].lowcost = G.arc[k][j];
shortEdge[j].adjvex = k;
}
}
}
}
在shortEdge辅助数组中找到权值最小的并返回
//找一维数组中最小权值的索引
const int INF = 56537
int minEdge(node shortEdge,int x){ //x表示图中顶点数目,遍历shortEdge数组
int min = INF;
for(int j=1; j<x; j++){ //除去自身顶点还剩vertexNum-1个顶点
if(shortEdge[j].lowcost!=0 && shortEdge[j].lowcost<min){
min = shortEdge[j].lowcost;
k = j;
}
}
return k; //得到最小权值的索引
}
每次都在shortEdge数组中查询,找最小的权值,(必须是没有加入生成树的结点 )
当有一个结点加入生成树时候,就更新shortEdge的两个值,
输出如何是如何生成树的:
//在未加入生成树结点中找到权值最小边的结点索引
int MinEdge(int lowcost[], int vertexNum)
{
int min=INF;
int loc;
for(int i=0; i<vertexNum; i++){
if(lowcost[i]!=0 && lowcost[i]<min){
min = lowcost[i];
loc = i;
}
}
return loc;
}
//找到到某顶点最小边,是哪个顶点到某顶点边最小
int MaxEdge(int lowcost[], int vertexNum, int adjvex[]){
int min = INF;
int loc;
//在未加入的顶点中找,到最小的边的索引i, 索引的adjvex[i]存储的是哪个顶点到i顶点的信息。
for(int i=0; i<vertexNum; i++){
if(lowcost[i]!=0 && lowcost[i]<min){
min = lowcost[i];
loc = adjvex[i];
}
}
return loc;
}
int k = MinEdge(lowcost,vertexNum);
int m = MaxEdge(lowcost,vertexNum,adjvex);
cout<<vertex[m]<<" "<<vertex[k]<<" "<<lowcost[k]<<endl;
输出每步生成树的起始顶点,终顶点,和这条边的权值.