KrusKal求最小生成树


这个算法的主要难点是:怎么避免连通图成环,可以用并查集算法

参考:http://blog.csdn.net/dellaserss/article/details/7724401/

图例:


代码:

#include<stdio.h>
#include<stdlib.h>
/*主要采用并查集来判断是否成环,加入了路径压缩*/
#include <malloc.h>
#include <string.h>
#define MAX 20
#define nLENGTH(a)  (sizeof(a)/sizeof(a[0]))
#define eLENGTH(a) ( sizeof(a) / sizeof(char) )/ ( sizeof(a[0]) / sizeof(char) )
//邻接矩阵
typedef struct _graph
{
    char vexs[MAX];       // 顶点集合
    int vexnum;           // 顶点数
    int edgnum;           // 边数
}Graph, *PGraph; 
// 边的结构体
typedef struct _EdgeData
{
    char start; // 边的起点
    char end;   // 边的终点
    int weight; // 边的权重
}EData;
//指向节点的位置
int point_node(PGraph g,char c)
{

	for(int i=0;i<g->vexnum;i++)
	{
		if(g->vexs[i]==c)
		{
			return i;
		}
	}
	return -1;
}
//对边按权值大小排序
void Sort_edg(EData edg[],int e)
{
	int i,j;

    for (i=0; i<e; i++)
    {
        for (j=i+1; j<e; j++)
        {
            if (edg[i].weight > edg[j].weight)
            {
                // 交换"第i条边"和"第j条边"
                EData tmp = edg[i];
                edg[i] = edg[j];
                edg[j] = tmp;
            }
        }
    }	
	for(j=0;j<e;j++)
	{
		printf("%c--%c\t%d",edg[j].start,edg[j].end,edg[j].weight);
		printf("\n");
	}

	

}
/*并查集的主要思路以下:*/
//-------------------------------------------------------------------------------
//找到根顶点       
int FindRoot(int a[],int p)
{
	int r=p;
	while(a[r]!=r)
		r=a[r];
	//路径压缩
	int x=p,j;
	while(x!=r)
	{
		j=a[x]; //j 保存 p 的父顶点
		a[j]=r; //把 终端顶点 r 赋给 p的父顶点
		x=j;   //把j值赋给x,不断循环,把父级的父级 r 一次一次赋给 x ,直到x与 r相等
	}
	return r;

}
//--------------------------------------------------------------------------------
void KrusKalTree(int b[][3],char a[],int L,int e)
{
	int rand=0;
	PGraph g; //矩阵
	EData edg[MAX];//保存边数组
	int ch[MAX]={0,1,2,3,4,5,6};//并查集用
    EData rets[MAX]; //用来存放选择好的边
	g=(PGraph)malloc(sizeof(Graph));
	//memset()第一个参数 是地址,第二个参数是开辟空间的初始值,第三个参数是开辟空间的大小
	printf("顶点个数:\n");//顶点数
	g->vexnum=L;
	printf("%d\n",g->vexnum);
	printf("边个数:\n");//边数
	g->edgnum=e;
	printf("%d\n",g->edgnum);
	//初始化顶点
	for(int j=0;j<g->vexnum;j++)
	{
		g->vexs[j]=a[j];
	}
	//得到边的数组
	for(int i=0;i<e;i++)
	{
		edg[i].start=char(b[i][0]);
		edg[i].end=char(b[i][1]);
		edg[i].weight=b[i][2];
	}
	//对边进行排序
	Sort_edg(edg,e);
	//进行并查集求解
	for(int k=0; k< e ; k++)
	{
		int p1,p2,m,n;
		p1=point_node(g,edg[k].start);
		p2=point_node(g,edg[k].end);
		
		//找他们的根顶点
		m=FindRoot(ch,p1);
		n=FindRoot(ch,p2);
		if(m!=n)
		{
			ch[m]=n;
			rets[rand++]=edg[k];
		}
	}
	printf("得到的最小生成树:\n");
	//打印已经得到的最小生成树的边
	for(j=0;j<rand;j++)
	{
		printf("%c--%c\t%d",rets[j].start,rets[j].end,rets[j].weight);
		printf("\n");

	}
	//通过循环,可以看出,压缩路径起了作用,不用通过循环即可,找到终端顶点
	for(j=0;j<rand;j++)
	{
		printf("%d\t",ch[i]);

	}
}

//测试
int main()
{
	int i,j;
	PGraph gp;
	//测试用例

	char a[]={'A', 'B', 'C', 'D', 'E', 'F', 'G'};
	int b[][3]={
        {'A', 'B',12}, 
        {'A', 'F',16}, 
        {'A', 'G',14}, 
        {'B', 'F',7}, 
        {'B', 'C',10}, 
        {'C', 'F',6}, 
        {'C', 'E',5},
		{'C', 'D',3},
		{'D', 'E',4},
		{'E', 'F',2},
		{'E', 'G',8},
		{'F', 'G',9}}; 

	//测试用例

	int n=nLENGTH(a);
	int e=eLENGTH(b);
	KrusKalTree(b,a,n,e);

	return 0;

}


智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告