王道考研 ++++ Kruskal 克鲁斯卡尔算法

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MaxSize 100
typedef struct GraphEage
{
  int front,rear,len;
  struct GraphEage *next;
}GraphEage;

int Father[MaxSize];
void InsertSort(GraphEage *G,int a,int b,int len);
int Kruskal(GraphEage *G,int n,int m);
int Find(int child);

//查找最高父节点
int Find(int child)
{
  if(Father[child] == child)return child;
  else return Find(Father[child]);
}
//插入排序
void InsertSort(GraphEage *G,int a,int b,int len)
{
  GraphEage *E,*R=G;
  E = (GraphEage*)malloc(sizeof(GraphEage));
  E->front = a;E->rear = b;E->len = len;
  E->next = NULL;
  //遍历插入
  while (1)
  {
    if(R->next == NULL)
    { //链表中没有元素或者是遍历到最后时
      R->next = E;
      break;
    }else if(len < R->next->len)
    { //下一个元素比他大 插入
      E->next = R->next;
      R->next = E;
      break;
    }
    R = R->next;
  }
}
/*克鲁斯卡尔算法*/
int Kruskal(GraphEage *G,int n,int m)
{ //ans记录最小生成树的边权之和
  int ans = 0,i;
  //并查集初始化,使父节点为自己本身
  for(i = 0;i < n;i++)Father[i] = i;
  //最小生成树的边数是 节点数-1
  while(n > 1)
  {
    GraphEage *R = G->next;//获取集合中剩余边权最小的
    G->next = G->next->next;//在集合中删除取出的这个元素
    //寻找这条边两个节点的最高父节点
    int a = Find(R->front);
    int b = Find(R->rear);
    if(a != b)//不相等说明不在一个集合中
    {
      Father[a] = b;//默认把 a 当作 b的父节点(可用秩优化)
      ans += R->len;
      n--;
    }
  }
  return ans;
}
int main(int argc, char const *argv[])
{
  GraphEage *G;
  int n,m,i;
  G = (GraphEage*)malloc(sizeof(GraphEage));
  G->next = NULL;
  printf("请输入节点数与边数:");
  scanf("%d%d",&n,&m);
  printf("请输入%d条边:\n",m);
  for(i = 0;i < m;i++)
  {
    int a,b,len;
    scanf("%d%d%d",&a,&b,&len);
    InsertSort(G,a,b,len);
  }
  int ans = Kruskal(G,n,m);
  printf("最小生成树的路径权值是:%d\n",ans);
  return 0;
}
// 0 1 4
// 0 4 1
// 0 5 2
// 1 2 1
// 1 5 3
// 2 3 6
// 2 5 5
// 3 4 5
// 3 5 4
// 4 5 3

发布了85 篇原创文章 · 获赞 40 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/WX_1218639030/article/details/99414124