g6/plugins/template.maxSpanningForest/maxSpanningForest.js

113 lines
2.8 KiB
JavaScript
Raw Normal View History

2018-06-05 23:58:10 +08:00
/**
* @fileOverview 最大生成森林
* @author huangtonger@aliyun.com
*/
2018-06-13 17:38:00 +08:00
const G6 = require('../../src/index');
2018-06-05 23:58:10 +08:00
const { Util } = G6;
const maxSpanningTree = require('./maxSpanningTree');
function maxSpanningForest(nodes, edges) {
const connectedSubsets = [];
const forest = {
nodes: [],
edges: [],
maxRankNode: null
};
const nodeMap = {};
let maxRank = -Infinity;
Util.each(nodes, node => {
node.links = [];
node.edges = [];
nodeMap[node.id] = node;
if (Util.isNil(node.weight)) {
node.weight = 1;
}
if (Util.isNil(node.rank)) {
if (node.weight) {
node.rank = node.weight;
} else {
node.rank = 1;
}
}
});
Util.each(edges, (edge, i) => {
const source = nodeMap[edge.source];
const target = nodeMap[edge.target];
source.links.push(nodes.indexOf(target));
target.links.push(nodes.indexOf(source));
source.edges.push(i);
target.edges.push(i);
if (Util.isNil(edge.weight)) {
edge.weight = 1;
}
});
Util.each(nodes, (node, i) => {
if (!node.visited) {
connectedSubsets.push(getConnectedSubset(i, nodes, edges));
}
});
Util.each(nodes, node => {
delete node.links;
delete node.edges;
delete node.visited;
});
Util.each(connectedSubsets, connectedSubset => {
const tree = maxSpanningTree(connectedSubset);
const root = connectedSubset.root;
forest.nodes = forest.nodes.concat(tree.nodes);
forest.edges = forest.edges.concat(tree.edges);
if (root.rank > maxRank) {
maxRank = root.rank;
forest.maxRankNode = root;
}
});
return forest;
}
// 获取连通子集
function getConnectedSubset(start, nodes, edges) {
const connectedSubset = {
nodes: [],
edges: [],
root: null
};
const edgeMap = {};
const subEdges = [];
let maxRank = -Infinity;
dfs(start, nodes, index => {
const node = nodes[index];
if (node.rank > maxRank) {
maxRank = node.rank;
connectedSubset.root = node;
}
connectedSubset.nodes.push(node);
connectedSubset.edges = connectedSubset.edges.concat(node.edges);
});
// 边索引去重
Util.each(connectedSubset.edges, edgeIndex => {
if (!edgeMap[edgeIndex]) {
subEdges.push(edges[edgeIndex]);
edgeMap[edgeIndex] = true;
}
});
connectedSubset.edges = subEdges;
return connectedSubset;
}
// 深度优先遍历算法
function dfs(start, nodes, callback) {
const listToExplore = [ start ];
nodes[ start ].visited = true;
callback(start);
while (listToExplore.length > 0) {
const nodeIndex = listToExplore.pop();
nodes[ nodeIndex ].links.forEach(function(childIndex) {
if (!nodes[ childIndex ].visited) {
nodes[ childIndex ].visited = true;
callback(childIndex);
listToExplore.push(childIndex);
}
});
}
}
module.exports = maxSpanningForest;