码迷,mamicode.com
首页 > 编程语言 > 详细

最小生成树( 克鲁斯卡尔算法)

时间:2014-12-01 22:29:54      阅读:271      评论:0      收藏:0      [点我收藏+]

标签:des   blog   http   io   ar   os   for   on   数据   

/*
	Name: 
	Copyright: 
	Author: 
	Date: 01-12-14 20:17
	Description: 最小生成树( 克鲁斯卡尔算法)
	关于并查集的算法,参见《一种简单而有趣的数据结构——并查集》http://blog.csdn.net/qiaoruozhuo/article/details/39674991 
*/
#include<stdio.h>
#include<stdlib.h>

#define MAXN 1000   //最大顶点数量 
#define MAX 20000   //最大边数量 
#define INFINITY 999999   //无穷大 

int map[MAX][MAX] = {0};//邻接矩阵存储图信息 

typedef struct EdgeNode{ //三元组边表集 
	int u, v;  //弧尾和弧头 
	int w; //权值,对于非网图可以不需要 
} EdgeNode;

void CreatGraph(EdgeNode *E, int m);//创建三元组边表集图 
void CreatGraph_2(EdgeNode *E, int m, int n);//创建邻接矩阵图(随机图) 
int Locate(EdgeNode *E, int n, int u, int v);//判断u,v是否是邻接点 
void PrintGraph(EdgeNode *E, int m);//输出图
int cmp (const void *a , const void *b);//快排的配套函数 
int FindFatherAndReducePath(int father[], int pos);//查找族长并压缩路径:找到族长后,将所途经的前辈结点均指向族长
int UnionBySize(int father[], int posI, int posJ);//按大小求并:将成员posI和posJ合并到同一个家族
void KRSL(EdgeNode *E, int m, int n);//克鲁斯卡尔算法求最小生成树

int main()
{
	EdgeNode E[MAX];
	int i, m, n;

	printf("请输入顶点数量:"); 
    scanf("%d", &n);
    printf("\n请输入边数量:"); 
    scanf("%d", &m);
    
    CreatGraph_2(E, m, n);//创建三元组边表集图 
    PrintGraph(E, m);//输出图
	qsort(E, m, sizeof(E[0]), cmp);//按照权值大小递增排序 
	PrintGraph(E, m);//输出图
	
	KRSL(E, m, n);//克鲁斯卡尔算法求最小生成树

    return 0;
}

void CreatGraph(EdgeNode *E, int m)//创建三元组边表集图 
{
    int i;
   
    printf("\n请按照a b c格式输入边信息:\n"); 
    for (i=0; i<m; i++)
    {
        scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
    }
} 

void CreatGraph_2(EdgeNode *E, int m, int n)//创建三元组边表集图 (随机图) 
{
    int i, j, top;

    for (i=1; i<n; i++)//确保是连通图
    {
    	E[i-1].u = 0;
        E[i-1].v = i;
		E[i-1].w = rand() % 100 + 1;
    } 

    top = n - 1;
    while (top < m)
    {
        for (i=0; i<n; i++) 
        {
            for (j=i+1; j<n; j++)
            {
                if (rand()%100 == 0) //有10%的概率出现边
                {
                    if (!Locate(E, top, i, j))
                    {
                        E[top].u = i;
				        E[top].v = j;
						E[top++].w = rand() % 100 + 1;
                        if (top == m)
                            return;
                    }
                } 
            }
        }
    }
} 

int Locate(EdgeNode *E, int n, int u, int v)//判断u,v是否是邻接点 
{
    int i;
    for (i=0; i<n; i++) 
    {
    	if (u == E[i].u && v == E[i].v)
    		return 1;
    }
    
    return 0;
}

void PrintGraph(EdgeNode *E, int m)//输出图
{
    int i;
    
    for (i=0; i<m; i++)
    {
        printf("<%d, %d> = %d\t", E[i].u, E[i].v, E[i].w);
    }
    printf("\n");
} 

int cmp (const void *a , const void *b)//快排的配套函数 
{
	return (((EdgeNode *)a)->w > ((EdgeNode *)b)->w ? 1 : -1);
}


void KRSL(EdgeNode *E, int m, int n)//克鲁斯卡尔算法求最小生成树
{
	int i, min, top = 1;
	int father[MAXN] = {0};
	EdgeNode minTree[MAXN] = {0};
    
    for (i=0; i<n; i++)//初始化每个家族的成员都是1,为便于比较,取家族成员数的相反数 
    	father[i] = -1;
    
    for (i=0; i<m; i++)
    {
    	if (UnionBySize(father, E[i].u, E[i].v))//判断该边的两个顶点是否已经连通,未连通则按大小求并
    	{
    		minTree[top].u = E[i].u;
    		minTree[top].v = E[i].v;
    		minTree[top++].w = E[i].w;
    		
    		if (top == n)//选用了n-1条边后退出循环 
    			break;
    	}
    }
    
    min = 0;
    for (i=1; i<top; i++) //输出各顶点在最小生成树中的邻接点及边的长度 
    {
        printf("<%d, %d> = %d\t", minTree[i].u, minTree[i].v, minTree[i].w);
        min += minTree[i].w;
    }    
    printf("\n最小生成树总长度(权值)为 %d\n", min); 
} 

int FindFatherAndReducePath(int father[], int pos)//查找族长并压缩路径:找到族长后,将所途经的前辈结点均指向族长
{
    if (father[pos] <= 0)
		return pos;
    //若自己不是族长,则找到族长后,将所途经的结点均指向族长   
	return father[pos] = FindFatherAndReducePath(father, father[pos]);
}

int UnionBySize(int father[], int posI, int posJ)//按大小求并:将成员posI和posJ合并到同一个家族
{
    //首先各自去寻找自己的族长
    int fI = FindFatherAndReducePath(father, posI);
    int fJ = FindFatherAndReducePath(father, posJ);

    if (fI == fJ) //如果是同一个族长门下,不必合并,即合并失败 
        return 0;
        
    if (father[fI] < father[fJ])
    {//如果族长fI的实力比fJ强,即|fI|>|fJ|,则fI当族长,并修改father[fI]和father[fJ]
        father[fI] += father[fJ];
        father[fJ] = fI;
    }
    else              //否则fJ当族长
    {
        father[fJ] += father[fI];
        father[fI] = fJ;
    }
    
    return 1;
}

最小生成树( 克鲁斯卡尔算法)

标签:des   blog   http   io   ar   os   for   on   数据   

原文地址:http://blog.csdn.net/qiaoruozhuo/article/details/41653739

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!