c语言数据结构-------最小生成树(Prim和Kruskal算法)

#include 
#include 
#include
#include 
//图,邻接矩阵存储
#define MaxVertexNum 100  //最大顶点数

typedef struct {
    char vex[MaxVertexNum]; //顶点表
    int edge[MaxVertexNum][MaxVertexNum]; //边表
    int vernum, arcnum; //记录当前图的顶点数量和边数
} MGraph;

//初始化图
MGraph InitMgraph() {
    MGraph graph;
    memset(graph.vex, 0, sizeof(graph.edge));
    graph.arcnum = 0;
    graph.vernum = 0;
    return graph;
}


//prim算法(贪心算法)
//本程序仅用来模拟过程,输出每一次循环新加入的顶点和边的权值,不再输出一棵树
//时间复杂度 |V|*|V|
void Prim(MGraph G) {
    //标记各节点是否加入树,0表示未加入
    int isJoin[G.vernum];
    memset(isJoin, 0, sizeof(isJoin));

    //各节点加入树的最低代价
    int lowCast[G.vernum];
    memset(lowCast, INFINITY, sizeof(lowCast));

    //从vex[0]开始的最小生成树
    int i = 0;
    isJoin[i] = 1;
    printf("根节点:%c\n", G.vex[i]);
    int count = 1;
    while (count < G.vernum) {
        for (int j = 0; j < G.vernum; ++j) {
            if (G.edge[i][j] != 0 && isJoin[j] == 0)
                if (lowCast[j] == -1 || lowCast[j] > G.edge[i][j]) {
                    lowCast[j] = G.edge[i][j];
                }
        }
        int number = 100;
        //找lowcast最小值
        for (int t = 0; t < G.vernum; ++t) {
            if (lowCast[t] > 0 && number > lowCast[t] && isJoin[t] == 0) {
                number = lowCast[t];
            }
        }
        for (int t = 0; t < G.vernum; ++t) {
            if (number == lowCast[t] && isJoin[t] == 0) {
                isJoin[t] = 1;
                i = t;
                count++;
                printf("%c ", G.vex[t]);
                break;
            }
        }
        printf("%d ", number);
        printf("\n");

    }
}

//创建一条边的变量类型,包含权重,边头,边尾
typedef struct {
    int weight;
    char head;
    char tail;
} VerByWeight;

/
//并查集(用于实现克鲁斯卡尔算法)
#define size 100

//并查集,树的双亲表示法
typedef struct UFSetsNode {
    char data;
    int parent;
} UFSetsNode;

typedef struct UFSets {
    UFSetsNode ufSetsNode[size];
    int count;
} UFSets;

//初始化并查集
void initSets(UFSets *sets) {
    for (int i = 0; i < size; i++) {
        //每个节点自成一棵树
        sets->ufSetsNode[i].parent = -1;
        sets->count = 0;
    }
}
//改进Find操作,将从根到元素x路径上的所有元素都变成根的孩子
int FindOptimize(UFSets *sets, char x) {
    //找到x的位置,并记录索引
    int index = -1;
    for (int i = 0; i < (*sets).count; i++) {
        if ((*sets).ufSetsNode[i].data == x) {
            index = i;
            break;
        }
    }
    //并查集没有x元素
    if (index == -1) {
        return -1;
    }
    //x索引的备份
    int t = index;
    //找到x的根索引
    while ((*sets).ufSetsNode[index].parent >= 0) {
        index = (*sets).ufSetsNode[index].parent;
    }
    //临时记录x路径上的元素的索引
    int r;
    //优化的代码
    while ((*sets).ufSetsNode[t].parent >= 0) {
        r = (*sets).ufSetsNode[t].parent;
        //修改t的父节点
        (*sets).ufSetsNode[t].parent = index;
        t = r;
    }
    return index;
}

//并查集优化Union操作(小树合并大树)每棵树根节点的绝对值记录的是节点个数
//若用代码表示每棵树的节点个数,需进行遍历操作
bool UnionOptimize(UFSets *sets, char R1, char R2) {
    //R1的根节点
    int Root1 = FindOptimize(sets, R1);
    //R2的根节点
    int Root2 = FindOptimize(sets, R2);
    //同一个集合
    if (Root1 == Root2) {
        return false;
    }
    //由于是负数,值越大,结点数越少
    if (sets->ufSetsNode[Root1].parent < sets->ufSetsNode[Root2].parent) {
        sets->ufSetsNode[Root1].parent += sets->ufSetsNode[Root2].parent;

        sets->ufSetsNode[Root2].parent = Root1;
    } else {
        sets->ufSetsNode[Root2].parent += sets->ufSetsNode[Root1].parent;

        sets->ufSetsNode[Root1].parent = Root2;
    }


    return true;
}

