Home DSA Bidirectional Search Algorithm — BFS from Both Ends

Bidirectional Search Algorithm — BFS from Both Ends

Where developers are forged. · Structured learning · Free forever.
📍 Part of: Searching → Topic 8 of 8
Learn bidirectional search — how running BFS from source and destination simultaneously reduces time complexity from O(b^d) to O(b^(d/2)).
⚙️ Intermediate — basic DSA knowledge assumed
In this tutorial, you'll learn:
  • Run BFS simultaneously from source and destination. When frontiers meet, the shortest path goes through the meeting node.
  • O(b^(d/2)) vs O(b^d) — exponential improvement. For b=10, d=10: standard 10^10 nodes, bidirectional 2×10^5. Real difference in real systems.
  • Termination requires care: when frontiers first touch, continue until all current-level nodes are processed. First meeting node may not give the globally shortest path.
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
⚡ Quick Answer
Standard BFS from source to destination explores O(b^d) nodes (b=branching factor, d=depth). Bidirectional search runs BFS from both ends simultaneously, meeting in the middle. Each side explores only O(b^(d/2)) nodes. Since b^(d/2) + b^(d/2) << b^d, the improvement is dramatic — like two people looking for each other in a city, each walking halfway, rather than one searching the whole city.

Google Maps finds the shortest route between any two points on Earth in milliseconds. Standard Dijkstra from source to destination on a graph with 100 million nodes would be far too slow. Bidirectional Dijkstra (bidirectional search with weights) is one of the key techniques that makes this practical — along with A* and contraction hierarchies.

The exponential improvement from O(b^d) to O(b^(d/2)) is real and dramatic. For a typical road network with branching factor b=4 and depth d=20, standard search explores 4^20 ≈ 10^12 nodes. Bidirectional explores 2×4^10 ≈ 2×10^6 nodes. A factor of 500,000 difference.

Why Bidirectional Search is Faster

Standard BFS explores all nodes up to depth d: O(b + b² + ... + b^d) ≈ O(b^d)

Bidirectional BFS: each direction explores to depth d/2: O(2 × b^(d/2)) ≈ O(b^(d/2))

For b=10, d=10: - Standard: 10^10 = 10 billion nodes - Bidirectional: 2 × 10^5 = 200,000 nodes

A reduction by factor ~50,000.

🔥
Key ConditionBidirectional search requires knowing the goal state in advance. It works for single-source single-destination shortest path but cannot be used for all-pairs shortest path or when the goal is unknown.

Implementation

bidirectional_bfs.py · PYTHON
1234567891011121314151617181920212223242526272829303132333435
from collections import deque

def bidirectional_bfs(graph: dict, start, end) -> int:
    """Returns shortest path length, -1 if not found."""
    if start == end: return 0
    # Forward and backward frontiers + visited sets
    front_visited = {start: 0}
    back_visited  = {end: 0}
    front_queue = deque([start])
    back_queue  = deque([end])

    def expand(queue, visited, other_visited):
        node = queue.popleft()
        for neighbour in graph.get(node, []):
            if neighbour not in visited:
                visited[neighbour] = visited[node] + 1
                queue.append(neighbour)
                if neighbour in other_visited:
                    return visited[neighbour] + other_visited[neighbour]
        return None

    while front_queue and back_queue:
        result = expand(front_queue, front_visited, back_visited)
        if result is not None: return result
        result = expand(back_queue, back_visited, front_visited)
        if result is not None: return result
    return -1

graph = {
    'A': ['B','C'], 'B': ['A','D','E'],
    'C': ['A','F'], 'D': ['B'],
    'E': ['B','F'], 'F': ['C','E','G'],
    'G': ['F']
}
print(bidirectional_bfs(graph, 'A', 'G'))  # 3
▶ Output
3

Applications

Google Maps / GPS: Route planning between two known locations — bidirectional Dijkstra instead of BFS for weighted graphs.

Word Ladder: Find shortest transformation sequence — bidirectional BFS from both start and end words.

Social networks: Shortest path between two users — bidirectional BFS from both users' friend lists.

Chess / game AI: Bidirectional iterative deepening for known goal states.

Complexity

Time: O(b^(d/2)) where b=branching factor, d=shortest path depth Space: O(b^(d/2)) for both frontiers

The meeting condition must be handled carefully — the first meeting point may not give the shortest path. The correct termination is when the sum of forward and backward distances through any meeting node is minimised.

🎯 Key Takeaways

  • Run BFS simultaneously from source and destination. When frontiers meet, the shortest path goes through the meeting node.
  • O(b^(d/2)) vs O(b^d) — exponential improvement. For b=10, d=10: standard 10^10 nodes, bidirectional 2×10^5. Real difference in real systems.
  • Termination requires care: when frontiers first touch, continue until all current-level nodes are processed. First meeting node may not give the globally shortest path.
  • Requires knowing the destination in advance. Cannot be used for single-source all-destinations — that requires standard BFS/Dijkstra.
  • Production usage: Google Maps/routing uses bidirectional Dijkstra + A* + contraction hierarchies. The 'meet in the middle' idea also applies to DP (knapsack meet-in-middle).

Interview Questions on This Topic

  • QWhy is bidirectional BFS O(b^(d/2)) instead of O(b^d)?
  • QIn what situations can you NOT use bidirectional search?
  • QHow does bidirectional Dijkstra differ from bidirectional BFS?
  • QWhat is the word ladder problem and how does bidirectional BFS solve it efficiently?

Frequently Asked Questions

Does bidirectional BFS always find the shortest path?

Yes, but the termination condition requires care. When the two frontiers first meet, you should continue until all nodes at the current frontier depth are processed, then return the minimum path found — the first meeting node might not give the globally shortest path.

🔥
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousExponential Search and Fibonacci Search
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged