From 056a34fd543ed0cde3c7abbdbf0ba6d76769e0cc Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 11 Nov 2020 18:10:29 -0600 Subject: [PATCH 1/4] initial commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bdd6033c0..823ef6804 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Graphs - +# initial commit ## Objectives * [Graph Intro](objectives/graph-intro) From ab88c2b9b59ad20b188155284ff648a16e2e9d8d Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 11 Nov 2020 20:22:18 -0600 Subject: [PATCH 2/4] completed graph --- README.md | 2 +- projects/graph/graph.py | 104 +++++++++++++++++++++++++++++++++++----- 2 files changed, 93 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 823ef6804..3834632aa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Graphs -# initial commit +# initial commit [ https://github.com/LambdaSchool/Graphs/pull/745 ] ## Objectives * [Graph Intro](objectives/graph-intro) diff --git a/projects/graph/graph.py b/projects/graph/graph.py index 59fecae4b..814712ec0 100644 --- a/projects/graph/graph.py +++ b/projects/graph/graph.py @@ -13,42 +13,71 @@ 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 + 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 + visited = [] + queue = Queue() + queue.enqueue(starting_vertex) + + while queue.size() > 0: + current_node = queue.dequeue() + if current_node not in visited: + visited.append(current_node) + print(current_node) + for neighbor in self.get_neighbors(current_node): + queue.enqueue(neighbor) + def dft(self, starting_vertex): """ Print each vertex in depth-first order beginning from starting_vertex. """ - pass # TODO + visited = [] + stack = Stack() + stack.push(starting_vertex) + + while stack.size() > 0: + current_node = stack.pop() + if current_node not in visited: + visited.append(current_node) + print(current_node) + for neighbor in self.get_neighbors(current_node): + stack.push(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() + return self.dft_recursive_helper(starting_vertex, visited) + + def dft_recursive_helper(self, starting_vertex, visited): + visited.add(starting_vertex) + print(starting_vertex) + for neighbor in self.get_neighbors(starting_vertex): + if neighbor not in visited: + self.dft_recursive_helper(neighbor, visited) def bfs(self, starting_vertex, destination_vertex): """ @@ -56,7 +85,24 @@ def bfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in breath-first order. """ - pass # TODO + visited = set() + queue = Queue() + queue.enqueue([starting_vertex]) + + while queue.size() > 0: + current_path = queue.dequeue() + current_node = current_path[-1] + + if current_node == destination_vertex: + return current_path + + if current_node not in visited: + visited.add(current_node) + for neighbor in self.get_neighbors(current_node): + new_path = list(current_path) + new_path.append(neighbor) + queue.enqueue(new_path) + def dfs(self, starting_vertex, destination_vertex): """ @@ -64,17 +110,51 @@ def dfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in depth-first order. """ - pass # TODO + visited = set() + stack = Stack() + stack.push([starting_vertex]) + + while stack.size() > 0: + current_path = stack.pop() + current_node = current_path[-1] + + if current_node == destination_vertex: + return current_path + + if current_node not in visited: + visited.add(current_node) + for neighbor in self.get_neighbors(current_node): + new_path = list(current_path) + new_path.append(neighbor) + stack.push(new_path) 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 + visited = set() + return self.dfs_recursive_helper([starting_vertex], destination_vertex, visited) + + def dfs_recursive_helper(self, current_path, destination_vertex, visited): + current_vertex = current_path[-1] + + if current_vertex == destination_vertex: + return current_path + + visited.add(current_vertex) + + for neighbor in self.get_neighbors(current_vertex): + if neighbor not in visited: + new_path = list(current_path) + new_path.append(neighbor) + result = self.dfs_recursive_helper(new_path, destination_vertex, visited) + if len(result) > 0: + return result + + return [] if __name__ == '__main__': graph = Graph() # Instantiate your graph @@ -142,4 +222,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 From 6496f85c9290935436d53605ccce910453707a16 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sun, 15 Nov 2020 20:16:28 -0600 Subject: [PATCH 3/4] ancestor.py is completed, passed test. --- .vscode/settings.json | 5 +++++ projects/ancestor/ancestor.py | 36 ++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..ed86cb2b5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "deque" + ] +} \ No newline at end of file diff --git a/projects/ancestor/ancestor.py b/projects/ancestor/ancestor.py index 3bd003098..7065898e3 100644 --- a/projects/ancestor/ancestor.py +++ b/projects/ancestor/ancestor.py @@ -1,3 +1,37 @@ +from collections import deque, defaultdict def earliest_ancestor(ancestors, starting_node): - pass \ No newline at end of file + #child pair with no parent + graph = create_graph(ancestors) + stack = deque() + stack.append((starting_node, 0)) # distance from node + visited = set() + earliestAncestor = (starting_node, 0) + + while len(stack) > 0: + current = stack.pop() + current_node, distance = current[0], current[1] + visited.add(current) + + if current_node not in graph: + if distance > earliestAncestor[1]: + earliestAncestor = current + elif distance == earliestAncestor[1] and current_node < earliestAncestor[0]: + earliestAncestor = current + else: + for ancestor in graph[current_node]: + if ancestor not in visited: + stack.append((ancestor, distance + 1)) + + return earliestAncestor[0] if earliestAncestor[0] != starting_node else -1 + + +def create_graph(edges): + # every added dict should a deafult value set() + graph = defaultdict(set) + + for edge in edges: + ancestor, child = edge[0], edge[1] + graph[child].add(ancestor) + + return graph \ No newline at end of file From fd713b66af899b65739e6392619ea7a249d04b87 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 17 Nov 2020 23:46:13 -0600 Subject: [PATCH 4/4] social.py complete --- projects/social/social.py | 52 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/projects/social/social.py b/projects/social/social.py index 8609d8800..eaa3571b7 100644 --- a/projects/social/social.py +++ b/projects/social/social.py @@ -1,3 +1,6 @@ +import random, math +from collections import deque + class User: def __init__(self, name): self.name = name @@ -5,8 +8,8 @@ def __init__(self, name): class SocialGraph: def __init__(self): self.last_id = 0 - self.users = {} - self.friendships = {} + self.users = {} + self.friendships = {} def add_friendship(self, user_id, friend_id): """ @@ -24,7 +27,7 @@ def add_user(self, name): """ Create a new user with a sequential integer ID """ - self.last_id += 1 # automatically increment the ID to assign the new user + self.last_id += 1 #increment the ID to assign the new user self.users[self.last_id] = User(name) self.friendships[self.last_id] = set() @@ -32,39 +35,52 @@ def populate_graph(self, num_users, avg_friendships): """ Takes a number of users and an average number of friendships as arguments - Creates that number of users and a randomly distributed friendships between those users. - The number of users must be greater than the average number of friendships. """ - # Reset graph self.last_id = 0 self.users = {} self.friendships = {} - # !!!! IMPLEMENT ME - # Add users + for i in range(num_users): + self.add_user(f"User {i}") # Create friendships + possible_friendships = [] + for user_id in self.users: + for friend_id in range(user_id + 1, self.last_id+ 1): + possible_friendships.append((user_id, friend_id)) + + random.shuffle(possible_friendships) + + for i in range(math.floor(num_users * avg_friendships / 2)): + friendship = possible_friendships[i] + self.add_friendship(friendship[0], friendship[1]) def get_all_social_paths(self, user_id): - """ - Takes a user's user_id as an argument + # dict mapping + visited = {} + queue = deque() + queue.append([user_id]) - Returns a dictionary containing every user in that user's - extended network with the shortest friendship path between them. + while len(queue) > 0: + current_path = queue.popleft() + current_node = current_path[-1] + visited[current_node] = current_path + + for friend in self.friendships[current_node]: + if friend not in visited: + new_path = current_path.copy() + new_path.append(friend) + queue.append(new_path) - The key is the friend's ID and the value is the path. - """ - visited = {} # Note that this is a dictionary, not a set - # !!!! IMPLEMENT ME return visited if __name__ == '__main__': sg = SocialGraph() sg.populate_graph(10, 2) - print(sg.friendships) + print(f"friendships: {sg.friendships}") connections = sg.get_all_social_paths(1) - print(connections) + print(f"connections: {connections}") \ No newline at end of file