diff --git a/projects/graph/README.md b/projects/graph/README.md index e7c8489e7..1a8da8f98 100644 --- a/projects/graph/README.md +++ b/projects/graph/README.md @@ -2,7 +2,6 @@ This is a multi-stage project to implement a basic graph class and traversals. - ## Part 1: Graph Class In the file `graph.py`, implement a `Graph` class that supports the API in the example below. In particular, this means there should be a field `vertices` that @@ -65,9 +64,6 @@ Write a function within your Graph class that takes takes a starting node and a Write a function within your Graph class that takes takes a starting node and a destination node as an argument, then performs DFS. Your function should return a valid path (not necessarily the shortest) from the start node to the destination node. Note that there are multiple valid paths. - ## Part 7: Implement Depth-First Search using Recursion Write a function within your Graph class that takes takes a starting node and a destination node as an argument, then performs DFS using recursion. Your function should return a valid path (not necessarily the shortest) from the start node to the destination node. Note that there are multiple valid paths. - - diff --git a/projects/graph/graph.py b/projects/graph/graph.py index 59fecae4b..53dad51f7 100644 --- a/projects/graph/graph.py +++ b/projects/graph/graph.py @@ -13,42 +13,82 @@ def add_vertex(self, vertex_id): """ Add a vertex to the graph. """ - pass # TODO + self.vertices[vertex_id] = set() def add_edge(self, v1, v2): """ Add a directed edge to the graph. """ - pass # TODO + if v1 not in self.vertices or v2 not in self.vertices: + print('Error - invalid vertex') + return + + self.vertices[v1].add(v2) def get_neighbors(self, vertex_id): """ Get all neighbors (edges) of a vertex. """ - pass # TODO + return self.vertices[vertex_id] def bft(self, starting_vertex): """ Print each vertex in breadth-first order beginning from starting_vertex. """ - pass # TODO + queue = Queue() + visited = set() + + queue.enqueue(starting_vertex) + + while queue.size() > 0: + current_vert = queue.dequeue() + + if current_vert not in visited: + visited.add(current_vert) + + print(current_vert) + + for vert in self.vertices[current_vert]: + queue.enqueue(vert) def dft(self, starting_vertex): """ Print each vertex in depth-first order beginning from starting_vertex. """ - pass # TODO - - def dft_recursive(self, starting_vertex): + stack = Stack() + visited = set() + + stack.push(starting_vertex) + + while stack.size() > 0: + current_vert = stack.pop() + + if current_vert not in visited: + visited.add(current_vert) + + print(current_vert) + + for v in self.vertices[current_vert]: + stack.push(v) + + def dft_recursive(self, starting_vertex, visited=None): """ Print each vertex in depth-first order beginning from starting_vertex. This should be done using recursion. """ - pass # TODO + if visited == None: + visited = set() + + visited.add(starting_vertex) + print(starting_vertex) + + for n in self.get_neighbors(starting_vertex): + if n not in visited: + self.dft_recursive(n, visited) def bfs(self, starting_vertex, destination_vertex): """ @@ -56,7 +96,26 @@ def bfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in breath-first order. """ - pass # TODO + queue = Queue() + visited = set() + + queue.enqueue([starting_vertex]) + + while queue.size() > 0: + current_path = queue.dequeue() + current_vert = current_path[-1] + + if current_vert == destination_vertex: + return current_path + + if current_vert not in visited: + visited.add(current_vert) + + for vert in self.vertices[current_vert]: + new_path = list(current_path) + new_path.append(vert) + queue.enqueue(new_path) + def dfs(self, starting_vertex, destination_vertex): """ @@ -64,9 +123,27 @@ def dfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in depth-first order. """ - pass # TODO - - def dfs_recursive(self, starting_vertex, destination_vertex): + stack = Stack() + visited = set() + + stack.push([starting_vertex]) + + while stack.size() > 0: + current_path = stack.pop() + current_vert = current_path[-1] + + if current_vert == destination_vertex: + return current_path + + if current_vert not in visited: + visited.add(current_vert) + + for v in self.vertices[current_vert]: + new_path = list(current_path) + new_path.append(v) + stack.push(new_path) + + def dfs_recursive(self, starting_vertex, destination_vertex, path=None, visited=None): """ Return a list containing a path from starting_vertex to destination_vertex in @@ -74,7 +151,25 @@ def dfs_recursive(self, starting_vertex, destination_vertex): This should be done using recursion. """ - pass # TODO + if path == None: + path = [] + if visited == None: + visited = set() + + path.append(starting_vertex) + visited.add(starting_vertex) + + if starting_vertex == destination_vertex: + return path + + for v in self.get_neighbors(starting_vertex): + if v not in visited: + new_path = self.dfs_recursive(v, destination_vertex, path, visited) + if new_path is not None: + return new_path + else: + path.pop() + if __name__ == '__main__': graph = Graph() # Instantiate your graph @@ -142,4 +237,4 @@ def dfs_recursive(self, starting_vertex, destination_vertex): [1, 2, 4, 7, 6] ''' print(graph.dfs(1, 6)) - print(graph.dfs_recursive(1, 6)) + print(graph.dfs_recursive(1, 6)) \ No newline at end of file