Skip to content

Commit 07bd625

Browse files
committed
[Basics] Implement a pre-order depth-first graph traversal algorithm
1 parent 32442c6 commit 07bd625

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

Sources/Basics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ add_library(Basics
3636
FileSystem/VFSOverlay.swift
3737
Graph/AdjacencyMatrix.swift
3838
Graph/DirectedGraph.swift
39+
Graph/GraphAlgorithms.swift
3940
Graph/UndirectedGraph.swift
4041
SourceControlURL.swift
4142
HTTPClient/HTTPClient.swift
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2015-2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import struct OrderedCollections.OrderedSet
14+
15+
/// Implements a pre-order depth-first search.
16+
///
17+
/// The cycles are handled by skipping cycle points but it should be possible to
18+
/// to extend this in the future to provide a callback for every cycle.
19+
///
20+
/// - Parameters:
21+
/// - nodes: The list of input nodes to sort.
22+
/// - successors: A closure for fetching the successors of a particular node.
23+
/// - onUnique: A callback to indicate the the given node is being processed for the first time.
24+
/// - onDuplicate: A callback to indicate that the node was already processed at least once.
25+
///
26+
/// - Complexity: O(v + e) where (v, e) are the number of vertices and edges
27+
/// reachable from the input nodes via the relation.
28+
public func DFS<T: Hashable>(
29+
_ nodes: [T],
30+
successors: (T) throws -> [T],
31+
onUnique: (T) -> Void,
32+
onDuplicate: (T, T) -> Void
33+
) rethrows {
34+
var stack = OrderedSet<T>()
35+
var visited = Set<T>()
36+
37+
for node in nodes {
38+
precondition(stack.isEmpty)
39+
stack.append(node)
40+
41+
while !stack.isEmpty {
42+
let curr = stack.removeLast()
43+
44+
let visitResult = visited.insert(curr)
45+
if visitResult.inserted {
46+
onUnique(curr)
47+
} else {
48+
onDuplicate(visitResult.memberAfterInsert, curr)
49+
continue
50+
}
51+
52+
for succ in try successors(curr).reversed() {
53+
stack.append(succ)
54+
}
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)