数据结构(C实现)------- 最小生成树之Prim算法

[本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020]

算法描述

  如果连通图是一个网,则称该网中所有生成树中权值总和最小的生成树为最小生成树,也称最小代价生成树。利用Prim算法构造的最小生成树方法思想:

  假设G=(V,E)是一个具有n个顶点的连通网,顶点集V={v1,v2,...,vn}.设所求的最小生成树T=(U,TE),其中U是T的顶点集,TE是T的边集,U和TE初值均为空集。

  Prim算法的基本思想如下:首先从V中任取一个顶点(假定取v1),将生成树T置为仅有一个结点v1的树,即U={v1};然后只要U是V的真子集,就在所有那些一个端点在T中,另一个端点在T外的边中,找一条最短(即权值最小 )的边。假定符合条件的最短边为(vi,vj),则把该条边和其不在T中的顶点vj,分别并入T的边集TE和顶点集U。如此进行下去,每次往生成树里并入一个顶点和一条边,直到把所有顶点都包括进生成树T为止。此时,必有U=V,TE中有n-1条边,则T=(U,TE)是G的一棵最小生成树。

算法实现

  设一个edge数组,记录从顶点U集到V-U的代价最小的边,每条边的信息包括边的始点和,终点和权值。从顶点u出发,利用prim算法求最小生成树步骤如下:

  (1) 初始化edge数组,记录顶点u到图中其余结点的代价最小的n-1的边。

  (2) 将顶点u加入U中。

  (3) 当U不等于V时,做如下处理。

    1) 从edge数组中选一条代价最小的边。

    2) 将该边的终点加入U中。

    3) 调整edges数组,使它始终记录顶点U到V-U的代价最小的边。

算法代码

// 定义边结构体
typedef struct{
	int start;
	int end;
	int cost;
}Edge;

/*
 *Prim算法求最小生成树
 * */
void Prim_MG(MGraph MG,char vs){
	Edge edge[MAX_VEX_NUM];
	int i,j,k,v,min;
	int s = getIndexOfVexs(vs,&MG);
	//初始化边
	for(i = 1;i <= MG.vexnum;i++){
		if(s != i){
			edge[i].start = s;
			edge[i].end = i;
			edge[i].cost = MG.arcs[s][i];

		}
	}
	//首先将s加入生成树集合中
	edge[s].cost = 0;
	for(i = 2;i <= MG.vexnum;i++){
		min = 1000;
		for(j = 1;j<= MG.vexnum;j++){
			if(edge[j].cost != 0 && edge[j].cost < min ){
				min = edge[j].cost;
				k = j;
			}
		}
		v = edge[k].end;
		edge[v].cost = 0; // 加入新节点

		//输出生成树中的边
	 	printf("%c %c %d\n",MG.vexs[edge[v].start],MG.vexs[edge[v].end],MG.arcs[edge[v].start][edge[v].end]);

		//重新调整数组
		for(j = 1;j <= MG.vexnum;j++){
			if(edge[j].cost != 0 && MG.arcs[v][j] != 0 && MG.arcs[v][j] < edge[j].cost){
				edge[j].start = k;
				edge[j].end = j;
				edge[j].cost = MG.arcs[v][j];
			}
		}
	}

}

算法说明

  假设图中有n个顶点,则第一个进行初始化的循环语句的频度为n,第二个循环语句频度为n-1。其中有两个内循环;其一是在edge数组中找权值最小的边,其频度为n-1,其二是重新调整edge数组的边,频度为n,所以Prim算法的时间复杂度为O(n^2),而与图中的边数无关,因此适用于求稠密的最小生成树。

完整代码

/*
 * =====================================================================================
 *
 *       Filename:  Prim.c
 *
 *    Description:  最小生成树算法之Prim算法
 *
 *        Version:  1.0
 *        Created:  2015年03月11日 15时27分19秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  jesson20121020 (), [email protected]
 *   Organization:
 *
 * =====================================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#define MAX_VEX_NUM 50
#define UN_REACH 1000

typedef char VertexType;
typedef enum {
	DG, UDG
} GraphType;
typedef struct {
	VertexType vexs[MAX_VEX_NUM];
	int arcs[MAX_VEX_NUM][MAX_VEX_NUM];
	int vexnum, arcnum;
	GraphType type;
} MGraph;

/**
 * 根据名称得到指定顶点在顶点集合中的下标
 * vex  顶点
 * return 如果找到,则返回下标,否则,返回0
 */
int getIndexOfVexs(char vex, MGraph *MG) {
	int i;
	for (i = 1; i <= MG->vexnum; i++) {
		if (MG->vexs[i] == vex) {
			return i;
		}
	}
	return 0;
}