/

//Kruskal算法 克鲁斯卡尔算法(贪心算法)
//本程序仅用来模拟过程,输出每一次循环的边
//时间复杂度|E|log2|E| log2|E|为给每边排序的时间,但本程序手动排序了
void Kruskal(MGraph G) {
    //手动初始化
    VerByWeight verByWeights[G.arcnum];
    verByWeights[0].head = 'A';
    verByWeights[0].tail = 'D';
    verByWeights[0].weight = 1;
    verByWeights[1].head = 'C';
    verByWeights[1].tail = 'F';
    verByWeights[1].weight = 2;
    verByWeights[2].head = 'B';
    verByWeights[2].tail = 'E';
    verByWeights[2].weight = 3;
    verByWeights[3].head = 'C';
    verByWeights[3].tail = 'D';
    verByWeights[3].weight = 4;
    verByWeights[4].head = 'D';
    verByWeights[4].tail = 'F';
    verByWeights[4].weight = 4;
    verByWeights[5].head = 'B';
    verByWeights[5].tail = 'D';
    verByWeights[5].weight = 5;
    verByWeights[6].head = 'A';
    verByWeights[6].tail = 'C';
    verByWeights[6].weight = 5;
    verByWeights[7].head = 'D';
    verByWeights[7].tail = 'E';
    verByWeights[7].weight = 6;
    verByWeights[8].head = 'E';
    verByWeights[8].tail = 'F';
    verByWeights[8].weight = 6;
    verByWeights[9].head = 'A';
    verByWeights[9].tail = 'B';
    verByWeights[9].weight = 6;
//初始化并查集
    UFSets ufSets;
    initSets(&ufSets);
    for (int i = 0; i < G.vernum; ++i) {
        ufSets.ufSetsNode[i].data = 'A' + i;
        ufSets.ufSetsNode[i].parent = -1;
        ufSets.count++;
    }
    int j = 0;
    for (int i = 0; i < G.arcnum; ++i) {
        //选择权重最小的边
        //并查集Union时间复杂度为常数,已进行优化
        if (UnionOptimize(&ufSets, verByWeights[i].head, verByWeights[i].tail)) {
            printf("第%d条边:%c%c,权重%d\n", ++j,
                   verByWeights[i].head, verByWeights[i].tail, verByWeights[i].weight);

        }

    }


}


int main(void) {

//无向图
    //初始化图
    MGraph graph = InitMgraph();
    //图添加元素
    //顶点集添加A,B,C,D,E,F
    for (int i = 0; i < 6; i++) {
        graph.vex[i] = (char) 'A' + i;
        graph.vernum++;

    }
    //边集加边(A,B),(A,C),(A,D),(B,E),(B,D),(C,D),(C,F),(D,E),(D,F),(E,F)
    graph.edge[0][1] = 6;
    graph.edge[0][2] = 5;
    graph.edge[0][3] = 1;
    graph.edge[1][3] = 5;
    graph.edge[1][4] = 3;
    graph.edge[2][3] = 4;
    graph.edge[2][5] = 2;
    graph.edge[3][4] = 6;
    graph.edge[3][5] = 4;
    graph.edge[4][5] = 6;

    graph.edge[1][0] = 6;
    graph.edge[2][0] = 5;
    graph.edge[3][0] = 1;
    graph.edge[3][1] = 5;
    graph.edge[4][1] = 3;
    graph.edge[3][2] = 4;
    graph.edge[5][2] = 2;
    graph.edge[4][3] = 6;
    graph.edge[5][3] = 4;
    graph.edge[5][4] = 6;
    graph.arcnum = 10;
    printf("普里姆算法找最小生成树\n");
    Prim(graph);
    printf("克鲁斯卡尔算法找最小生成树\n");
    Kruskal(graph);


}

测试用例

c语言数据结构-------最小生成树(Prim和Kruskal算法)_第1张图片

你可能感兴趣的:(c语言,数据结构,算法)