数据结构_图的应用_最小生成树2(克鲁斯卡尔算法)

#include<stdio.h>
#define MNUM 10
#define Arcnum_2 11
typedef struct
{
    int vexs[MNUM];  //这里把数字作为顶点的代表  如果是字母可以为char vexs[MNUM];
    int arcs[MNUM][MNUM];
    int vexnum, arcnum;
}Graph;
typedef struct
{
    int head;
    int tail;
    int lowcost;
}Edge;
Edge edge[Arcnum_2], temp;
int Vexset[MNUM]; /*标识各个顶点的连通分量, 对于每一个顶点vi属于V,
在辅助数组中存一个相应元素Vexset[i],表示该定点所在的联通分量,初始
时,Vexset[i] = i, 表示各顶点自成一个连通分量。*/
void Creat_graph(Graph * G)
{
    int i, j, m, n, q;
    scanf("%d %d", &G->vexnum, &G->arcnum);
    for(i = 0; i < G->vexnum; i++){
        G->vexs[i] = i;
    }
    for(i = 0; i < G->vexnum; i++){
        for(j = 0; j < G->vexnum; j++){
            if(i == j)
                G->arcs[i][j] = 0;
            else
                G->arcs[i][j] = 99;
        }
    }
    for(i = 0; i < G->arcnum; i++){
        scanf("%d %d %d", &m, &n, &q);
        G->arcs[m][n] = q;
        G->arcs[n][m] = q; //建立无向图
        edge[i].head = m;
        edge[i].tail = n;
        edge[i].lowcost = q;
    }
}

void Sort(Edge edge[])
{
    int i, j, k;
    for(i = 0; i < Arcnum_2; i++){
        k = i;
        for(j = i + 1; j < Arcnum_2; j++){
            if(edge[k].lowcost > edge[j].lowcost){
                k = j;
            }
            if(k != i){
                temp = edge[i];
                edge[i] = edge[k];
                edge[k] = temp;
            }
        }
    }
}
void MiniSpanTree_Kruskal(Graph G)
{
    int i, j;
    int v1, v2, vs1, vs2;
    Sort(edge);
    for(i = 0; i < G.vexnum; i++){
        Vexset[i] = i; //辅存数组,表示各个顶点自成一个连通分量
    }
    for(i = 0; i < G.arcnum; i++){  //**1**
        v1 = edge[i].head;
        v2 = edge[i].tail;
        vs1 = Vexset[v1];
        vs2 = Vexset[v2];
        if(vs1 != vs2){
            printf("%d --> %d\n", v1, v2);
            for(j = 0; j < G.vexnum; j++){  /*  **2**   需要找遍历俩遍边,第一次**1**为了查找最小的边,第二次**2**为了,
看看最小的边所连的顶点是否已经连通*/
                if(Vexset[j] == vs2)
                    Vexset[j] = vs1;  //类似于并查集,把同一个连通分量的编号都合到一起
            }
        }
    }
}
int main()
{
    Graph G;
    Creat_graph(&G);

    int i, j;
    for(i = 0; i < G.vexnum; i++){
        for(j = 0; j < G.vexnum; j++){
            if(G.arcs[i][j] < 10)
                printf("%d      ", G.arcs[i][j]);
            else
                printf("%d     ", G.arcs[i][j]);
        }
        putchar('\n');
    } //输出
    MiniSpanTree_Kruskal(G);

    return 0;
}



运行结果为:



两个算法的比较:

最小生成树之普里姆算法:它是对点入手,有两次遍历顶点,第一次遍历为了访问各个顶点,第二次遍历为了更新每个顶点的权值,所以复杂度为o(n^2),比较适合用于稠密图。

最小生成树之克鲁斯卡尔算法:它是对边入手,复杂度为o(eloge),比较适合边数少的稀疏图。

仅供参考,如有不妥欢迎批评指正。



猜你喜欢

转载自blog.csdn.net/ltrbless/article/details/80413770