From 8cbc3352d00cbfd54a181bb67a953a12e0ed01c0 Mon Sep 17 00:00:00 2001 From: ameralhomdy Date: Sun, 15 Nov 2020 21:23:33 -0700 Subject: [PATCH 1/2] MVP day 1 --- projects/graph/graph.py | 138 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 124 insertions(+), 14 deletions(-) diff --git a/projects/graph/graph.py b/projects/graph/graph.py index 59fecae4b..8cdecffa3 100644 --- a/projects/graph/graph.py +++ b/projects/graph/graph.py @@ -1,7 +1,8 @@ """ Simple graph implementation """ -from util import Stack, Queue # These may come in handy +# from util import Stack, Queue # These may come in handy +from collections import deque class Graph: @@ -9,46 +10,102 @@ class Graph: def __init__(self): self.vertices = {} + def __repr__(self): + return str(self.vertices) + def add_vertex(self, vertex_id): """ Add a vertex to the graph. """ - pass # TODO + if vertex_id in self.vertices: + print(f"WARNING: Graph already contains `{vertex_id}`") + return + self.vertices[vertex_id] = set() + + def remove_vertex(self, vertex_id): + """ + Removes a vertex from the graph, as well as its edges. + """ + if vertex_id not in self.vertices: + print(f"WARNING: Attempting to remove non-existing vertex `{vertex_id}") + return + self.vertices.pop(vertex_id) + for remaining_vertex in self.vertices: + self.vertices[remaining_vertex].discard(vertex_id) def add_edge(self, v1, v2): """ - Add a directed edge to the graph. + Add a directed edge from v1 to v2. + """ + if v1 not in self.vertices or v2 not in self.vertices: + print(f"WARNING: Attempting to add edge to non-existing nodes `{v1}` and `{v2}`") + return + self.vertices[v1].add(v2) + + def remove_edge(self, v1, v2): """ - pass # TODO + Remove a directed edge from v1 to v2. + """ + if v1 not in self.vertices or v2 not in self.vertices: + print("WARNING: Attempting to remove edges from non-existent vertex") + return + self.vertices[v1].discard(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 + visited = set() + queue = deque() + queue.append(starting_vertex) + while len(queue) > 0: + currNode = queue.popleft() + if currNode not in visited: + visited.add(currNode) + print(currNode) + # push all neighbors onto queue + for neighbor in self.vertices[currNode]: + queue.append(neighbor) def dft(self, starting_vertex): """ Print each vertex in depth-first order beginning from starting_vertex. """ - pass # TODO + visited = set() + stack = deque() + stack.append(starting_vertex) + while len(stack) > 0: + currNode = stack.pop() + if currNode not in visited: + visited.add(currNode) + print(currNode) + # push all neighbors onto stack + for neighbor in self.vertices[currNode]: + stack.append(neighbor) def dft_recursive(self, starting_vertex): """ Print each vertex in depth-first order beginning from starting_vertex. - This should be done using recursion. """ - pass # TODO + visited = set() + def recursive_helper(vertex, visited): + if vertex not in visited: + visited.add(vertex) + print(vertex) + for neighbor in self.vertices[vertex]: + recursive_helper(neighbor, visited) + + recursive_helper(starting_vertex, visited) def bfs(self, starting_vertex, destination_vertex): """ @@ -56,7 +113,22 @@ def bfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in breath-first order. """ - pass # TODO + visited = set() + queue = deque() + # Push the current path onto the stack, instead of just a single vertex + queue.append([starting_vertex]) + while len(queue) > 0: + currPath = queue.popleft() + currNode = currPath[-1] # current node is the last node in the path + if currNode == destination_vertex: + return currPath + if currNode not in visited: + visited.add(currNode) + # push all neighbors onto stack + for neighbor in self.vertices[currNode]: + newPath = list(currPath) + newPath.append(neighbor) + queue.append(newPath) def dfs(self, starting_vertex, destination_vertex): """ @@ -64,17 +136,49 @@ def dfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in depth-first order. """ - pass # TODO + visited = set() + stack = deque() + # Push the current path onto the stack, instead of just a single vertex + stack.append([starting_vertex]) + while len(stack) > 0: + currPath = stack.pop() + currNode = currPath[-1] # current node is the last node in the path + if currNode == destination_vertex: + return currPath + if currNode not in visited: + visited.add(currNode) + # push all neighbors onto stack + for neighbor in self.vertices[currNode]: + newPath = list(currPath) # make a copy of the current path + newPath.append(neighbor) + stack.append(newPath) def dfs_recursive(self, starting_vertex, destination_vertex): """ Return a list containing a path from starting_vertex to destination_vertex in depth-first order. - This should be done using recursion. """ - pass # TODO + def recursive_helper(curr_path, visited, goal_vertex): + curr_vertex = curr_path[-1] + # base case + if curr_vertex == goal_vertex: + return curr_path + visited.add(curr_vertex) + for neighbor in self.vertices[curr_vertex]: + if neighbor not in visited: + newPath = list(curr_path) + newPath.append(neighbor) + # recursive case: keep traversing the graph, visit neighbor next + res = recursive_helper(newPath, visited, goal_vertex) + if len(res) > 0: + return res + # another base case: if goal vertex not found + return [] + + visited = set() + return recursive_helper([starting_vertex], visited, destination_vertex) if __name__ == '__main__': graph = Graph() # Instantiate your graph @@ -118,6 +222,7 @@ def dfs_recursive(self, starting_vertex, destination_vertex): 1, 2, 4, 3, 7, 6, 5 1, 2, 4, 3, 7, 5, 6 ''' + print("BFT:") graph.bft(1) ''' @@ -127,13 +232,16 @@ def dfs_recursive(self, starting_vertex, destination_vertex): 1, 2, 4, 7, 6, 3, 5 1, 2, 4, 6, 3, 5, 7 ''' + print("DFT:") graph.dft(1) + print("DFT recursive:") graph.dft_recursive(1) ''' Valid BFS path: [1, 2, 4, 6] ''' + print("BFS: 1 to 6") print(graph.bfs(1, 6)) ''' @@ -141,5 +249,7 @@ def dfs_recursive(self, starting_vertex, destination_vertex): [1, 2, 4, 6] [1, 2, 4, 7, 6] ''' + print("DFS: 1 to 6") print(graph.dfs(1, 6)) - print(graph.dfs_recursive(1, 6)) + print("DFS recursive: 1 to 6") + print(graph.dfs_recursive(1, 6)) \ No newline at end of file From 3a22e6971473e0b3af9d25a8a6ffec4e87ef38f0 Mon Sep 17 00:00:00 2001 From: ameralhomdy Date: Tue, 17 Nov 2020 18:25:11 -0700 Subject: [PATCH 2/2] MVP day 2 --- projects/ancestor/ancestor.py | 50 ++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/projects/ancestor/ancestor.py b/projects/ancestor/ancestor.py index 3bd003098..8e6b2e491 100644 --- a/projects/ancestor/ancestor.py +++ b/projects/ancestor/ancestor.py @@ -1,3 +1,51 @@ def earliest_ancestor(ancestors, starting_node): - pass \ No newline at end of file + # set up our graph + graphy = {} + for tup in ancestors: + if tup[0] not in graphy: + graphy[tup[0]] = set() + graphy[tup[0]].add(tup[1]) + + path = [starting_node] + q = [path] + result = [] + + if get_parents(starting_node, graphy) == []: + return -1 + + while len(q) > 0: + new_path = q.pop(0) + vertex = new_path[-1] + parents = get_parents(vertex, graphy) + print("parents, vertex", parents, vertex) + + if parents == []: + result.append(new_path) + else: + for i in parents: + pathy = new_path + [i] + q.append(pathy) + + size = len(result[0]) + for i in result: + if len(i) > size: + size = len(i) + new_results = list(filter(lambda x: len(x) >= size, result)) + + # print("new results", new_results) + return min([i[-1] for i in new_results]) + + +def get_parents(node, graph): + parents = [] + for i in graph: + if node in graph[i]: + parents.append(i) + return parents + + +ancestors = [(1, 3), (2, 3), (3, 6), (5, 6), (5, 7), + (4, 5), (4, 8), (8, 9), (11, 8), (10, 1)] + +print(earliest_ancestor(ancestors, 6)) \ No newline at end of file