kruskal算法,适合稀疏图,顶点多,边少(c语言)

kruskal算法的一点就是不能形成环路,而且是从排列好的边集合依次选出最小的边,每次选出的顶点都要放在同一个边集合中,之后在顶点集合选两个顶点的边,要求这两个顶点不能在边集合中,这样才能保障不形成环路。
一、链表表示

#include<stdio.h>
#include<stdlib.h>
/*
    kruskal,最小生成树,利用链表,并查集的知识
*/
typedef struct{
    int bef;
    int aft;
    int weight;
}pic_node;//图中点的结构体

typedef struct find_set{
    int data;
    struct find_set *next;
}NODE;//点集合的节点

typedef struct set_head{
    NODE *head;
    NODE *tail;
    int flag;
}HEAD;//点集合的头

HEAD set[20];//点集合
pic_node arr[20];//开始时候数据

int edge;//边数
int s=0;
int vertex;//顶点数
void add_set(int a,int b);
void sort(pic_node arr[]);
int find(int who);
int main()
{
    printf("enter the number of vertex:");//输入顶点个数 
    scanf(" %d",&vertex);

    printf("enter the number of edges:");//输入边个数
    scanf(" %d",&edge);

    printf("enter bef,aft,weight:");//输入两点和权值
    for(int i=0;i<edge;i++)
        scanf("%d%d%d",&arr[i].bef,&arr[i].aft,&arr[i].weight);

    sort(arr);//进行排序,求出最小
    pic_node edge_set[20];//边集合

    for(int i=0;i<vertex;i++)//初始化点集合,每个集合首先包含自己
    {
        //实际利用并查集
        set[i].head = (NODE *)malloc(sizeof(NODE));
        set[i].flag = 1;//如果一个集合被并入另一个集合,此集合赋值0,表示不存在了
        (set[i].head)->data = i + 1;
        set[i].tail = set[i].head;
        (set[i].tail)->next = NULL;
    }

    int j=0;
    for(int i=0;i<edge;i++)
    {
        if(find(arr[i].bef) != find(arr[i].aft))//如果两个顶点不在一个集合
        {
            edge_set[j++]=arr[i];//加入边的集合
            add_set(arr[i].bef,arr[i].aft);//将两个集合放在一起,防止形成环路
        }
        if(j>vertex-1)//边要小于顶点减去一
            break;
    }

    for(int i=0;i<vertex;i++)//输出点的集合
    {
        if(set[i].flag)
        {
            for(NODE *f=set[i].head;f!=NULL;f=f->next)
                printf("%d ",f->data);
            putchar('\n');
        }
    }
    for(int i=0;i<j;i++)//输出边的集合
        printf("(%d,%d) ",edge_set[i].bef,edge_set[i].aft);
    putchar('\n');

    return 0;
}
void sort(pic_node arr[])
{
    pic_node temp;
    for(int i=0;i<edge;i++)
        for(int j=0;j<edge-i-1;j++)
        {
            if(arr[j].weight > arr[j+1].weight)
            {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = arr[i];
            }
        }
}

int find(int who)
{
    for (int i = 0; i < vertex; i++)
    {
        if (set[i].flag != 0)
        {
            for (NODE *p = set[i].head; p != NULL; p = p->next)
            {
                if (p->data == who)
                {
                    return i;
                }
            }
        }
    }
    return -1;
}

void add_set(int a,int b)
{
    int alist = find(a),
        blist = find(b);

    set[blist].flag = 0;
    (set[alist].tail)->next = set[blist].head;
    //将第一个集合的尾部,变成第二个集合的头部
    set[alist].tail = set[blist].tail;//将两个集合的尾部同步
}

二、矩阵表示

#include<stdio.h>
#include<stdlib.h>
//kruskal算法,最小生成树使用数组,设置父节点是什么
typedef struct{
    int bef;
    int aft;
    int weight;
}node;
typedef struct find_set{
    struct find_set *bef;
    int data;
    struct find_set *next;
}NODE;
typedef struct set_head{
    NODE *head;
    NODE *tail;
    int flag;
}HEAD;
HEAD set[20];
node arr[20];
void sort(node arr[]);
void push(node *result);
int find(int bef,int aft);
int edge;
int s=0;
int vertex;

typedef struct set_t {
    int parent, data;
}set_t;
set_t Set[20];
int FindParent(int n);
void Union(int t1, int t2);

int main()
{
    printf("enter the number of vertex:"); 
    scanf(" %d",&vertex);

    printf("enter the edge:");
    scanf(" %d",&edge);

    printf("enter bef,aft,weight:");
    for(int i=0;i<edge;i++)
        scanf("%d%d%d",&arr[i].bef,&arr[i].aft,&arr[i].weight);

    sort(arr);
    node edge_set[20];

    for(int i=0;i<vertex;i++)//初始化点集合
    {
        Set[i].data = i + 1;
        Set[i].parent = i;
    }
    int j=0;
    for(int i=0;i<edge;i++)
    {
        if (FindParent(arr[i].bef) != FindParent(arr[i].aft)) 
        {
            edge_set[j++] = arr[i];
            Union(arr[i].bef - 1, arr[i].aft - 1);
        }
    }

    putchar('\n');
    for(int i=0;i<j;i++)
        printf("(%d,%d) ",edge_set[i].bef,edge_set[i].aft);
    putchar('\n');

    return 0;
}
void sort(node arr[])
{
    node temp;
    for(int i=0;i<edge;i++)
        for(int j=0;j<edge-i-1;j++)
        {
            if(arr[j].weight > arr[j+1].weight)
            {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = arr[i];
            }
        }
}

int FindParent(int n)//查找父节点
{
    if (Set[n].parent == n)
        return n;
    return FindParent(Set[n].parent);
}

void Union(int t1, int t2)//进行集合合并,实际就是将父节点改变 
{
    int root1 = FindParent(Set[t1].parent),
        root2 = FindParent(Set[t2].parent);

    if (root1 != root2) 
    {
        Set[root2].parent = root1;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37787222/article/details/79064648