邻接矩阵实现克鲁斯卡尔算法

//主要源代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INF 999999
#define MAX_NAME 3
#define VERTEX_MAX_NUM 100
typedef char VertexType[MAX_NAME];
typedef int VRType;
typedef struct {    //建立邻接矩阵
    int weight;
}adjMatrix[VERTEX_MAX_NUM][VERTEX_MAX_NUM];
struct MGraph{
    VertexType vex[VERTEX_MAX_NUM];//建立顶点向量
    adjMatrix arcs;  //图中的邻接矩阵
    int vrtnum,arcnum;//顶点,弧的个数
};
typedef struct Sort{
    int x,y,w;
}weightValue[VERTEX_MAX_NUM*VERTEX_MAX_NUM];
typedef struct VRTFather{
    int fa;
}Father[VERTEX_MAX_NUM];
int LocateVex(MGraph G,VertexType u){
    int i;
    for( i=0;i<G.vrtnum;i++)
        if(strcmp(u,G.vex[i])==0)
         return i;
    return -1;
}
void creatMGraph(MGraph &G){
    int i,j,w;
    VertexType va,vb;
    printf("请输入无向图G的顶点数、边数:");
    scanf("%d %d",&G.vrtnum,&G.arcnum);
    printf("请输入%d个顶点的值:\n",G.vrtnum);
    for(i=0;i<G.vrtnum;i++) //构造顶点向量,(其实就是将顶点的名字换成数字)
        scanf("%s",G.vex[i]);
    for(i=0;i<G.vrtnum;i++) //初始化邻接矩阵,都赋为无穷
        for(j=0;j<G.vrtnum;j++)
            G.arcs[i][j].weight=INF;
    printf("请输入%d条边的顶点1 顶点2 权值(以空格为间隔):\n",G.vrtnum);
    for(int k=0;k<G.arcnum;k++){
        scanf("%s%s%d%*c",va,vb,&w);
        i=LocateVex(G,va);
        j=LocateVex(G,vb);
        G.arcs[i][j].weight=G.arcs[j][i].weight=w;
    }
}
void DisplayArc(MGraph g){
    printf("建立的邻接矩阵如下:\n  ");
    for(int i=0;i<g.vrtnum;i++)
        printf("%7s",g.vex[i]);
    printf("\n");
    for(int i=0;i<g.vrtnum;i++){
         printf("%s",g.vex[i]);
        for(int j=0;j<g.vrtnum;j++){
            if(g.arcs[i][j].weight==INF)
                printf("     ∞");
            else
                printf("%7d",g.arcs[i][j].weight);
        }
        printf("\n");
    }
}
int findFather(int x,Father &father)
{
    int root;//找x顶点的父亲
    while(x!=father[x].fa)
    x=father[x].fa;
    root=x;//用temp存储x的最深根节点。即x的父亲结点
    return root;
}
void MiniSpanTree_KRUSKAL(MGraph G){
    int min=INF,i,j,vx,vy;
    weightValue value,temp;
    Father father;
    for(i=0;i<G.vrtnum;i++)//初始化所有顶点的父亲为他自己
        father[i].fa=i;
    int k=0;
    //将所有的边(包括边两端顶点信息),赋值到value结构体数组中
    for(i=0;i<G.vrtnum;i++)
    for(j=0;j<G.vrtnum;j++,k++){
        value[k].w=G.arcs[i][j].weight;
        value[k].x=i;value[k].y=j;
    }
    //对value数组中所有的边进行从大到小排序
    for(i=0; i<G.vrtnum*G.vrtnum-1; i++)
    for(j=0; j<G.vrtnum*G.vrtnum-1-i; j++){
       if(value[j].w>value[j+1].w){
            temp[0]=value[j+1];
            value[j+1]=value[j];
            value[j]=temp[0];
       }
    }
    printf("克鲁斯卡尔算法的最小生成树为:\n");
    int allcost=0;
    for(i=0;i<2*G.arcnum-1;i+=2){
        //从value数组中每隔两个点进行取边的值,因为无向图中每个顶点的值有两个
        int a,b;
        a=value[i].x;
        b=value[i].y;
        if(findFather(a,father)!=findFather(b,father)){
            //当前边和其他边不构成环,就输出这条边
            printf("(%s-%s) %d\n",G.vex[a],G.vex[b],G.arcs[a][b].weight);
            //将此边的右顶点的父亲赋值为左顶点的父亲
            father[father[b].fa].fa=findFather(a,father);
            allcost+=G.arcs[a][b].weight;//每输出一次,累加此边的权值
        }
    }
    printf("最小二叉树的最小权值为:%d\n",allcost);
}


int main(){


    MGraph g;
    creatMGraph(g);
    DisplayArc(g);
    MiniSpanTree_KRUSKAL(g);
    return 0;
}
/*
测试样例:
v0 v1 v2 v3 v4 v5 v6
v0 v1 28
v1 v2 16
v2 v3 12
v3 v4 22
v4 v5 25
v5 v0 10
v1 v6 14
v3 v6 18
v4 v6 24
*/


  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
克鲁斯卡尔算法是一种用于求解最小生成树的算法,其中邻接矩阵是一种常见的图的存储方式。下面是克鲁斯卡尔算法邻接矩阵实现: 假设我们有一个无向图,其中顶点数为n,边数为m,邻接矩阵为graph[n][n],其中graph[i][j]表示顶点i和顶点j之间的边权值(如果没有边相连,则为0)。 ```python # 定义边的结构体 class Edge: def __init__(self, u, v, w): self.u = u self.v = v self.w = w # 定义并查集 class UnionFind: def __init__(self, n): self.parent = list(range(n)) self.rank = [0] * n def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) return self.parent[x] def union(self, x, y): px, py = self.find(x), self.find(y) if px == py: return False if self.rank[px] < self.rank[py]: self.parent[px] = py elif self.rank[px] > self.rank[py]: self.parent[py] = px else: self.parent[py] = px self.rank[px] += 1 return True # 定义克鲁斯卡尔算法 def kruskal(n, edges): uf = UnionFind(n) edges.sort(key=lambda x: x.w) res = [] for e in edges: if uf.union(e.u, e.v): res.append(e) return res # 示例 n = 5 graph = [[0, 2, 0, 6, 0], [2, 0, 3, 8, 5], [0, 3, 0, 0, 7], [6, 8, 0, 0, 9], [0, 5, 7, 9, 0]] edges = [] for i in range(n): for j in range(i+1, n): if graph[i][j] != 0: edges.append(Edge(i, j, graph[i][j])) res = kruskal(n, edges) for e in res: print(e.u, e.v, e.w) ``` 上述代码中,我们首先定义了一个边的结构体Edge,其中u、v、w分别表示边的两个端点和边权值。然后我们定义了一个并查集UnionFind,用于判断两个顶点是否在同一个连通块中。最后,我们定义了kruskal函数,其中n表示顶点数,edges表示边的列表。在kruskal函数中,我们首先对边按照权值从小到大进行排序,然后依次加入到最小生成树中,如果加入的边会形成回路,则舍弃掉。最后,我们输出最小生成树的所有边。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值