Files
lan-manager/web/node_modules/@antv/algorithm/es/connected-component.js
openclaw 0a5f6a8047 Initial commit: Lan-manager project code
- Go backend (server/)
- Frontend (web/, server/static/)
- Database and deployment files
- Scripts and docs

Co-Authored-By: 狸花猫/Claude-Qwen3.6-Plus 🐾
2026-04-20 00:52:58 +08:00

123 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { getNeighbors } from "./util";
/**
* Generate all connected components for an undirected graph
* @param graph
*/
export var detectConnectedComponents = function detectConnectedComponents(graphData) {
var _a = graphData.nodes,
nodes = _a === void 0 ? [] : _a,
_b = graphData.edges,
edges = _b === void 0 ? [] : _b;
var allComponents = [];
var visited = {};
var nodeStack = [];
var getComponent = function getComponent(node) {
nodeStack.push(node);
visited[node.id] = true;
var neighbors = getNeighbors(node.id, edges);
var _loop_1 = function _loop_1(i) {
var neighbor = neighbors[i];
if (!visited[neighbor]) {
var targetNode = nodes.filter(function (node) {
return node.id === neighbor;
});
if (targetNode.length > 0) {
getComponent(targetNode[0]);
}
}
};
for (var i = 0; i < neighbors.length; ++i) {
_loop_1(i);
}
};
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (!visited[node.id]) {
// 对于无向图进行dfs遍历每一次调用后都得到一个连通分量
getComponent(node);
var component = [];
while (nodeStack.length > 0) {
component.push(nodeStack.pop());
}
allComponents.push(component);
}
}
return allComponents;
};
/**
* Tarjan's Algorithm 复杂度 O(|V|+|E|)
* For directed graph only
* a directed graph is said to be strongly connected if "every vertex is reachable from every other vertex".
* refer: http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
* @param graph
* @return a list of strongly connected components
*/
export var detectStrongConnectComponents = function detectStrongConnectComponents(graphData) {
var _a = graphData.nodes,
nodes = _a === void 0 ? [] : _a,
_b = graphData.edges,
edges = _b === void 0 ? [] : _b;
var nodeStack = [];
var inStack = {}; // 辅助判断是否已经在stack中减少查找开销
var indices = {};
var lowLink = {};
var allComponents = [];
var index = 0;
var getComponent = function getComponent(node) {
// Set the depth index for v to the smallest unused index
indices[node.id] = index;
lowLink[node.id] = index;
index += 1;
nodeStack.push(node);
inStack[node.id] = true;
// 考虑每个邻接点
var neighbors = getNeighbors(node.id, edges, 'target').filter(function (n) {
return nodes.map(function (node) {
return node.id;
}).indexOf(n) > -1;
});
var _loop_2 = function _loop_2(i) {
var targetNodeID = neighbors[i];
if (!indices[targetNodeID] && indices[targetNodeID] !== 0) {
var targetNode = nodes.filter(function (node) {
return node.id === targetNodeID;
});
if (targetNode.length > 0) {
getComponent(targetNode[0]);
}
// tree edge
lowLink[node.id] = Math.min(lowLink[node.id], lowLink[targetNodeID]);
} else if (inStack[targetNodeID]) {
// back edge, target node is in the current SCC
lowLink[node.id] = Math.min(lowLink[node.id], indices[targetNodeID]);
}
};
for (var i = 0; i < neighbors.length; i++) {
_loop_2(i);
}
// If node is a root node, generate an SCC
if (lowLink[node.id] === indices[node.id]) {
var component = [];
while (nodeStack.length > 0) {
var tmpNode = nodeStack.pop();
inStack[tmpNode.id] = false;
component.push(tmpNode);
if (tmpNode === node) break;
}
if (component.length > 0) {
allComponents.push(component);
}
}
};
for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
var node = nodes_1[_i];
if (!indices[node.id] && indices[node.id] !== 0) {
getComponent(node);
}
}
return allComponents;
};
export default function getConnectedComponents(graphData, directed) {
if (directed) return detectStrongConnectComponents(graphData);
return detectConnectedComponents(graphData);
}