Lua Program to Implement Breadth-First Search (BFS)

Lua Program to Implement Breadth-First Search (BFS)

Breadth-First Search, commonly known as BFS, is a fundamental algorithm used to explore graphs and trees. Unlike Depth-First Search, which dives deep into a branch before backtracking, BFS explores all neighbors of a node level by level. This approach makes BFS ideal for finding the shortest path in unweighted graphs, solving maze problems, and discovering nodes in network structures. For beginners, BFS is a great way to learn about queues, graph traversal, and systematic exploration.

Learn C Programming For Free on Windows

A beginner-friendly course that teaches real C programming using a Windows compiler. Learn arrays, pointers, functions, and file handling step by step with practical lessons.

Start Learning C Programming

Implementing BFS in Lua is straightforward thanks to its simple table structures and flexible loops. By learning BFS, you gain a powerful tool for analyzing networks, social graphs, or any connected structure. Understanding BFS also lays the groundwork for more advanced algorithms, such as Dijkstra’s shortest path or network flow algorithms. This article will guide you through multiple practical implementations of BFS, so you can see its versatility in action.

Program 1: BFS Using a Queue on a Simple Graph

This program demonstrates BFS using a queue to traverse a basic graph represented as an adjacency list.

-- BFS using a queue

local graph = {
    A = {"B", "C"},
    B = {"D", "E"},
    C = {"F"},
    D = {},
    E = {"F"},
    F = {}
}

local visited = {}
local queue = {"A"}

while #queue > 0 do

    local node = table.remove(queue, 1)

    if not visited[node] then

        print("Visited:", node)
        visited[node] = true

        for _, neighbor in ipairs(graph[node]) do
            table.insert(queue, neighbor)
        end

    end

end

In this example, BFS starts at node “A” and explores neighbors in the order they appear. The queue ensures that nodes are visited level by level, which is especially useful for finding the shortest path or performing systematic exploration. Beginners will find it easy to understand how BFS keeps track of visited nodes and handles order using a queue.

Program 2: BFS Using Recursion

Although BFS is usually iterative, it can also be implemented recursively using a queue. This approach helps beginners see how recursion can simulate iterative behavior.

-- Recursive BFS

local graph = {
    A = {"B", "C"},
    B = {"D", "E"},
    C = {"F"},
    D = {},
    E = {"F"},
    F = {}
}

local visited = {}

function bfsRecursive(queue)

    if #queue == 0 then return end

    local node = table.remove(queue, 1)

    if not visited[node] then

        print("Visited:", node)
        visited[node] = true

        for _, neighbor in ipairs(graph[node]) do
            table.insert(queue, neighbor)
        end

    end

    bfsRecursive(queue)

end

bfsRecursive({"A"})

This recursive BFS example demonstrates that recursion can work with queues to achieve the same level-by-level exploration. Beginners can see how recursion keeps track of the queue while still preserving BFS behavior.

Program 3: BFS on a Weighted Graph (Ignoring Weights)

BFS can also be applied to graphs where edges have weights, even though it ignores them. This is helpful for basic traversal before moving on to weighted shortest path algorithms.

-- BFS on a weighted graph (weights ignored)

local graph = {
    A = {B = 2, C = 3},
    B = {D = 4, E = 1},
    C = {F = 5},
    D = {},
    E = {F = 2},
    F = {}
}

local visited = {}
local queue = {"A"}

while #queue > 0 do

    local node = table.remove(queue, 1)

    if not visited[node] then

        print("Visited:", node)
        visited[node] = true

        for neighbor, _ in pairs(graph[node]) do
            table.insert(queue, neighbor)
        end

    end

end

This example shows that BFS can traverse any graph structure, whether or not edges carry weights. Beginners can see that BFS focuses on visiting nodes systematically, and weights can be incorporated later if needed.

Program 4: BFS for Connected Components

BFS can also be used to find connected components in an undirected graph. Each BFS traversal identifies one component.

-- BFS to find connected components

local graph = {
    A = {"B"},
    B = {"A"},
    C = {"D"},
    D = {"C"},
    E = {}
}

local visited = {}

function bfsComponents(startNode)

    local queue = {startNode}

    while #queue > 0 do

        local node = table.remove(queue, 1)

        if not visited[node] then

            visited[node] = true

            for _, neighbor in ipairs(graph[node] or {}) do
                table.insert(queue, neighbor)
            end

        end

    end

end

local count = 0

for node, _ in pairs(graph) do

    if not visited[node] then
        bfsComponents(node)
        count = count + 1
    end

end

print("Number of connected components:", count)

This example shows BFS applied beyond simple traversal. Beginners learn how to use BFS to analyze graph structure and count separate clusters of connected nodes.

Program 5: BFS with Numeric Node Labels (Including Negative Numbers)

BFS works perfectly with numeric nodes, including negative values, demonstrating its flexibility.

-- BFS with numeric node labels including negatives

local graph = {
    [-1] = {-2, 0},
    [-2] = {-3},
    [-3] = {},
    [0] = {1},
    [1] = {}
}

local visited = {}
local queue = {-1}

while #queue > 0 do

    local node = table.remove(queue, 1)

    if not visited[node] then

        print("Visited:", node)
        visited[node] = true

        for _, neighbor in ipairs(graph[node] or {}) do
            table.insert(queue, neighbor)
        end

    end

end

This example shows that BFS is not limited by node labels or types. Beginners see that the algorithm only requires a consistent method to track visited nodes.

Frequently Asked Questions (FAQ)

BFS often raises common questions for beginners:

Q1. What is the difference between BFS and DFS?
BFS explores nodes level by level, while DFS explores as deep as possible along a branch before backtracking.

Q2. Can BFS handle cycles?
Yes, by keeping track of visited nodes, BFS avoids revisiting and infinite loops.

Q3. When is BFS better than DFS?
BFS is ideal for finding shortest paths in unweighted graphs and exploring nodes systematically.

Q4. Can BFS be used on weighted graphs?
BFS ignores weights. For shortest paths with weights, algorithms like Dijkstra’s are used.

Q5. Is BFS suitable for trees?
Yes, BFS works naturally on trees, exploring all nodes level by level.

Conclusion

Breadth-First Search is a fundamental and versatile algorithm for exploring graphs and trees. Through iterative queues, recursion, weighted graphs, connected components, and numeric nodes, beginners can understand how BFS systematically visits nodes. Practicing these examples will strengthen your understanding of graph traversal, queues, and systematic exploration. BFS is a building block for many advanced algorithms, and mastering it opens doors to solving complex problems in networking, pathfinding, and data structures.

Scroll to Top