王道考研 ++++ 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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值