c语言实现克鲁斯卡尔算法完整版(包含矩阵转化为边集并排序)

   最近在看书学习数据结构时,学到图这一章时,有一些代码书上没有网上也找不到满意的,于是我就自己写啦,小白一枚,如果有写的不好的地方还请大佬指教

克鲁斯卡尔算法的基本思想:将边集以权值从小到大的顺序排列,不断将最小权值的边取出,将各个顶点纳入一个森林,最后将森林的各树连接,构成一颗最小生成树

代码如下:

#include<stdio.h>
#include<stdlib.h>
#define maxsize 20
#define maxedge 40
#define infinity 65535
typedef char VT;
typedef int ET;
typedef struct{
    VT vex[maxsize];
    ET arc[maxsize][maxsize];
    int numv,nume;
}MGraph;
typedef struct{
    int begin;
    int end;
    ET weight;
}Edge;

void MiniSpanTree_Kruskal(MGraph G);
void TranslateMGraph(MGraph G,Edge *edge);
void quicksort(int left,int right,Edge *edge);
void CreatMGraph(MGraph *G);

int main(void)
{
    MGraph G;
    CreatMGraph(&G);
    MiniSpanTree_Kruskal(G);
    return 0;
}

void MiniSpanTree_Kruskal(MGraph G)  
{
    int i,n,m;
    Edge edge[maxsize];

    int parent[maxsize]={0};   //定义一数组判断边与边是否形成回路

//parent数组标号i与对应位置上的值j表示边(Vi,Vj)已经被纳入子树
    TranslateMGraph(G,edge);  //注意这里的排序之后的(Vi,Vj)一定要i<j,不然运行会出错 
    for(i=0;i<G.nume;i++){
        n=Find(parent,edge[i].begin);
        m=Find(parent,edge[i].end);
        if(n!=m){     //n与m不等,表示没有生成回路,生成回路是不能纳入那一条边的
            parent[n]=m;
            printf("(V%d,V%d) %d\n",edge[i].begin,edge[i].end,edge[i].weight);
        }
    }
}

int Find(int *parent,int f)   //查找连线顶点的尾部下标
{
    while(parent[f]>0){
        f=parent[f];
    }
    return f;
}


void TranslateMGraph(MGraph G,Edge *edge)    //转化为边集
{
    int i,j,k=0;
    for(i=0;i<G.numv;i++){
        for(j=0;j<i;j++){
            if(G.arc[j][i]!=0&&G.arc[j][i]<infinity){
                edge[k].begin=j;edge[k].end=i;
                edge[k].weight=G.arc[j][i];
                k++;
            }
        }
    }
    quicksort(0,k-1,edge);
}

void quicksort(int left,int right,Edge *edge)    //快速排序
{
    int i,j;
    Edge p,k;
    i=left;
    j=right;
    k=edge[i];
    if(i>j) return ;  //递归出口 
    while(i<j){
        for(;i<j&&edge[j].weight>=k.weight;j--) ;
        for(;i<j&&edge[i].weight<=k.weight;i++) ;
        if(i<j){
            p=edge[i];
            edge[i]=edge[j];
            edge[j]=p;
        }
    }   //相等时跳出循环 
    edge[left]=edge[i];
    edge[i]=k;
    quicksort(i+1,right,edge);  
    quicksort(left,i-1,edge);  //划分更小模块,进行递归
}

void CreatMGraph(MGraph *G)
{
    int i,j,k,w;
    printf("输入顶点数和边数:\n");
    scanf("%d %d",&G->numv,&G->nume);
    for(i=0;i<G->numv;i++){
        printf("请输入顶点V%d的值:\n",i);
        scanf("%s",&G->vex[i]);
    }
    for(i=0;i<G->nume;i++){
        for(j=0;j<G->nume;j++){
            G->arc[i][j]=infinity;//初始化 
        }
    }
    for(k=0;k<G->nume;k++){
        printf("输入边(Vi,Vj)上的下标i与j和权w:\n");
        scanf("%d %d %d",&i,&j,&w);
        G->arc[i][j]=w;
        G->arc[j][i]=G->arc[i][j];
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值