最近在看书学习数据结构时,学到图这一章时,有一些代码书上没有网上也找不到满意的,于是我就自己写啦,小白一枚,如果有写的不好的地方还请大佬指教
克鲁斯卡尔算法的基本思想:将边集以权值从小到大的顺序排列,不断将最小权值的边取出,将各个顶点纳入一个森林,最后将森林的各树连接,构成一颗最小生成树
代码如下:
#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];
}
}