您的位置:首页 > 编程语言 > Go语言

Prim & Kruskal Algorithm

2017-06-10 16:59 162 查看
**Prim算法**


Prim算法是图论中的一种算法,可在加权连通图里搜索最小生成树。此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。

中文名:

普里姆算法

提出时间: 1930年

外文名: Prim Algorithm

应用学科: 计算机,数据结构,数学(图论)

别称: 最小生成树算法

适用领域范围: 应用图论知识的实际问题

算法:贪心

/[b]**********************************************************[/b]/

Prim算法的描述

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;

2).初始化:Vnew = {x},其中x为集合V中的任一节点(起点),Enew= {},为空;

3).重复下列操作,直到Vnew = V:

a.在集合E中选取权值最小的边 (u,v),其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);

b.将v加入集合Vnew中,将(u, v)边加入集合Enew中;

4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。

时间复杂度:

通过邻接矩阵图表示的简易实现中,找到所有最小权边共需O(V)的运行时间。使用简单的二叉堆与邻接表来表示的话,普里姆算法的运行时间则可缩减为O(ElogV),其中E为连通图的边数,V为顶点数。如果使用较为复杂的斐波那契堆,则可将运行时间进一步缩短为O(E+VlogV),这在连通图足够密集时(当E满足Ω(VlogV)条件时),可较显著地提高运行速度。

http://blog.csdn.net/zenail501129/article/details/23551909

http://blog.csdn.net/u014488381/article/details/41447229

#include <stdio.h>
#include <cstdlib>
#include<memory.h>
const int Max =0x7fffffff;
const int N=50;

int n;
int g

,dis
,visited
;

int prim()
{
int i,j;
int pos,min;
int ans=0;
memset(visited,0,sizeof(visited));
visited[1]=1;pos=1;
//assign a value to the dis
first
for(i=2;i<=n;i++)
dis[i]=g[pos][i];
for(i=1;i<n;i++)
{
min=Max;
for(j=1;j<=n;j++)
{
if(visited[j]==0&&min>dis[j])
{
min=dis[j];
pos=j;
}
}
printf("The node being traversed is :%d\n",pos);
ans+=min;
printf("The value of ans is %d\n",ans);
//mark the node
visited[pos]=1;
//update the weight
for(j=1;j<=n;j++)
if(visited[j]==0&&dis[j]>g[pos][j])
dis[j]=g[pos][j];
}
return ans;
}

int main()
{
int i=1,j=1;
int ans=0;
int w;
printf("Please enter the number of the nodes:\n");
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)
g[i][j]=0;
else
g[i][j]=Max;
}
printf("Please enter the number of the edges:\n");
int edgenum;
scanf("%d",&edgenum);
int v1,v2;
printf("Please enter the number and the corresponding weight:\n");
for(i=1;i<=edgenum;i++)
{
scanf("%d%d%d",&v1,&v2,&w);
g[v1][v2]=g[v2][v1]=w;
}
ans=prim();
printf("The sum of the weight of the edges is:%d\n",ans);
system("pause");
return 0;

}


Kruskal Algorithm

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;

#define MAXN 11     //顶点个数的最大值
#define MAXM 20     //边的个数的最大值
struct edge         //边
{
int u, v, w;
}edges[MAXM];       //边的数组
int parent[MAXN];   //parent[i]为顶点i所在集合对应的树中的根结点
int n, m;           //顶点个数、边的个数
int i, j;           //循环变量
void UFset()        //初始化
{
for(i = 1; i <= n; i++) parent[i] = -1;
}
int Find(int x)     //查找并返回结点x所属集合的根结点
{
int s;          //查找位置
for(s = x; parent[s] >=0; s = parent[s]) ;
while(s != x)   //优化方案——压缩路径,使后续的查找操作加速
{
int tmp = parent[x];
parent[x] = s;
x = tmp;
}
return s;
}
//运用并查集,将两个不同集合的元素进行合并,使两个集合中任意两个元素都连通
void Union(int R1, int R2)
{
int r1 = Find(R1), r2 = Find(R2);       //r1和r2分别为R1和R2的根结点
int tmp = parent[r1] + parent[r2];      //两个集合结点数之和(负数)
//如果R2所在树结点个数 > R1所在树结点个数(注意parent[r1]是负数)
if(parent[r1] > parent[r2])
{
parent[r1] = r2;
parent[r2] = tmp;
}
else
{
parent[r2] = r1;
parent[r1] = tmp;
}
}
int cmp(const void *a, const void *b)       //实现从小到大的比较函数
{
edge aa = *(const edge *)a, bb = *(const edge *)b;
return aa.w-bb.w;
}
void Kruskal()
{
int sumweight = 0;      //生成树的权值
int num = 0;            //已选用的边的数目
UFset();                //初始化parent数组
for(i = 0; i < m; i++)
{
if(Find(edges[i].u) != Find(edges[i].v))
{
printf("%d %d %d\n", edges[i].u, edges[i].v, edges[i].w);
sumweight += edges[i].w; num++;
Union(edges[i].u, edges[i].v);
}
if(num >= n-1) break;
}
printf("The weight of MST is : %d\n", sumweight);
}
main()
{
scanf("%d%d", &n, &m);  //读入顶点个数和边数
for(int i = 0; i < m; i++)
scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w); //读入边的起点和终点
printf("The edges chosen are :\n");
qsort(edges, m, sizeof(edges[0]), cmp); //对边按权值从小到大排序
Kruskal();
}

/**
7 9
1 2 28
1 6 10
6 5 25
5 7 24
5 4 22
7 4 18
4 3 12
3 2 16
7 2 14
**/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  prim 数据结构 算法