Bidirectional search is an advanced graph search algorithm that runs two simultaneous searches:
Forward Search: Starts from the initial node.
Backward Search: Starts from the goal node.
The search stops when both searches meet in the middle.
Implementation Strategy
To implement bidirectional search:
Use two queues for BFS traversal from the start and goal nodes.
Maintain two visited sets to track explored nodes.
Stop when the search frontiers meet.
Implementation of Bidirectional Search
Graph Representation (Adjacency List)
import java.util.*;
class Graph {
private final Map<Integer, List<Integer>> adjList;
public Graph() {
this.adjList = new HashMap<>();
}
// Add edge in an undirected graph
public void addEdge(int source, int destination) {
adjList.putIfAbsent(source, new ArrayList<>());
adjList.putIfAbsent(destination, new ArrayList<>());
adjList.get(source).add(destination);
adjList.get(destination).add(source);
}
// Returns the adjacency list
public List<Integer> getNeighbors(int node) {
return adjList.getOrDefault(node, new ArrayList<>());
}
// Print the graph
public void printGraph() {
for (var entry : adjList.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
Bidirectional Search Algorithm
class BidirectionalSearch {
private final Graph graph;
public BidirectionalSearch(Graph graph) {
this.graph = graph;
}
public boolean search(int start, int goal) {
if (start == goal) {
System.out.println("Start is the same as goal.");
return true;
}
// Queues for BFS from both directions
Queue<Integer> forwardQueue = new LinkedList<>();
Queue<Integer> backwardQueue = new LinkedList<>();
// Visited sets
Set<Integer> forwardVisited = new HashSet<>();
Set<Integer> backwardVisited = new HashSet<>();
// Initialize queues and visited sets
forwardQueue.add(start);
forwardVisited.add(start);
backwardQueue.add(goal);
backwardVisited.add(goal);
while (!forwardQueue.isEmpty() && !backwardQueue.isEmpty()) {
// Expand one level from start
if (bfsStep(forwardQueue, forwardVisited, backwardVisited)) {
System.out.println("Path found!");
return true;
}
// Expand one level from goal
if (bfsStep(backwardQueue, backwardVisited, forwardVisited)) {
System.out.println("Path found!");
return true;
}
}
System.out.println("No path found.");
return false;
}
private boolean bfsStep(Queue<Integer> queue, Set<Integer> visited, Set<Integer> oppositeVisited) {
if (!queue.isEmpty()) {
int node = queue.poll();
for (int neighbor : graph.getNeighbors(node)) {
if (oppositeVisited.contains(neighbor)) {
return true; // The two searches meet
}
if (!visited.contains(neighbor)) {
visited.add(neighbor);
queue.add(neighbor);
}
}
}
return false;
}
}