生成树的代价:设G=(V,E)是一个无向连通网,生成树上各边的权值之和称为该生成树的代价。
最小生成树:在图G所有生成树中,代价最小的生成树称为最小生成树。
Prim算法
设G=(V, E)是具有n个顶点的连通网,
T=(U, TE)是G的最小生成树,
T的初始状态为U={u0}(u0∈V),TE={ },
重复执行下述操作:
在所有u∈U,v∈V-U的边中找一条代价最小的边(u, v)并入集合TE,同时v并入U,直至U=V。
prim算法需要不断读取任意两个顶点的信息,所以图用邻接矩阵存储
数组lowcost[n]:用来保存集合V-U中各顶点与集合U中顶点最短边的权值,lowcost[v]=0表示顶点v已加入最小生成树中;
数组adjvex[n]:用来保存该边所依附的(集合V-U中各顶点与集合U中顶点的最短边)集合U中的顶点。
lowcost[i]=w 表示顶点vi和顶点vk之间的权值为w,其中:vi∈ V-U 且vk ∈U
adjvex[i]=k.
prim算法:
- 初始化两个辅助数组lowcost(=arc[0][i])和adjvex(=0)(0是始点);
- 输出顶点u0,将顶点u0加入集合U中;
- 重复执行下列操作n-1次
3.1 在lowcost中选取最短边(lowcost[k]),取对应的顶点序号k;
3.2 输出顶点k和对应的权值;
3.3 将顶点k加入集合U中(lowcost[k]=0);
3.4 调整数组lowcost和adjvex;
Void prim(MGraph G){
for(int i=1;i<G.vertexNu;i++){
lowcost[i]=G.arc[0][i]; adjvex[i]=0;
}
lowcost[0]=0;
for(i=1;i<G.vertexNum;i+++){
k=MinEdge(lowcost,G.vertexNum)
/*int min=MIN;
for(int j=1; j<vertexNum; j++)
{
if(lowcost[j]!=0&&lowcost[j]<min)//lowcost[0]代表结点已加入U中
{
min=lowcost[j];
k=j;
}
}*/
cout<<K<<adjvex[k]<<lowcost[k];
lowcost[k]=0;
for(j=1;j<G.vertexNum;j++)
if((G.arc[k][j]<lowcost[j]){
lowcost[j]=G.arc[k][j];
arcvex[j]=k;
}
}
}
时间复杂性O(n2);适用于求稠密网的最小生成树
Kruskal算法:
因为Kruskal算法需要依此对图中的边进行操作,因此用边集数组来存储图。为了提高查找最短边的速度,可以先对边集数组上的权排序
- 初始化:U=V; TE={ };
- 循环直到T中的连通分量个数为1
2.1 在E中寻找最短边(u,v);
2.2 如果顶点u、v位于T的两个不同连通分量,则
2.2.1 将边(u,v)并入TE;
2.2.2 将这两个连通分量合并为一个;
2.3 在E中标记边(u,v),使得(u,v)不参加后续最短边的选取;
如何判断一条边所依附的两个顶点在同一个连通分两中(并查集)
定义Parent[i]数组。数组分量的值表示顶点i的双亲节点(初值为-1;)
当一条边(u,v)的两个顶点的根结不同时,这两个结点属于不同的连通分量(利用parent 数组查找一棵树的根节点。当一个结点n的parent==-1,树的根节点即为n)
如何将一条边所依附的两个顶点合并到同一个连通分量中
要进行联通分量的合并 ,其中一个顶点所在的树的根节点为vex1,另一个顶点所在的树的根节点为vex2,则:parent[vex2]=vex1;求某棵树v所在的生成树的根节点,只需要延数组v=parent[v]不断查找v的双亲,直到parent[v]=-1.
struct EdgeType//边集数组
{
int from;//边所依附的两个顶点下标
int to;
int weight;//权值
}
int Find(int *parent, int node)
{
int f;
f=node;
while(parent[f]>-1)
f=parent[f];
return f;
}
/*sort(edge,edge+n,cmp);//排序
int num=0;
int vex1,vex2;
int parent[vertexNum];*/
for(int i=0; i<vertexNum; i++)
{
parent[i]=-1;
}
int i;
for(num=0,i=0; num<vertexNum-1; i++)
{
vex1=Find(parent,edge[i].from);
vex2=Find(parent,edge[i].to);
if(vex1!=vex2)
{
cout<<edge[i].from+1<<" "<<edge[i].to+1<<" ";
parent[vex2]=vex1;
num++;
}
}
因此时间复杂性为O(elog2e).
适用于求稀疏网的最小生成树。