Commit 300493e
authored
fix(core): use Set for O(1) visited node lookup in hasPath (#33754)
## Current Behavior
The `hasPath` function in `graph.ts` uses an array with `indexOf()` for
tracking visited nodes during recursive graph traversal:
```typescript
function hasPath(graph, target, node, visited: string[]) {
for (let d of graph.dependencies[node] || []) {
if (visited.indexOf(d.target) > -1) continue; // O(n) lookup
visited.push(d.target);
// recursive call...
}
}
```
This results in O(n) lookups per node visited, making worst-case
traversal O(n²).
## Expected Behavior
Use `Set` for O(1) visited node tracking:
```typescript
function hasPath(graph, target, node, visited: Set<string>) {
for (const d of graph.dependencies[node] || []) {
if (visited.has(d.target)) continue; // O(1) lookup
visited.add(d.target);
// recursive call...
}
}
```
## Performance Impact
```
Before (Array + indexOf): After (Set + has):
┌─────────────────────────┐ ┌─────────────────────────┐
│ hasPath() called │ │ hasPath() called │
└───────────┬─────────────┘ └───────────┬─────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ visited.indexOf(target) │ │ visited.has(target) │
│ O(n) lookup │ │ O(1) lookup │
└───────────┬─────────────┘ └───────────┬─────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ visited.push(target) │ │ visited.add(target) │
│ O(1) │ │ O(1) │
└───────────┬─────────────┘ └───────────┬─────────────┘
│ │
▼ ▼
Complexity: O(n²) Complexity: O(n)
for full traversal for full traversal
```
**Example with 500 nodes:**
- Before: 500 nodes × avg 250 indexOf lookups = ~125,000 comparisons
- After: 500 nodes × 1 Set lookup each = 500 operations
## Why Accept This PR
1. **Zero risk**: Same semantics, just faster data structure
2. **Standard pattern**: Set is the idiomatic choice for visited
tracking in graph algorithms
3. **Measurable impact**: Graph filtering with `--focus` flag will be
significantly faster on large monorepos
## Related Issue(s)
Contributes to #32265
## Merge Dependencies
This PR has no dependencies and can be merged independently.
---1 parent c6b2a26 commit 300493e
1 file changed
Lines changed: 6 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
183 | 183 | | |
184 | 184 | | |
185 | 185 | | |
186 | | - | |
| 186 | + | |
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
191 | | - | |
192 | | - | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
193 | 193 | | |
194 | 194 | | |
195 | 195 | | |
| |||
210 | 210 | | |
211 | 211 | | |
212 | 212 | | |
213 | | - | |
| 213 | + | |
| 214 | + | |
214 | 215 | | |
215 | 216 | | |
216 | 217 | | |
| |||
0 commit comments