/**
 * 创建邻接矩阵
 */
void create_MG(MGraph *MG) {
	int i, j, k,weight;
	int v1, v2, type;
	char c1, c2;
	printf("Please input graph type DG(0) or UDG(1) :");
	scanf("%d", &type);
	if (type == 0)
		MG->type = DG;
	else if (type == 1)
		MG->type = UDG;
	else {
		printf("Please input correct graph type DG(0) or UDG(1)!");
		return;
	}

	printf("Please input vexmun : ");
	scanf("%d", &MG->vexnum);
	printf("Please input arcnum : ");
	scanf("%d", &MG->arcnum);
	getchar();
	for (i = 1; i <= MG->vexnum; i++) {
		printf("Please input %dth vex(char):", i);
		scanf("%c", &MG->vexs[i]);
		getchar();
	}

	//初始化邻接矩阵
	for (i = 1; i <= MG->vexnum; i++) {
		for (j = 1; j <= MG->vexnum; j++) {
			if(i == j)
				MG->arcs[i][j] = 0;
			else
				MG->arcs[i][j] = UN_REACH;
		}
	}

	//输入边的信息,建立邻接矩阵
	for (k = 1; k <= MG->arcnum; k++) {
		printf("Please input %dth arc v1(char) v2(char) weight(int): ", k);

		scanf("%c %c %d", &c1, &c2,&weight);
		v1 = getIndexOfVexs(c1, MG);
		v2 = getIndexOfVexs(c2, MG);
		if (MG->type == 1)
			MG->arcs[v1][v2] = MG->arcs[v2][v1] = weight;
		else
			MG->arcs[v1][v2] = weight;
		getchar();
	}

}
/**
 * 打印邻接矩阵和顶点信息
 */
void print_MG(MGraph MG) {
	int i, j;
	if(MG.type == DG){
		printf("Graph type: Direct graph\n");
	}
	else{
		printf("Graph type: Undirect graph\n");
	}

	printf("Graph vertex number: %d\n",MG.vexnum);
	printf("Graph arc number: %d\n",MG.arcnum);

	printf("Vertex set:\n ");
	for (i = 1; i <= MG.vexnum; i++)
		printf("%c\t", MG.vexs[i]);
	printf("\nAdjacency Matrix:\n");

	for (i = 1; i <= MG.vexnum; i++) {
		j = 1;
		for (; j < MG.vexnum; j++) {
			printf("%d\t", MG.arcs[i][j]);
		}
		printf("%d\n", MG.arcs[i][j]);
	}
}

// 定义边结构体
typedef struct{
	int start;
	int end;
	int cost;
}Edge;

/*
 *Prim算法求最小生成树
 * */
void Prim_MG(MGraph MG,char vs){
	Edge edge[MAX_VEX_NUM];
	int i,j,k,v,min;
	int s = getIndexOfVexs(vs,&MG);
	//初始化边
	for(i = 1;i <= MG.vexnum;i++){
		if(s != i){
			edge[i].start = s;
			edge[i].end = i;
			edge[i].cost = MG.arcs[s][i];

		}
	}
	//首先将s加入生成树集合中
	edge[s].cost = 0;
	for(i = 2;i <= MG.vexnum;i++){
		min = 1000;
		for(j = 1;j<= MG.vexnum;j++){
			if(edge[j].cost != 0 && edge[j].cost < min ){
				min = edge[j].cost;
				k = j;
			}
		}
		v = edge[k].end;
		edge[v].cost = 0; // 加入新节点

		//输出生成树中的边
	 	printf("%c %c %d\n",MG.vexs[edge[v].start],MG.vexs[edge[v].end],MG.arcs[edge[v].start][edge[v].end]);

		//重新调整数组
		for(j = 1;j <= MG.vexnum;j++){
			if(edge[j].cost != 0 && MG.arcs[v][j] != 0 && MG.arcs[v][j] < edge[j].cost){
				edge[j].start = k;
				edge[j].end = j;
				edge[j].cost = MG.arcs[v][j];
			}
		}
	}

}

/**
 * 主函数
 */
int main(void) {
	MGraph MG;
	char startVex;
	create_MG(&MG);
	print_MG(MG);

	printf("\nPlease input the start vex(char):");
	scanf("%c",&startVex);
	printf("\nThe result of Prim:\n");
	Prim_MG(MG,startVex);	

	return EXIT_SUCCESS;
}

运行演示

