什么是Kruskal算法
最小生成树是一个图的极小连通子图,它包含原图的所有顶点,并且所有边的权值之和尽可能小。
之前描述了Prim算法是用于生成图结构的最小生成树,而Kruskal算法(中文名:克鲁斯卡尔算法),是另外一种最小生成树算法,用的也是贪婪算法的思想。
Kruskal算法详细解析
以下算法详细步骤图,均来自B站up主”WAY_zhong”的视频——《最小生成树(Kruskal(克鲁斯卡尔)和Prim(普里姆))算法动画演示》
最小生成树既然是树,则需要遵循树的以下几个规则:
1.因为是树的结构,所有结构中不能形成环。
2.必须连接图结构中的所有顶点,任意两个顶点间都是互通的。
3.如果树有n个顶点,它对应边的个数就是n-1个。
假如有这样一个无向带权图
接着把图实例中所有的边取出,放到一个列表中
并按照边的权值,由小到大进行排列
接着在列表中按次序,每次取出一条边,回添到图实例中,不断重复此过程……
每次添加一条边,都判断是否形成了环(形成了环),如果如果没有形成环,那么这个条边就会被选中,成为最小生成树的一条边。
相反,如果形成了环,这条边则会被抛弃,接着判断列表中的下一条边
直到选择了n-1条边(满足树对边的规则),其中n是顶点的个数,此时最小生成树完成。
完整可视化算法流程可参考B站原作者的视频:
最小生成树(Kruskal(克鲁斯卡尔)和Prim(普里姆))算法动画演示
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| const INF = Number.MAX_SAFE_INTEGER;
const find = (i, parent) => { while (parent[i]) { i = parent[i]; } return i; };
const union = (i, j, parent) => { if (i !== j) { parent[j] = i; return true; } return false; };
const initializeCost = graph => { const cost = []; const { length } = graph; for (let i = 0; i < length; i++) { cost[i] = []; for (let j = 0; j < length; j++) { if (graph[i][j] === 0) { cost[i][j] = INF; } else { cost[i][j] = graph[i][j]; } } } return cost; };
export const kruskal = graph => { const { length } = graph; const parent = []; let ne = 0; let a; let b; let u; let v; const cost = initializeCost(graph); while (ne < length - 1) { for (let i = 0, min = INF; i < length; i++) { for (let j = 0; j < length; j++) { if (cost[i][j] < min) { min = cost[i][j]; a = u = i; b = v = j; } } } u = find(u, parent); v = find(v, parent); if (union(u, v, parent)) { ne++; } cost[a][b] = cost[b][a] = INF; } return parent; };
|