MCPcopy Create free account
hub / github.com/esengine/esengine / kahnSort

Function kahnSort

packages/runtime-core/src/utils/DependencyUtils.ts:185–243  ·  view source on GitHub ↗

* @zh 使用 Kahn 算法进行拓扑排序 * @en Topological sort using Kahn's algorithm * * @zh Kahn 算法优势: * - 能够检测循环依赖 * - 返回所有循环中的节点 * - 时间复杂度 O(V + E)

(
    items: T[],
    resolveId: (id: string) => string
)

Source from the content-addressed store, hash-verified

183 * - 时间复杂度 O(V + E)
184 */
185function kahnSort<T extends IDependable>(
186 items: T[],
187 resolveId: (id: string) => string
188): TopologicalSortResult<T> {
189 const itemMap = new Map<string, T>();
190 const graph = new Map<string, Set<string>>();
191 const inDegree = new Map<string, number>();
192
193 // 构建节点映射
194 for (const item of items) {
195 itemMap.set(item.id, item);
196 graph.set(item.id, new Set());
197 inDegree.set(item.id, 0);
198 }
199
200 // 构建边(依赖 -> 被依赖者)
201 for (const item of items) {
202 for (const dep of item.dependencies || []) {
203 const depId = resolveId(dep);
204 if (itemMap.has(depId)) {
205 graph.get(depId)!.add(item.id);
206 inDegree.set(item.id, (inDegree.get(item.id) || 0) + 1);
207 }
208 }
209 }
210
211 // 收集入度为 0 的节点
212 const queue: string[] = [];
213 for (const [id, degree] of inDegree) {
214 if (degree === 0) {
215 queue.push(id);
216 }
217 }
218
219 // BFS 处理
220 const sorted: T[] = [];
221 while (queue.length > 0) {
222 const current = queue.shift()!;
223 sorted.push(itemMap.get(current)!);
224
225 for (const neighbor of graph.get(current) || []) {
226 const newDegree = (inDegree.get(neighbor) || 0) - 1;
227 inDegree.set(neighbor, newDegree);
228 if (newDegree === 0) {
229 queue.push(neighbor);
230 }
231 }
232 }
233
234 // 检查循环依赖
235 if (sorted.length !== items.length) {
236 const cycleIds = items
237 .filter(item => !sorted.includes(item))
238 .map(item => item.id);
239 return { sorted, hasCycles: true, cycleIds };
240 }
241
242 return { sorted, hasCycles: false };

Callers 1

topologicalSortFunction · 0.85

Calls 8

resolveIdFunction · 0.85
setMethod · 0.65
hasMethod · 0.65
getMethod · 0.65
pushMethod · 0.65
filterMethod · 0.65
addMethod · 0.45
mapMethod · 0.45

Tested by

no test coverage detected