@antv/algorithm
Version:
graph algorithm
113 lines • 3.76 kB
JavaScript
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;