Iterative Deepening Search (IDS) or Iterative Deepening Depth First Search (IDDFS)
Palavras-chave:
Publicado em: 07/09/2025Iterative Deepening Search (IDS/IDDFS) Explained
Iterative Deepening Search (IDS), also known as Iterative Deepening Depth-First Search (IDDFS), is a graph search algorithm that combines the space efficiency of Depth-First Search (DFS) with the completeness of Breadth-First Search (BFS). This article provides a comprehensive guide to understanding and implementing IDS, including code examples and complexity analysis.
Fundamental Concepts / Prerequisites
To effectively understand IDS, you should have a basic grasp of the following:
- Graph Representation: Familiarity with representing graphs (e.g., adjacency lists or matrices).
- Depth-First Search (DFS): Knowledge of how DFS works. DFS explores as far as possible along each branch before backtracking.
- Breadth-First Search (BFS): Knowledge of how BFS works. BFS explores all the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level.
- Recursion: Understanding of recursive functions is crucial for implementing DFS, which forms the core of IDS.
Implementation in Python
This section demonstrates the implementation of Iterative Deepening Search in Python.
def iterative_deepening_search(graph, start, target):
"""
Performs Iterative Deepening Search to find the target node in a graph.
Args:
graph: A dictionary representing the graph, where keys are nodes
and values are lists of their neighbors.
start: The starting node.
target: The target node to find.
Returns:
A list of nodes representing the path from the start to the target,
or None if the target is not found.
"""
depth = 0
while True:
result = depth_limited_search(graph, start, target, depth)
if result:
return result
if result is False: # No solution within the current depth
return None
depth += 1
def depth_limited_search(graph, start, target, limit, path=None):
"""
Performs Depth-Limited Search to find the target node within a specified depth limit.
Args:
graph: A dictionary representing the graph.
start: The starting node.
target: The target node to find.
limit: The maximum depth to search.
path: The current path (list of nodes visited).
Returns:
A list of nodes representing the path from the start to the target,
False if the target is not found within the depth limit or
None if target is not reachable at all.
"""
if path is None:
path = [start]
if start == target:
return path
if limit == 0:
return False # Cutoff
for neighbor in graph[start]:
if neighbor not in path:
new_path = path + [neighbor]
result = depth_limited_search(graph, neighbor, target, limit - 1, new_path)
if result:
return result
return False # No solution found within the depth limit
# Example graph representation using an adjacency list
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': ['F'],
'F': []
}
# Example usage:
start_node = 'A'
target_node = 'F'
path = iterative_deepening_search(graph, start_node, target_node)
if path:
print(f"Path from {start_node} to {target_node}: {path}")
else:
print(f"No path found from {start_node} to {target_node}")
Code Explanation
The code defines two functions: iterative_deepening_search
and depth_limited_search
.
depth_limited_search(graph, start, target, limit, path)
performs a Depth-First Search with a specified depth limit. It recursively explores the graph from the start
node, up to the given limit
. If the target
node is found within the limit, it returns the path. If the limit is reached, it returns False
signifying a cutoff. It returns False
(cutoff) when the depth limit is reached and no solution is found along that path, and False
again if it explored the path completely and found no solution.
iterative_deepening_search(graph, start, target)
iteratively calls depth_limited_search
with increasing depth limits (starting from 0). It stops and returns the path if the depth_limited_search
finds the target
. It returns None
if all depths are explored and no solution is found. The depth limit is incremented in each iteration until either the target node is found or all possible depths are exhausted.
Complexity Analysis
Time Complexity: The time complexity of IDS is O(bd), where 'b' is the branching factor (maximum number of children of a node) and 'd' is the depth of the shallowest goal node. Although it may seem inefficient to repeatedly perform DFS, the nodes at the deepest level (level 'd') are expanded only once, the nodes at depth 'd-1' are expanded twice, and so on. Thus the total number of node expansions is: 1*bd + 2*bd-1 + 3*bd-2 + ... + d*b0 which is still O(bd).
Space Complexity: The space complexity of IDS is O(bd), where 'b' is the branching factor and 'd' is the depth of the shallowest goal node. This is because IDS uses DFS at each iteration, which requires space only for the nodes on the current path (depth 'd'). This is a significant advantage over BFS which needs to store all nodes at the current level in the queue.
Alternative Approaches
Breadth-First Search (BFS): BFS guarantees finding the shortest path to the goal. However, BFS has a space complexity of O(bd), which can be prohibitive for large graphs, as it needs to store all the nodes at each level in the queue. IDS avoids this issue by using only the memory proportional to the depth, rather than the number of nodes at the given depth.
Conclusion
Iterative Deepening Search offers a balanced approach to graph search, combining the space efficiency of DFS with the completeness and optimality (if all step costs are equal) of BFS. It's a useful algorithm when memory is a constraint, and the depth of the solution is unknown. The repeated DFS calls might seem inefficient, but the time complexity remains comparable to BFS, while greatly reducing memory usage.