C语言-算法分析与设计-用Kruskal 算法实现最小生成树

实验内容

(1)用Kruskal 算法实现最小生成树

(2)画出程序运行时间与节点数n的关系图

(3)分析实验结果

Kruskal 算法

parent[1..n]←{1..n}  //森林由n棵树构成,每棵树只有一个结点。

    T←{ } //T为边的集合,初始时为空。

    while |T|<n-1

令(x,y)为下一条边

if Find(x)≠Find(y) then

   将(x,y)加入T

      Union(x,y)

end if

  end while

 public int find(int p) {

        // 直到找到根节点

        while (p != parent[p]) {

            p = parent[p];

        }

        return parent[p];

    }

 public void union(int p, int q) {

        int pRoot = find(p);

        int qRoot = find(q);

        if( pRoot==qRoot ) {

            // p节点、q节点的根节点一样, 故直接返回

            return;

        }

        // 将 p节点的根节点 指向 q节点的根节点

        parent[pRoot] = qRoot;

        // 连通分量的数量减1

}

运行结果

如图:

     顶点数为10,边数为5,随机生成树,运行之后得到最小生成树,耗时0.000126秒。

时间复杂度

实验结果

       显而易见,随着节点数n增加,运行时间也迅速增加。

原因分析

       在理论上,Kruskal算法的时间复杂度是O(ElogE),其中E是边的数量。这是因为算法需要对所有的边进行排序,所以时间复杂度与边的数量和对边的排序时间有关。

       在实际应用中,Kruskal算法的运行时间会受到许多因素的影响,例如内存访问速度、CPU速度、磁盘I/O速度等等。因此,很难准确地预测Kruskal算法的运行时间与节点数之间的关系。一般来说,随着节点数的增加,Kruskal算法的运行时间也会相应地增加。这是因为随着节点数的增加,边的数量也会增加,从而导致排序和查找环的时间增加。

遇到的问题

       算法的时间复杂度过高。

解决方法

       Kruskal算法的时间复杂度为O(ElogE),其中E为边的数量。为了优化算法的时间复杂度,可以使用一些技巧,例如使用优先队列(最小堆)来存储待检查的边,这样可以减少不必要的遍历。另外,可以使用一些优化算法,例如使用并查集来处理边冲突,这样可以减少不必要的比较和合并操作。

源码

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

#define MAX_VERTICES 100
#define MAX_EDGES 500
#define MAX_WEIGHT 100

typedef struct {
    int from, to, weight;
} Edge;

typedef struct {
    int parent;
    int rank;
} Subset;

int find(Subset subsets[], int i) {
    if (subsets[i].parent != i) {
        subsets[i].parent = find(subsets, subsets[i].parent);
    }
    return subsets[i].parent;
}

void unionSets(Subset subsets[], int x, int y) {
    int xroot = find(subsets, x);
    int yroot = find(subsets, y);

    if (subsets[xroot].rank < subsets[yroot].rank) {
        subsets[xroot].parent = yroot;
    } else if (subsets[xroot].rank > subsets[yroot].rank) {
        subsets[yroot].parent = xroot;
    } else {
        subsets[yroot].parent = xroot;
        subsets[xroot].rank++;
    }
}

int compareEdges(const void *a, const void *b) {
    return ((Edge*)a)->weight - ((Edge*)b)->weight;
}

void kruskal(int numVertices, int numEdges, Edge edges[]) {
    Edge result[MAX_VERTICES];
    Subset subsets[MAX_VERTICES];
    int e = 0;
    int i = 0;

    qsort(edges, numEdges, sizeof(Edge), compareEdges);

    for (int v = 0; v < numVertices; v++) {
        subsets[v].parent = v;
        subsets[v].rank = 0;
    }

    while (e < numVertices - 1 && i < numEdges) {
        Edge nextEdge = edges[i++];

        int x = find(subsets, nextEdge.from);
        int y = find(subsets, nextEdge.to);

        if (x != y) {
            result[e++] = nextEdge;
            unionSets(subsets, x, y);
        }
    }

    printf("最小生成树的边及权值:\n");
    for (int j = 0; j < e; j++) {
        printf("%d - %d, 权值: %d\n", result[j].from, result[j].to, result[j].weight);
    }
}

