您的位置:首页 > 其它

Prim实现最小生成树

2015-10-14 22:39 330 查看
1,什么是最小生成树?

用连通网(图)表示n个城市以及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,带有权值。对于这样的一个连通网,找n-1条边使得这n个城市连通,这就是一颗生成树,这样的生成树很多,我们要找总的权值最小的树,即为最小生成树。

2,应用背景?

在n个城市间建立耗费经费最小的通信网。

3,存在方法:Prim和Kruskal方法;主要利用了简称为MST的性质:

假设把连通网的顶点分为了两个集合U和V,现在图里有一条最小权值边u->v;其中u存在U集合,v在V集合,那么这条边u->v一定存在于一颗最小生成树中。

4,Prim算法主要是维持一个closeedge数组。

closeedge数组元素包含两个成员;AdjVex和lowcost;表示的意思是在非i结点所在集合中和i连边的顶点中,权值最小的顶点以及该边权值

(1)选一个顶点作为开始结点,把顶点集合分成两个集合U和V-U(这里V表示图的所有顶点集合)。初始化closeedge数组;

(2)从closeedge中选一个权值最小的出来,把该顶点归入U;更新closeedge数组;

重复上述操作即可。

#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;

typedef int ValType;
typedef int Vertextype;
#define Max_Value 1000   //用在FindMinLowcost函数中
#define INFINITY 65535       //用来初始化邻接矩阵为无穷大
#define path "F:\\test.txt"
typedef struct UDG{
int vernum,arcnum;
ValType **AdjMatix;//邻接矩阵
}Graph;
typedef struct node{
Vertextype AdjVex;//closeedge数组元素中的邻接点
ValType lowcost;//权值
node()
{
lowcost = 0;
}
}node;//closeedge数组元素类型

void Readfile(Graph &g)//结果是生成邻接矩阵,读取顶点数和边数
{
ifstream infile(path);
cout<<"输出顶点数和边数!"<<endl infile="">> g.vernum >> g.arcnum;
cout << g.vernum << ' ' << g.arcnum << endl;
g.AdjMatix = new ValType*[g.vernum];
int i = 0;
for(i;i < g.vernum;i ++)
{
g.AdjMatix[i] = new ValType[g.vernum];
//memset(g.AdjMatix[i],-1,sizeof(ValType)*g.vernum);//初始化邻接矩阵为无边时的值
for(int t = 0; t < g.vernum; t++)
{
g.AdjMatix[i][t] = INFINITY;
}
}
cout<<"读取每一条边以及权值!"<<endl;
int head,tail,val;
int j = 0;
for(j; j < g.arcnum; j++)
{
infile >> head >> tail >> val;
g.AdjMatix[head][tail] = val;
g.AdjMatix[tail][head] = val;
}
}
int FindMinLowcost(node *x,int length)
{
int i = 0;
int min = Max_Value;
int locate;
for (i; i < length; i++)
{
if ((x[i].lowcost != 0) && (x[i].lowcost != INFINITY) && (x[i].lowcost < min))
{
min = x[i].lowcost;
locate = i;
}
}
return locate;
}

void MiniSpanTree_Prim(Graph g,Vertextype v)//Prim求最小生成树,关键维持一个closeedge数组
{
node *closeedge = new node[g.vernum];
cout << "初始化closeedge数组!" << endl;
int j = 0;
for (j; j < g.vernum; j++)
{
if(j != v)
{
//closeedge[j] = { v, g.AdjMatix[j][v] };
closeedge[j].AdjVex = v;
closeedge[j].lowcost = g.AdjMatix[j][v];
}
}
//closeedge[v].lowcost = 0;//这个语句可以不要,因为lowcost初始化时就为0
int i = 1,k;
for (i; i < g.vernum; i++)//只需在V-U中再依次找n-1个顶点
{
k = FindMinLowcost(closeedge, g.vernum);//在closedege中找到当前最小lowcost所在位置
cout << closeedge[k].AdjVex << "-->" << k << endl;
v = k;
closeedge[k].lowcost = 0;//相当于把顶点k放到U中
for (int s = 0; s < g.vernum; s++)//更新closeedge数组,s要在这里定义,
{
if (closeedge[s].lowcost != 0 && g.AdjMatix[s][k] < closeedge[s].lowcost)
{
//closeedge[s] = {k, g.AdjMatix[s][k]};
closeedge[s].AdjVex = k;
closeedge[s].lowcost = g.AdjMatix[s][k];
}
}
}

}
void deletegraph(Graph &g)
{
int i = 0;
for (i; i < g.vernum; i++)
{
delete []g.AdjMatix[i];
}
delete []g.AdjMatix;
g.AdjMatix = NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
Graph A;
Readfile(A);
MiniSpanTree_Prim(A, 0);
deletegraph(A);
system("pause");
return 0;
}
</endl></iostream></fstream>


测试数据test.txt为:

6 10

0 1 6

0 2 1

0 3 5

1 2 5

1 4 3

2 3 5

2 4 6

2 5 4

3 5 2

4 5 6

输出结果为:



Prim算法的时间复杂度为O(n2);所以它适合求边稠密的网的最小生成树。空间复杂度为O(n),个人理解主要就是维持closeedge数组。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: