|
let tarjanStronglyConnected = function() { |
|
|
|
let eles = this; |
|
let nodes = {}; |
|
let index = 0; |
|
let components = []; |
|
let stack = []; |
|
let cut = eles.spawn(eles); |
|
|
|
const stronglyConnectedSearch = sourceNodeId => { |
|
stack.push(sourceNodeId); |
|
nodes[sourceNodeId] = { |
|
index : index, |
|
low : index++, |
|
explored : false |
|
}; |
|
|
|
let connectedEdges = eles.getElementById(sourceNodeId) |
|
.connectedEdges() |
|
.intersection(eles); |
|
|
|
connectedEdges.forEach(edge => { |
|
let targetNodeId = edge.target().id(); |
|
if (targetNodeId !== sourceNodeId) { |
|
if (!(targetNodeId in nodes)) { |
|
stronglyConnectedSearch(targetNodeId); |
|
} |
|
if (!(nodes[targetNodeId].explored)) { |
|
nodes[sourceNodeId].low = Math.min(nodes[sourceNodeId].low, |
|
nodes[targetNodeId].low); |
|
} |
|
} |
|
}); |
|
|
|
if (nodes[sourceNodeId].index === nodes[sourceNodeId].low) { |
|
let componentNodes = eles.spawn(); |
|
for (;;) { |
|
const nodeId = stack.pop(); |
|
componentNodes.merge(eles.getElementById(nodeId)); |
|
nodes[nodeId].low = nodes[sourceNodeId].index; |
|
nodes[nodeId].explored = true; |
|
if (nodeId === sourceNodeId) { |
|
break; |
|
} |
|
} |
|
|
|
let componentEdges = componentNodes.edgesWith(componentNodes); |
|
let component = componentNodes.merge(componentEdges); |
|
components.push(component); |
|
cut = cut.difference(component); |
|
} |
|
}; |
|
|
|
eles.forEach(ele => { |
|
if (ele.isNode()) { |
|
let nodeId = ele.id(); |
|
if (!(nodeId in nodes)) { |
|
stronglyConnectedSearch(nodeId); |
|
} |
|
} |
|
}); |
|
|
|
return { |
|
cut, |
|
components |
|
}; |
|
|
|
}; |
|
|
|
export default { |
|
tarjanStronglyConnected, |
|
tsc: tarjanStronglyConnected, |
|
tscc: tarjanStronglyConnected, |
|
tarjanStronglyConnectedComponents: tarjanStronglyConnected |
|
}; |
|
|