int main() {
    int numVertices, numEdges;
    Edge edges[MAX_EDGES];

    printf("请输入顶点个数:");
    scanf("%d", &numVertices);
    printf("请输入边数:");
    scanf("%d", &numEdges);

    if (numEdges > numVertices * (numVertices - 1) / 2) {
        printf("边数过多,无法构成连通图\n");
        return 1;
    }

    srand(time(NULL));
    printf("自动生成各边的权值:\n");
    for (int i = 0; i < numEdges; i++) {
        edges[i].from = rand() % numVertices;
        edges[i].to = rand() % numVertices;
        edges[i].weight = rand() % MAX_WEIGHT + 1;
        printf("边%d: %d - %d, 权值: %d\n", i+1, edges[i].from, edges[i].to, edges[i].weight);
    }

    clock_t start, end;
    start = clock();
    kruskal(numVertices, numEdges, edges);
    end = clock();
    printf("程序运行时间:%f秒\n", (double)(end - start) / CLOCKS_PER_SEC);

    return 0;
}

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是Prim算法Kruskal算法实现最小生成的C语言代码: 1. Prim算法实现最小生成 ```c #include <stdio.h> #include <limits.h> #define V 5 // 顶点数 int minKey(int key[], bool mstSet[]) { int min = INT_MAX, min_index; for (int v = 0; v < V; v++) { if (mstSet[v] == false && key[v] < min) { min = key[v], min_index = v; } } return min_index; } void printMST(int parent[], int graph[V][V]) { printf("Edge \tWeight\n"); for (int i = 1; i < V; i++) { printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]); } } void primMST(int graph[V][V]) { int parent[V]; int key[V]; bool mstSet[V]; for (int i = 0; i < V; i++) { key[i] = INT_MAX, mstSet[i] = false; } key[0] = 0; parent[0] = -1; for (int count = 0; count < V - 1; count++) { int u = minKey(key, mstSet); mstSet[u] = true; for (int v = 0; v < V; v++) { if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v]) { parent[v] = u, key[v] = graph[u][v]; } } } printMST(parent, graph); } ``` 2. Kruskal算法实现最小生成 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define V 5 // 顶点数 #define E 7 // 边数 struct Edge { int src, dest, weight; }; struct Graph { int V, E; struct Edge* edge;}; struct Graph* createGraph(int V, int E) { struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph)); graph->V = V; graph->E = E; graph->edge = (struct Edge*)malloc(graph->E * sizeof(struct Edge)); return graph; } int find(int parent[], int i) { if (parent[i] == -1) { return i; } return find(parent, parent[i]); } void Union(int parent[], int x, int y) { int xset = find(parent, x); int yset = find(parent, y); parent[xset] = yset; } int myComp(const void* a, const void* b) { struct Edge* a1 = (struct Edge*)a; struct Edge* b1 = (struct Edge*)b; return a1->weight > b1->weight; } void KruskalMST(struct Graph* graph) { int* parent = (int*)malloc(graph->V * sizeof(int)); memset(parent, -1, sizeof(int) * graph->V); qsort(graph->edge, graph->E, sizeof(graph->edge[0]), myComp); struct Edge result[graph->V]; int e = 0, i = 0; while (e < graph->V - 1 && i < graph->E) { struct Edge next_edge = graph->edge[i++]; int x = find(parent, next_edge.src); int y = find(parent, next_edge.dest); if (x != y) { result[e++] = next_edge; Union(parent, x, y); } } printf("Following are the edges in the constructed MST\n"); for (i = 0; i < e; ++i) { printf("%d -- %d == %d\n", result[i].src, result[i].dest, result[i].weight); } return; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西唯兵欧泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值