You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.7 KiB
113 lines
3.7 KiB
import UnionFind from './structs/union-find';
|
|
import MinBinaryHeap from './structs/binary-heap';
|
|
import { getEdgesByNodeId } from './util';
|
|
/**
|
|
* Prim algorithm,use priority queue,复杂度 O(E+V*logV), V: 节点数量,E: 边的数量
|
|
* refer: https://en.wikipedia.org/wiki/Prim%27s_algorithm
|
|
* @param graph
|
|
* @param weight 指定用于作为边权重的属性,若不指定,则认为所有边权重一致
|
|
*/
|
|
var primMST = function primMST(graphData, weight) {
|
|
var selectedEdges = [];
|
|
var _a = graphData.nodes,
|
|
nodes = _a === void 0 ? [] : _a,
|
|
_b = graphData.edges,
|
|
edges = _b === void 0 ? [] : _b;
|
|
if (nodes.length === 0) {
|
|
return selectedEdges;
|
|
}
|
|
// 从nodes[0]开始
|
|
var currNode = nodes[0];
|
|
var visited = new Set();
|
|
visited.add(currNode);
|
|
// 用二叉堆维护距已加入节点的其他节点的边的权值
|
|
var compareWeight = function compareWeight(a, b) {
|
|
if (weight) {
|
|
return a.weight - b.weight;
|
|
}
|
|
return 0;
|
|
};
|
|
var edgeQueue = new MinBinaryHeap(compareWeight);
|
|
getEdgesByNodeId(currNode.id, edges).forEach(function (edge) {
|
|
edgeQueue.insert(edge);
|
|
});
|
|
while (!edgeQueue.isEmpty()) {
|
|
// 选取与已加入的结点之间边权最小的结点
|
|
var currEdge = edgeQueue.delMin();
|
|
var source = currEdge.source;
|
|
var target = currEdge.target;
|
|
if (visited.has(source) && visited.has(target)) continue;
|
|
selectedEdges.push(currEdge);
|
|
if (!visited.has(source)) {
|
|
visited.add(source);
|
|
getEdgesByNodeId(source, edges).forEach(function (edge) {
|
|
edgeQueue.insert(edge);
|
|
});
|
|
}
|
|
if (!visited.has(target)) {
|
|
visited.add(target);
|
|
getEdgesByNodeId(target, edges).forEach(function (edge) {
|
|
edgeQueue.insert(edge);
|
|
});
|
|
}
|
|
}
|
|
return selectedEdges;
|
|
};
|
|
/**
|
|
* Kruskal algorithm,复杂度 O(E*logE), E: 边的数量
|
|
* refer: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm
|
|
* @param graph
|
|
* @param weight 指定用于作为边权重的属性,若不指定,则认为所有边权重一致
|
|
* @return IEdge[] 返回构成MST的边的数组
|
|
*/
|
|
var kruskalMST = function kruskalMST(graphData, weight) {
|
|
var selectedEdges = [];
|
|
var _a = graphData.nodes,
|
|
nodes = _a === void 0 ? [] : _a,
|
|
_b = graphData.edges,
|
|
edges = _b === void 0 ? [] : _b;
|
|
if (nodes.length === 0) {
|
|
return selectedEdges;
|
|
}
|
|
// 若指定weight,则将所有的边按权值从小到大排序
|
|
var weightEdges = edges.map(function (edge) {
|
|
return edge;
|
|
});
|
|
if (weight) {
|
|
weightEdges.sort(function (a, b) {
|
|
return a.weight - b.weight;
|
|
});
|
|
}
|
|
var disjointSet = new UnionFind(nodes.map(function (n) {
|
|
return n.id;
|
|
}));
|
|
// 从权值最小的边开始,如果这条边连接的两个节点于图G中不在同一个连通分量中,则添加这条边
|
|
// 直到遍历完所有点或边
|
|
while (weightEdges.length > 0) {
|
|
var curEdge = weightEdges.shift();
|
|
var source = curEdge.source;
|
|
var target = curEdge.target;
|
|
if (!disjointSet.connected(source, target)) {
|
|
selectedEdges.push(curEdge);
|
|
disjointSet.union(source, target);
|
|
}
|
|
}
|
|
return selectedEdges;
|
|
};
|
|
/**
|
|
* 最小生成树
|
|
* refer: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm
|
|
* @param graph
|
|
* @param weight 指定用于作为边权重的属性,若不指定,则认为所有边权重一致
|
|
* @param algo 'prim' | 'kruskal' 算法类型
|
|
* @return EdgeConfig[] 返回构成MST的边的数组
|
|
*/
|
|
var minimumSpanningTree = function minimumSpanningTree(graphData, weight, algo) {
|
|
var algos = {
|
|
prim: primMST,
|
|
kruskal: kruskalMST
|
|
};
|
|
if (!algo) return kruskalMST(graphData, weight);
|
|
return algos[algo](graphData, weight);
|
|
};
|
|
export default minimumSpanningTree;
|