Swift Program to Implement Depth-First Search (DFS)

Swift Program to Implement Depth-First Search (DFS)

Depth-First Search, often called DFS, is one of the most important graph-traversal algorithms in computer science. It explores a graph or tree by going as deep as possible into one path before stepping back and exploring the next. This creates a natural “diving” effect where the algorithm tries to reach the deepest node before returning to the surface. Because of this behaviour, DFS is excellent for solving problems such as pathfinding, cycle detection, topological sorting, and exploring tree structures.

Pluralsight Logo
Accelerate your tech career
with hands-on learning.
Whether you're a tech newbie or a total pro,
get the skills and confidence to land your next move.
Start 10-Day Free Trial

What makes DFS special is how flexible it is. You can write it using recursion, a stack, or even mix it with other techniques to suit your needs. It works well in many real-world situations, from navigating folder structures to analysing social networks. For Swift beginners, learning DFS is a great way to build confidence when working with graphs and data structures, because it shows how a simple idea can power many kinds of tasks.

Program 1: Basic Recursive DFS on a Graph

This first program shows a simple recursive DFS on a graph represented with adjacency lists. It is the most common way to introduce DFS and helps beginners clearly see how the algorithm moves through nodes.

import Foundation

func dfsRecursive(_ graph: [Int: [Int]], start: Int, visited: inout Set<Int>) {

    visited.insert(start)
    print(start)

    if let neighbors = graph[start] {

        for node in neighbors {

            if !visited.contains(node) {
                dfsRecursive(graph, start: node, visited: &visited)
            }

        }

    }

}

let graph: [Int: [Int]] = [
    1: [2, 3],
    2: [4],
    3: [5],
    4: [],
    5: []
]

var visited = Set<Int>()

dfsRecursive(graph, start: 1, visited: &visited)

This recursive version starts at a given node and keeps visiting its neighbours until it reaches the end of a branch. Once it can go no deeper, it returns to explore the next branch. This natural flow makes recursion very easy to understand, especially when dealing with tree-like structures.

Program 2: Iterative DFS Using a Stack

This version removes recursion entirely and uses a Swift array as a stack. It helps learners understand the internal behaviour of DFS by manually controlling which node gets processed next.

import Foundation

func dfsIterative(_ graph: [Int: [Int]], start: Int) {

    var stack: [Int] = [start]
    var visited = Set<Int>()

    while !stack.isEmpty {

        let node = stack.removeLast()

        if !visited.contains(node) {

            visited.insert(node)
            print(node)

            if let neighbors = graph[node] {

                for n in neighbors.reversed() {
                    stack.append(n)
                }

            }

        }

    }

}

let graph2: [Int: [Int]] = [
    1: [2, 3],
    2: [4],
    3: [5],
    4: [],
    5: []
]

dfsIterative(graph2, start: 1)

This style shows the inner mechanics of DFS clearly. Each time a node is processed, its neighbours are pushed onto the stack. The last neighbour pushed becomes the next node visited, which mirrors the “deep first” behaviour. It is very useful for learners who want more control and visibility without recursion.

Program 3: DFS on a Tree Structure

Here the algorithm is applied to a custom tree structure. Many Swift beginners work with trees in apps, so this version keeps the example practical.

import Foundation

class TreeNode {

    var value: Int
    var children: [TreeNode]

    init(_ value: Int, _ children: [TreeNode] = []) {
        self.value = value
        self.children = children
    }

}

func dfsTree(_ node: TreeNode) {

    print(node.value)

    for child in node.children {
        dfsTree(child)
    }

}

let root = TreeNode(1, [
    TreeNode(2, [TreeNode(4)]),
    TreeNode(3, [TreeNode(5)])
])

dfsTree(root)

This version shows how DFS fits naturally with trees. Each node processes itself first, then explores every child deeply before moving to the next. For beginners, this is a very friendly introduction because the structure mirrors real-world hierarchies like menus or folders.

Program 4: DFS With Path Tracking

This version keeps track of the current path from the start node to wherever DFS has travelled. This style is helpful for problems such as checking routes or exploring all possible paths.

import Foundation

func dfsWithPath(_ graph: [Int: [Int]], start: Int, visited: inout Set<Int>, path: inout [Int]) {

    visited.insert(start)
    path.append(start)

    print(path)

    if let neighbors = graph[start] {

        for node in neighbors {

            if !visited.contains(node) {
                dfsWithPath(graph, start: node, visited: &visited, path: &path)
            }

        }

    }

    path.removeLast()

}

let graph3: [Int: [Int]] = [
    1: [2, 3],
    2: [4],
    3: [5],
    4: [],
    5: []
]

var visited3 = Set<Int>()

var path: [Int] = []

dfsWithPath(graph3, start: 1, visited: &visited3, path: &path)

This form helps beginners visualize the algorithm deeply because it shows each step of the journey through the graph. The path changes as the search dives into a branch and resets when the algorithm backtracks.

Program 5: DFS as a Swift Extension

For a clean and reusable design, this program adds DFS directly to Dictionary where the keys are integers. This makes the algorithm convenient to call on any graph.

import Foundation

extension Dictionary where Key == Int, Value == [Int] {

    func dfs(start: Int) {

        var visited = Set<Int>()
        dfsHelper(start, visited: &visited)

    }

    private func dfsHelper(_ node: Int, visited: inout Set<Int>) {

        visited.insert(node)
        print(node)

        if let neighbors = self[node] {

            for n in neighbors {

                if !visited.contains(n) {
                    dfsHelper(n, visited: &visited)
                }

            }

        }

    }

}

let graph4: [Int: [Int]] = [
    1: [2, 3],
    2: [4],
    3: [5],
    4: [],
    5: []
]

graph4.dfs(start: 1)

This version is perfect for those who want a neat and modern Swift style. Once added as an extension, DFS becomes a simple and readable method that can be reused anytime without rewriting the main algorithm.

Frequently Asked Questions (FAQ)

This section answers common questions beginners often ask when learning DFS in Swift.

Q1. Do I need a special data structure to use DFS?
You only need a graph or tree representation. It works well with adjacency lists, dictionaries, and custom node classes.

Q2. Is DFS faster than BFS?
Both have similar time complexity, but DFS goes deep first while BFS explores level by level. The right choice depends on the problem.

Q3. Can DFS detect cycles?
Yes, keeping a visited set helps you detect when a node appears again.

Q4. Does DFS always find the shortest path?
No, DFS is not designed for shortest-path tasks. For that, other algorithms like BFS or Dijkstra are better.

Q5. Can DFS be used on trees and graphs in Swift?
Absolutely. DFS works on any structure where you can follow connections from one node to another.

Conclusion

Depth-First Search is one of the most flexible and useful algorithms you can learn as a Swift beginner. It teaches you how to explore data structures deeply and gives you a solid foundation for solving more advanced problems. By practicing different versions of DFS—recursive, iterative, tree-based, and extension-based—you gain a stronger understanding of how the algorithm works behind the scenes. Keep experimenting with DFS, try it on your own data structures, and soon navigating graphs in Swift will feel natural and enjoyable.

Scroll to Top