正在载入交互式动画窗口请稍等
Kruskal(克鲁斯卡尔)算法 可视化交互式动画版
在克鲁斯卡尔算法中,按升序对给定图的所有边进行排序。 如果新添加的边不形成环,则继续在MST中添加新的边和节点。 它首先选择最小加权边,最后选择最大加权边。 因此我们可以说它在每一步中都做出局部最优选择以找到最优解。 因此这是一个 贪婪算法 。
最小生成树 (MST) 或带权连通无向图的最小权重生成树是权重小于或等于所有其他生成树权重的生成树。 要了解有关最小生成树的更多信息,请参阅 这篇文章 。
克鲁斯卡尔算法简介:
在这里,我们将讨论 Kruskal 算法 来查找给定加权图的 MST。
如何使用Kruskal算法求MST?
以下是使用 Kruskal 算法查找 MST 的步骤:
- 按权重非降序对所有边进行排序。
- 选择最小的边。 检查是否与目前形成的生成树形成环。 如果未形成循环,则包括该边。 否则,丢弃它。
- 重复步骤#2,直到生成树中有 (V-1) 条边。
步骤2 使用 并查算法 来检测循环。
因此,我们建议您先阅读以下文章作为先决条件。
- 并查算法| 第 1 组(检测图中的循环)
- 并查算法| 设置 2(按等级和路径压缩联合)
Kruskal 寻找最小成本生成树的算法使用贪心方法。 贪心选择是在目前构建的 MST 中选择不会引起循环的最小权重边。 让我们通过一个例子来理解它:
插图:
下面是上述方法的图示:
输入图:
该图包含 9 个顶点和 14 条边。 因此,形成的最小生成树将具有 (9 – 1) = 8 个边。
排序后:
重量 来源 目的地 1 7 6 2 8 2 2 6 5 4 0 1 4 2 5 6 8 6 7 2 3 7 7 8 8 0 7 8 1 2 9 3 4 10 5 4 11 1 7 14 3 5 现在从已排序的边列表中一一挑选所有边
步骤1: 选取边7-6。 没有形成循环,包括它。
步骤2: 选取边8-2。 没有形成循环,包括它。
步骤3: 选取边6-5。 没有形成循环,包括它。
步骤 4: 选取边 0-1。 没有形成循环,包括它。
步骤5: 选取边2-5。 没有形成循环,包括它。
第6步: 选取边8-6。 由于包含该边会导致循环,因此将其丢弃。 拾取边2-3: 未形成循环,包含它。
步骤7: 选取边7-8。 由于包含该边会导致循环,因此将其丢弃。 选边 0-7。 没有形成循环,包括它。
第8步: 选取边1-2。 由于包含该边会导致循环,因此将其丢弃。 选取边 3-4。 没有形成循环,包括它。
注: 由于MST包含的边数等于(V – 1),所以算法到此停止
下面是上述方法的实现:
- C++
- C
- Java
- Python3
- C#
- JavaScript
C++
// C++ program for the above approach #include <bits/stdc++.h> using namespace std; // DSU data structure // path compression + rank by union class DSU { int * parent; int * rank; public : DSU( int n) { parent = new int [n]; rank = new int [n]; for ( int i = 0; i < n; i++) { parent[i] = -1; rank[i] = 1; } } // Find function int
find( int i) { if (parent[i] == -1) return i; return parent[i] = find(parent[i]);
} // Union function void unite( int x, int y) { int s1 = find(x); int s2 = find(y); if (s1 != s2) { if (rank[s1] < rank[s2]) { parent[s1] = s2; } else if (rank[s1] > rank[s2]) { parent[s2] = s1; } else { parent[s2] = s1; rank[s1] += 1; } } } }; class Graph { vector<vector< int > > edgelist; int
V; public : Graph( int V) { this ->V = V; } // Function to add edge in a graph void addEdge( int x, int y, int w) { edgelist.push_back({ w, x, y }); } void kruskals_mst() { // Sort all edges sort(edgelist.begin(), edgelist.end()); // Initialize the DSU DSU s(V); int ans = 0; cout << "Following are the edges in the " "constructed MST" << endl; for ( auto edge : edgelist) { int w = edge[0]; int x = edge[1]; int y = edge[2]; // Take this edge in MST if it does // not forms a cycle if (s.find(x) != s.find(y)) { s.unite(x, y); ans += w; cout << x << " -- " << y << " == " << w << endl; } } cout << "Minimum Cost Spanning Tree: " << ans; } }; // Driver code int main() { Graph g(4); g.addEdge(0, 1, 10); g.addEdge(1, 3, 15); g.addEdge(2, 3, 4); g.addEdge(2, 0, 6); g.addEdge(0, 3, 5);
// Function call g.kruskals_mst();
return 0; } |
C
Java
Python3
C#
Javascript
以下是构建的 MST 中的边 2 -- 3 == 4 0 -- 3 == 5 0 -- 1 == 10 最小成本生成树:19
时间复杂度: O(E * logE) 或 O(E * logV)
- 边排序需要 O(E * logE) 时间。
- 排序后,我们迭代所有边并应用查找并集算法。 查找和并集操作最多需要 O(logV) 时间。
- 所以总体复杂度是 O(E * logE + E * logV) 时间。
- E的值最多可以是O(V 2 ),因此O(logV)和O(logE)是相同的。 因此,总体时间复杂度为 O(E * logE) 或 O(E*logV)
辅助空间: O(V + E),其中V是图中的顶点数,E是图中的边数。
本文由 Aashish Barnwal编译 ,并由 图码 团队审核。 如果您发现任何不正确的内容,或者您想分享有关上述主题的更多信息,请发表评论。