[email protected]:~/develop/workspace/c_learning/csdn/Prim$ gcc -o Prim Prim.c
[email protected]:~/develop/workspace/c_learning/csdn/Prim$ ./Prim
Please input graph type DG(0) or UDG(1) :1
Please input vexmun : 4
Please input arcnum : 5
Please input 1th vex(char):a
Please input 2th vex(char):b
Please input 3th vex(char):c
Please input 4th vex(char):d
Please input 1th arc v1(char) v2(char) weight(int): a b 1
Please input 2th arc v1(char) v2(char) weight(int): a c 3
Please input 3th arc v1(char) v2(char) weight(int): a d 4
Please input 4th arc v1(char) v2(char) weight(int): b c 2
Please input 5th arc v1(char) v2(char) weight(int): c d 3

Please input the start vex(char):a

The result of Prim:
a b 1
b c 2
c d 3
时间: 2024-10-07 00:18:45

数据结构(C实现)------- 最小生成树之Prim算法的相关文章

数据结构--图--最小生成树(Prim算法)

构造连通网的最小生成树,就是使生成树的边的权值之和最小化.常用的有Prim和Kruskal算法.先看Prim算法:假设N={V,{E}}是连通网,TE是N上最小生成树中边的集合.算法从U={u0}(uo属于V),TE={}开始,重复执行下述操作:在所有u属于U,v属于V-U的边(u,v)属于E中找到代价最小的一条边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止.此时TE中必有n-1条边,T={V,{TE}}为N的最小生成树.为实现此算法,需另设一个辅助数组closedge,以记录从U

最小生成树(prim算法,Kruskal算法)c++实现

1.生成树的概念 连通图G的一个子图如果是一棵包含G的所有顶点的树,则该子图称为G的生成树. 生成树是连通图的极小连通子图.所谓极小是指:若在树中任意增加一条边,则将出现一个回路:若去掉一条边,将会使之变成非连通图. 生成树各边的权值总和称为生成树的权.权最小的生成树称为最小生成树. 2.最小生成树的性质用哲学的观点来说,每个事物都有自己特有的性质,那么图的最小生成树也是不例外的.按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点.n-1 条边. 3.构造最小生成树,要解决以下两个问题

最小生成树之Prim算法

Prim算法: 假设N = (V,{E})是连通网,TE是N上最小生成树中边的集合.算法从U={u0}(u0属于V),TE={}开始,重复执行下述操作:在所有u属于U,v属于V-U的边(u,v)属于E中找到一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止,此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树. 为实现这个算法,需附设一个辅助数组closedge,以记录从U到V-U具有最小代价的边.对每个顶点vi属于V-U,在辅助数组中存在一个相应分量clos

hihoCoder #1097 最小生成树之Prim算法

原题网址,http://hihocoder.com/problemset/problem/1097 #1097 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但 是,问题也接踵而来——小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就 可以使得任意两座城市都可以通过所建

Hihocoder 之 #1097 : 最小生成树一&#183;Prim算法 (用vector二维 模拟邻接表,进行prim()生成树算法, *【模板】)

#1097 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来——小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过

hihoCoder - hiho一下 第二十六周 - A - 最小生成树一&#183;Prim算法

题目1 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来--小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过这两

hihocoder hiho一下 第二十六周 最小生成树一&#183;(Prim算法)

题目1 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来——小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就 可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过这

hiho一下 第二十六周---最小生成树一&#183;Prim算法

最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来--小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过这两条道路连通的

最小生成树的Prim算法

构造最小生成树的Prim算法 假设G=(V,E)为一连通网,其中V为网中所有顶点的集合,E为网中所有带权边的集合.设置两个新的集合U和T,其中集合U用于存放G的最小生成树的顶点,集合T用于存放G的最小生成树中的边.令集合U的初值为U={u0}(假设构造最小生成树时是从顶点u0出发),集合T的初值为T={}.Prim算法的思想是:在连通网中寻找一个顶点落入U集,另外一个顶点落入V-U集的这个顶点加入到U集中,然后继续寻找一顶点在U集而另一顶点在V-U集且权值最小的边放入T集;如果不断重复直到U=V

24最小生成树之Prim算法

最小生成树的Prim算法 思想:采用子树延伸法 将顶点分成两类: 生长点--已经在生成树上的顶点 非生长点--未长到生成树上的顶点 使用待选边表: 每个非生长点在待选边表中有一条待选边,一端连着非生长点,另一端连着生长点 步骤: 步骤1)构造初始待选边表,任选一个顶点v作为初始生长点,对其余每个非生长点w(共n-1个),将边(w,v)加进待选边表,如果边(w,v)不存在,则认为边(w,v)的长度是∞. 步骤2)循环n-2遍,非生长点个数k从n-1变到1. ①选择树边. 从待选边表中选出一条最短的