(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
config: SearchConfig = {}
)
| 3559 | * @category iterators |
| 3560 | */ |
| 3561 | export const dfsPostOrder = <N, E, T extends Kind = "directed">( |
| 3562 | graph: Graph<N, E, T> | MutableGraph<N, E, T>, |
| 3563 | config: SearchConfig = {} |
| 3564 | ): NodeWalker<N> => { |
| 3565 | const start = config.start ?? [] |
| 3566 | const direction = config.direction ?? "outgoing" |
| 3567 | |
| 3568 | // Validate that all start nodes exist |
| 3569 | for (const nodeIndex of start) { |
| 3570 | if (!hasNode(graph, nodeIndex)) { |
| 3571 | throw missingNode(nodeIndex) |
| 3572 | } |
| 3573 | } |
| 3574 | |
| 3575 | return new Walker((f) => ({ |
| 3576 | [Symbol.iterator]: () => { |
| 3577 | const stack: Array<{ node: NodeIndex; visitedChildren: boolean }> = [] |
| 3578 | const discovered = new Set<NodeIndex>() |
| 3579 | const finished = new Set<NodeIndex>() |
| 3580 | |
| 3581 | // Initialize stack with start nodes |
| 3582 | for (let i = start.length - 1; i >= 0; i--) { |
| 3583 | stack.push({ node: start[i], visitedChildren: false }) |
| 3584 | } |
| 3585 | |
| 3586 | const nextMapped = () => { |
| 3587 | while (stack.length > 0) { |
| 3588 | const current = stack[stack.length - 1] |
| 3589 | |
| 3590 | if (!discovered.has(current.node)) { |
| 3591 | discovered.add(current.node) |
| 3592 | current.visitedChildren = false |
| 3593 | } |
| 3594 | |
| 3595 | if (!current.visitedChildren) { |
| 3596 | current.visitedChildren = true |
| 3597 | const neighbors = getTraversalNeighbors(graph, current.node, direction) |
| 3598 | |
| 3599 | for (let i = neighbors.length - 1; i >= 0; i--) { |
| 3600 | const neighbor = neighbors[i] |
| 3601 | if (!discovered.has(neighbor) && !finished.has(neighbor)) { |
| 3602 | stack.push({ node: neighbor, visitedChildren: false }) |
| 3603 | } |
| 3604 | } |
| 3605 | } else { |
| 3606 | const nodeToEmit = stack.pop()!.node |
| 3607 | |
| 3608 | if (!finished.has(nodeToEmit)) { |
| 3609 | finished.add(nodeToEmit) |
| 3610 | |
| 3611 | const nodeData = getNode(graph, nodeToEmit) |
| 3612 | if (Option.isSome(nodeData)) { |
| 3613 | return { done: false, value: f(nodeToEmit, nodeData.value) } |
| 3614 | } |
| 3615 | return nextMapped() |
| 3616 | } |
| 3617 | } |
| 3618 | } |
nothing calls this directly
no test coverage detected