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

来源:互联网 发布:社交网络之类的电影 编辑:程序博客网 时间:2024/05/21 06:18
/*Name: Copyright: Author: Date: 01-12-14 20:17Description: 最小生成树( 克鲁斯卡尔算法)关于并查集的算法,参见《一种简单而有趣的数据结构——并查集》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;}

0 0
原创粉丝点击