Kruskal最小生成树算法
在一个无向图中,获取一个可以连通的且权重和最小的图,可以连通指每个节点都被连接,如上图右边部分
- 最小生成图:一定是没有环的,权重和最低,意味着要排序从最小边开始建图
- 以第二个图的节点距离:首先为每个节点创建一个集合,初始情况下每个集合都只包含自身节点,如{A},{B},{C},...
- 从边开始创建最小图,从最小的边开始如上图的A-C,判断两个节点是否在一个集合中,A和C不在,则A、C的节点集合合并,{A,C}
- 然后是C-D,CD不在一个集合中,则合并集合,{A,C,D}
- 然后是A-B,BC不在一个集合中,则合并集合,{A,B,C,D}
- 然后是A-D,AD在一个集合中,跳过
- 然后是B-D,BD在一个集合中,跳过
- 然后是B-E,B-E不在一个集合中,则合并集合,{A,B,C,D,E},则最终形成的图的节点为{A,B,C,D,E}
function Kruskal(graph) {
let map = new Map();
let result = [];
//获取图中所有的节点
graph.nodes.values().forEach((node) => {
let list = [];
list.push(node);
//维护每个节点的集合
map.set(node, list);
});
//根据边的权重排序(从大到小)
let edgeArr = graph.edges;
edgeArr = edgeArr.sort((a, b) => b.priority - a.priority);
//从最小边开始放
while (edgeArr.length) {
let edge = edgeArr.pop();
//判断边的两个节点是否在一个集合中(是否形成环)
if (!isInSameList(edge.from, edge.to)) {
result.push(edge);
//不在一个集合中,进行合并集合的操作
union(edge.from, edge.to);
}
}
function isInSameList(from, to) {
let fromList = map.get(from);
let toList = map.get(to);
//通过内存地址来判断是否是同一个集合(是否会形成环)
if (fromList === toList) {
return true;
}
return false;
}
//合并集合
function union(from, to) {
let fromList = map.get(from);
let toList = map.get(to);
//将要合并的to节点的集合都加到from节点的集合中
toList.forEach((node) => {
fromList.push(node);
//将to节点的集合修改成fromList,这样两个节点的集合就是同一引用
map.set(node, fromList);
});
}
}