From 54defd7b24bb585574564443b2ffe69a2d2ff925 Mon Sep 17 00:00:00 2001 From: Aadit Kamat Date: Thu, 12 Sep 2019 01:26:59 +0800 Subject: [PATCH] Switch to deque for DFS implementation Signed-off-by: Aadit Kamat --- contents/algorithms/graph.md | 99 +++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/contents/algorithms/graph.md b/contents/algorithms/graph.md index c9883360..61cea92a 100644 --- a/contents/algorithms/graph.md +++ b/contents/algorithms/graph.md @@ -32,35 +32,37 @@ In coding interviews, graphs are commonly represented as 2-D matrices where cell A simple template for doing depth-first searches on a matrix goes like this: ```py -def dfs(matrix, method): +from collections import deque + + +def dfs(matrix): + # check for an empty graph + if len(matrix) == 0: + return [] rows, cols = len(matrix), len(matrix[0]) visited = set() directions = ((0, 1), (0, -1), (1, 0), (-1, 0)) - # Depends upon the question: many grid questions have blocked cells. - # This implementation assumes 0s represent valid and 1s represent invalid - def is_valid(i, j): - return matrix[i][j] == 0 - - # Uses short circuiting to check whether current position is within the boundary - # and has not been visited before checking if it is valid + # Uses short circuiting to check whether current position is within the + # boundary and has not been visited before checking if it is valid def pass_all_conditions(i, j): - return i in range(rows) and j in range(cols) and (i, j) not in visited \ - and is_valid((i, j)) - + return i in range(rows) and j in range(cols) and (i, j) not in visited + def traverse(i, j): - if not pass_all_conditions(i, j): - return - visited.add((i, j)) - # Traverse neighbors - for direction in directions: - next_i, next_j = i + direction[0], j + direction[1] - - + stack = deque([(i, j)]) + while stack: + curr_i, curr_j = stack.pop() + if pass_all_conditions(curr_i, curr_j): + visited.add((curr_i, curr_j)) + # Traverse neighbors + for direction in directions: + next_i, next_j = curr_i + direction[0], curr_j + direction[1] + stack.append((next_i, next_j)) + for i in range(rows): for j in range(cols): - dfs(i, j) - + traverse(i, j) + ``` Another similar template for doing breadth first searches on the matrix goes like this: @@ -68,32 +70,35 @@ Another similar template for doing breadth first searches on the matrix goes lik ```py from collections import deque -def bfs(matrix, method): - def add_neighbours(queue, current_point): - visited.add(current_point) - for direction in directions: - new_x, new_y = current_point[0] + direction[0], current_point[1] + direction[1] - queue.append((new_x, new_y)) - - # Depends upon the question: many grid questions have blocked cells. - # This implementation assumes 0s represent valid and 1s represent invalid - def is_valid(i, j): - return matrix[i][j] == 0 - - # Uses short circuiting to check whether current position is within the boundary - # and has not been visited before checking if it is valid - def pass_all_conditions(current_point): - return i in range(rows) and j in range(cols) and current_point not in visited \ - and is_valid(current_point) - - # Handle disjointed graphs - for x in range(rows): - for y in range(cols): - queue = deque([(i, j)]) - while store: - current_point = queue.popleft() - if pass_all_conditions(current_point): - add_neighbours(store, current_point) + +def bfs(matrix): + # check for an empty graph + if len(matrix) == 0: + return [] + rows, cols = len(matrix), len(matrix[0]) + visited = set() + directions = ((0, 1), (0, -1), (1, 0), (-1, 0)) + + # Uses short circuiting to check whether current position is within the + # boundary and has not been visited before checking if it is valid + def pass_all_conditions(i, j): + return i in range(rows) and j in range(cols) and (i, j) not in visited + + def traverse(i, j): + queue = deque([(i, j)]) + while queue: + curr_i, curr_j = queue.pop() + if pass_all_conditions(curr_i, curr_j): + visited.add((curr_i, curr_j)) + # Traverse neighbors + for direction in directions: + next_i, next_j = curr_i + direction[0], curr_j + direction[1] + queue.append((next_i, next_j)) + + for i in range(rows): + for j in range(cols): + traverse(i, j) + ``` > NOTE: While DFS is implemented using recursion in this sample, it could also be implemented iteratively similar to BFS. The key difference between the algorithms lies in the underlying data structure (BFS uses a queue while DFS uses a stack). The `deque` class in Python can function as both a stack and a queue