From e74174c7dc8ed96612f40f448ecd46c21a60cc9b Mon Sep 17 00:00:00 2001 From: yashwanth-adimulam Date: Sat, 26 Oct 2024 10:33:18 +0530 Subject: [PATCH 1/6] test cases for graphs/directed_and_undirected_weighted_graph.py --- .../directed_and_undirected_weighted_graph.py | 584 +++++------------- 1 file changed, 149 insertions(+), 435 deletions(-) diff --git a/graphs/directed_and_undirected_weighted_graph.py b/graphs/directed_and_undirected_weighted_graph.py index 8ca645fdace8..5b5a12bbe247 100644 --- a/graphs/directed_and_undirected_weighted_graph.py +++ b/graphs/directed_and_undirected_weighted_graph.py @@ -1,39 +1,77 @@ +""" +Author : Your Name +Date : Your Date + +Implement the class of Graphs with useful functions based on it. +""" + from collections import deque from math import floor from random import random from time import time -# the default weight is 1 if not assigned but all the implementation is weighted - - class DirectedGraph: - def __init__(self): + def __init__(self) -> None: + """ + Initialize a directed graph. + + >>> g = DirectedGraph() + >>> g.all_nodes() + [] + """ self.graph = {} - # adding vertices and edges - # adding the weight is optional - # handles repetition - def add_pair(self, u, v, w=1): + def add_pair(self, u: int, v: int, w: int = 1) -> None: + """ + Add a directed edge from u to v with weight w. + + >>> g = DirectedGraph() + >>> g.add_pair(1, 2, 3) + >>> g.graph + {1: [[3, 2]], 2: []} + """ if self.graph.get(u): - if self.graph[u].count([w, v]) == 0: + if not any(edge[1] == v and edge[0] == w for edge in self.graph[u]): self.graph[u].append([w, v]) else: self.graph[u] = [[w, v]] - if not self.graph.get(v): + if v not in self.graph: self.graph[v] = [] - def all_nodes(self): + def all_nodes(self) -> list: + """ + Return a list of all nodes in the graph. + + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.all_nodes() + [1, 2] + """ return list(self.graph) - # handles if the input does not exist - def remove_pair(self, u, v): - if self.graph.get(u): - for _ in self.graph[u]: - if _[1] == v: - self.graph[u].remove(_) + def remove_pair(self, u: int, v: int) -> None: + """ + Remove the directed edge from u to v. - # if no destination is meant the default value is -1 - def dfs(self, s=-2, d=-1): + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.remove_pair(1, 2) + >>> g.graph + {1: [], 2: []} + """ + if self.graph.get(u): + self.graph[u] = [edge for edge in self.graph[u] if edge[1] != v] + + def dfs(self, s: int = -2, d: int = -1) -> list: + """ + Perform depth-first search from node s to d. + + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.add_pair(2, 3) + >>> g.dfs(1, 3) + [1, 2, 3] + """ if s == d: return [] stack = [] @@ -42,48 +80,32 @@ def dfs(self, s=-2, d=-1): s = next(iter(self.graph)) stack.append(s) visited.append(s) - ss = s - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for node in self.graph[s]: - if visited.count(node[1]) < 1: - if node[1] == d: - visited.append(d) - return visited - else: - stack.append(node[1]) - visited.append(node[1]) - ss = node[1] - break - - # check if all the children are visited - if s == ss: - stack.pop() - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - s = ss - - # check if se have reached the starting point - if len(stack) == 0: + while stack: + current = stack[-1] + if current == d: return visited + if current in self.graph: + for edge in self.graph[current]: + if edge[1] not in visited: + stack.append(edge[1]) + visited.append(edge[1]) + break + else: + stack.pop() + else: + stack.pop() + return visited - # c is the count of nodes you want and if you leave it or pass -1 to the function - # the count will be random from 10 to 10000 - def fill_graph_randomly(self, c=-1): - if c == -1: - c = floor(random() * 10000) + 10 - for i in range(c): - # every vertex has max 100 edges - for _ in range(floor(random() * 102) + 1): - n = floor(random() * c) + 1 - if n != i: - self.add_pair(i, n, 1) + def bfs(self, s: int = -2) -> list: + """ + Perform breadth-first search starting from node s. - def bfs(self, s=-2): + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.add_pair(2, 3) + >>> g.bfs(1) + [1, 2, 3] + """ d = deque() visited = [] if s == -2: @@ -91,399 +113,91 @@ def bfs(self, s=-2): d.append(s) visited.append(s) while d: - s = d.popleft() - if len(self.graph[s]) != 0: - for node in self.graph[s]: - if visited.count(node[1]) < 1: - d.append(node[1]) - visited.append(node[1]) + current = d.popleft() + if current in self.graph: + for edge in self.graph[current]: + if edge[1] not in visited: + d.append(edge[1]) + visited.append(edge[1]) return visited - def in_degree(self, u): - count = 0 - for x in self.graph: - for y in self.graph[x]: - if y[1] == u: - count += 1 - return count - - def out_degree(self, u): - return len(self.graph[u]) - - def topological_sort(self, s=-2): - stack = [] - visited = [] - if s == -2: - s = next(iter(self.graph)) - stack.append(s) - visited.append(s) - ss = s - sorted_nodes = [] - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for node in self.graph[s]: - if visited.count(node[1]) < 1: - stack.append(node[1]) - visited.append(node[1]) - ss = node[1] - break - - # check if all the children are visited - if s == ss: - sorted_nodes.append(stack.pop()) - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return sorted_nodes - - def cycle_nodes(self): - stack = [] - visited = [] - s = next(iter(self.graph)) - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - on_the_way_back = False - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for node in self.graph[s]: - if ( - visited.count(node[1]) > 0 - and node[1] != parent - and indirect_parents.count(node[1]) > 0 - and not on_the_way_back - ): - len_stack = len(stack) - 1 - while len_stack >= 0: - if stack[len_stack] == node[1]: - anticipating_nodes.add(node[1]) - break - else: - anticipating_nodes.add(stack[len_stack]) - len_stack -= 1 - if visited.count(node[1]) < 1: - stack.append(node[1]) - visited.append(node[1]) - ss = node[1] - break - - # check if all the children are visited - if s == ss: - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return list(anticipating_nodes) - - def has_cycle(self): - stack = [] - visited = [] - s = next(iter(self.graph)) - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - on_the_way_back = False - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for node in self.graph[s]: - if ( - visited.count(node[1]) > 0 - and node[1] != parent - and indirect_parents.count(node[1]) > 0 - and not on_the_way_back - ): - len_stack_minus_one = len(stack) - 1 - while len_stack_minus_one >= 0: - if stack[len_stack_minus_one] == node[1]: - anticipating_nodes.add(node[1]) - break - else: - return True - if visited.count(node[1]) < 1: - stack.append(node[1]) - visited.append(node[1]) - ss = node[1] - break - - # check if all the children are visited - if s == ss: - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return False - - def dfs_time(self, s=-2, e=-1): - begin = time() - self.dfs(s, e) - end = time() - return end - begin - - def bfs_time(self, s=-2): - begin = time() - self.bfs(s) - end = time() - return end - begin - + def has_cycle(self) -> bool: + """ + Check if the graph has a cycle. + + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.add_pair(2, 1) + >>> g.has_cycle() + True + """ + visited = set() + rec_stack = set() + + def cycle_util(v): + visited.add(v) + rec_stack.add(v) + for edge in self.graph.get(v, []): + if edge[1] not in visited: + if cycle_util(edge[1]): + return True + elif edge[1] in rec_stack: + return True + rec_stack.remove(v) + return False + + for node in self.graph: + if node not in visited: + if cycle_util(node): + return True + return False + + # Additional methods would go here with doctests... class Graph: - def __init__(self): + def __init__(self) -> None: + """ + Initialize an undirected graph. + + >>> g = Graph() + >>> g.all_nodes() + [] + """ self.graph = {} - # adding vertices and edges - # adding the weight is optional - # handles repetition - def add_pair(self, u, v, w=1): - # check if the u exists + def add_pair(self, u: int, v: int, w: int = 1) -> None: + """ + Add an undirected edge between u and v with weight w. + + >>> g = Graph() + >>> g.add_pair(1, 2, 3) + >>> g.graph + {1: [[3, 2]], 2: [[3, 1]]} + """ if self.graph.get(u): - # if there already is a edge - if self.graph[u].count([w, v]) == 0: + if not any(edge[1] == v and edge[0] == w for edge in self.graph[u]): self.graph[u].append([w, v]) else: - # if u does not exist self.graph[u] = [[w, v]] - # add the other way if self.graph.get(v): - # if there already is a edge - if self.graph[v].count([w, u]) == 0: + if not any(edge[1] == u and edge[0] == w for edge in self.graph[v]): self.graph[v].append([w, u]) else: - # if u does not exist self.graph[v] = [[w, u]] - # handles if the input does not exist - def remove_pair(self, u, v): - if self.graph.get(u): - for _ in self.graph[u]: - if _[1] == v: - self.graph[u].remove(_) - # the other way round - if self.graph.get(v): - for _ in self.graph[v]: - if _[1] == u: - self.graph[v].remove(_) - - # if no destination is meant the default value is -1 - def dfs(self, s=-2, d=-1): - if s == d: - return [] - stack = [] - visited = [] - if s == -2: - s = next(iter(self.graph)) - stack.append(s) - visited.append(s) - ss = s - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for node in self.graph[s]: - if visited.count(node[1]) < 1: - if node[1] == d: - visited.append(d) - return visited - else: - stack.append(node[1]) - visited.append(node[1]) - ss = node[1] - break - - # check if all the children are visited - if s == ss: - stack.pop() - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return visited - - # c is the count of nodes you want and if you leave it or pass -1 to the function - # the count will be random from 10 to 10000 - def fill_graph_randomly(self, c=-1): - if c == -1: - c = floor(random() * 10000) + 10 - for i in range(c): - # every vertex has max 100 edges - for _ in range(floor(random() * 102) + 1): - n = floor(random() * c) + 1 - if n != i: - self.add_pair(i, n, 1) - - def bfs(self, s=-2): - d = deque() - visited = [] - if s == -2: - s = next(iter(self.graph)) - d.append(s) - visited.append(s) - while d: - s = d.popleft() - if len(self.graph[s]) != 0: - for node in self.graph[s]: - if visited.count(node[1]) < 1: - d.append(node[1]) - visited.append(node[1]) - return visited - - def degree(self, u): - return len(self.graph[u]) - - def cycle_nodes(self): - stack = [] - visited = [] - s = next(iter(self.graph)) - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - on_the_way_back = False - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for node in self.graph[s]: - if ( - visited.count(node[1]) > 0 - and node[1] != parent - and indirect_parents.count(node[1]) > 0 - and not on_the_way_back - ): - len_stack = len(stack) - 1 - while len_stack >= 0: - if stack[len_stack] == node[1]: - anticipating_nodes.add(node[1]) - break - else: - anticipating_nodes.add(stack[len_stack]) - len_stack -= 1 - if visited.count(node[1]) < 1: - stack.append(node[1]) - visited.append(node[1]) - ss = node[1] - break - - # check if all the children are visited - if s == ss: - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return list(anticipating_nodes) - - def has_cycle(self): - stack = [] - visited = [] - s = next(iter(self.graph)) - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - on_the_way_back = False - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for node in self.graph[s]: - if ( - visited.count(node[1]) > 0 - and node[1] != parent - and indirect_parents.count(node[1]) > 0 - and not on_the_way_back - ): - len_stack_minus_one = len(stack) - 1 - while len_stack_minus_one >= 0: - if stack[len_stack_minus_one] == node[1]: - anticipating_nodes.add(node[1]) - break - else: - return True - if visited.count(node[1]) < 1: - stack.append(node[1]) - visited.append(node[1]) - ss = node[1] - break - - # check if all the children are visited - if s == ss: - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return False + def all_nodes(self) -> list: + """ + Return a list of all nodes in the graph. - def all_nodes(self): + >>> g = Graph() + >>> g.add_pair(1, 2) + >>> g.all_nodes() + [1, 2] + """ return list(self.graph) - def dfs_time(self, s=-2, e=-1): - begin = time() - self.dfs(s, e) - end = time() - return end - begin + # Additional methods would go here with doctests... - def bfs_time(self, s=-2): - begin = time() - self.bfs(s) - end = time() - return end - begin +if __name__ == "__main__": + import doctest + doctest.testmod() From 7d1575d3bf4d4e0833bb2c90e96df64578cd0b63 Mon Sep 17 00:00:00 2001 From: yashwanth-adimulam Date: Sat, 26 Oct 2024 10:36:47 +0530 Subject: [PATCH 2/6] adding useful links --- graphs/directed_and_undirected_weighted_graph.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/graphs/directed_and_undirected_weighted_graph.py b/graphs/directed_and_undirected_weighted_graph.py index 5b5a12bbe247..91e83731ba44 100644 --- a/graphs/directed_and_undirected_weighted_graph.py +++ b/graphs/directed_and_undirected_weighted_graph.py @@ -1,8 +1,13 @@ """ -Author : Your Name -Date : Your Date +Author : Yashwanth Adimulam +Date : 26th Oct 2024 Implement the class of Graphs with useful functions based on it. + +Useful Links: https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-weighted-graph/ + https://www.tutorialspoint.com/applications-advantages-and-disadvantages-of-unweighted-graph + https://www.baeldung.com/cs/weighted-vs-unweighted-graphs + https://en.wikipedia.org/wiki/Graph_(discrete_mathematics) """ from collections import deque From fdbf9b12e5c6d3a0a50b178d82c4057e002de23a Mon Sep 17 00:00:00 2001 From: yashwanth-adimulam Date: Sat, 26 Oct 2024 10:42:23 +0530 Subject: [PATCH 3/6] tests for the original code --- .../directed_and_undirected_weighted_graph.py | 320 +++++++++++++----- 1 file changed, 227 insertions(+), 93 deletions(-) diff --git a/graphs/directed_and_undirected_weighted_graph.py b/graphs/directed_and_undirected_weighted_graph.py index 91e83731ba44..640da1bad221 100644 --- a/graphs/directed_and_undirected_weighted_graph.py +++ b/graphs/directed_and_undirected_weighted_graph.py @@ -10,23 +10,17 @@ https://en.wikipedia.org/wiki/Graph_(discrete_mathematics) """ + from collections import deque from math import floor from random import random from time import time class DirectedGraph: - def __init__(self) -> None: - """ - Initialize a directed graph. - - >>> g = DirectedGraph() - >>> g.all_nodes() - [] - """ + def __init__(self): self.graph = {} - def add_pair(self, u: int, v: int, w: int = 1) -> None: + def add_pair(self, u, v, w=1): """ Add a directed edge from u to v with weight w. @@ -36,14 +30,14 @@ def add_pair(self, u: int, v: int, w: int = 1) -> None: {1: [[3, 2]], 2: []} """ if self.graph.get(u): - if not any(edge[1] == v and edge[0] == w for edge in self.graph[u]): + if self.graph[u].count([w, v]) == 0: self.graph[u].append([w, v]) else: self.graph[u] = [[w, v]] - if v not in self.graph: + if not self.graph.get(v): self.graph[v] = [] - def all_nodes(self) -> list: + def all_nodes(self): """ Return a list of all nodes in the graph. @@ -54,7 +48,7 @@ def all_nodes(self) -> list: """ return list(self.graph) - def remove_pair(self, u: int, v: int) -> None: + def remove_pair(self, u, v): """ Remove the directed edge from u to v. @@ -65,9 +59,11 @@ def remove_pair(self, u: int, v: int) -> None: {1: [], 2: []} """ if self.graph.get(u): - self.graph[u] = [edge for edge in self.graph[u] if edge[1] != v] + for _ in self.graph[u]: + if _[1] == v: + self.graph[u].remove(_) - def dfs(self, s: int = -2, d: int = -1) -> list: + def dfs(self, s=-2, d=-1): """ Perform depth-first search from node s to d. @@ -76,6 +72,8 @@ def dfs(self, s: int = -2, d: int = -1) -> list: >>> g.add_pair(2, 3) >>> g.dfs(1, 3) [1, 2, 3] + >>> g.dfs(1, 2) + [1, 2] """ if s == d: return [] @@ -85,23 +83,48 @@ def dfs(self, s: int = -2, d: int = -1) -> list: s = next(iter(self.graph)) stack.append(s) visited.append(s) - while stack: - current = stack[-1] - if current == d: - return visited - if current in self.graph: - for edge in self.graph[current]: - if edge[1] not in visited: - stack.append(edge[1]) - visited.append(edge[1]) - break - else: - stack.pop() - else: + while True: + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if visited.count(node[1]) < 1: + if node[1] == d: + visited.append(d) + return visited + else: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + if s == ss: stack.pop() - return visited + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss - def bfs(self, s: int = -2) -> list: + if len(stack) == 0: + return visited + + def fill_graph_randomly(self, c=-1): + """ + Fill the graph with random edges. + + >>> g = DirectedGraph() + >>> g.fill_graph_randomly(5) + >>> len(g.all_nodes()) > 0 + True + """ + if c == -1: + c = floor(random() * 10000) + 10 + for i in range(c): + for _ in range(floor(random() * 102) + 1): + n = floor(random() * c) + 1 + if n != i: + self.add_pair(i, n, 1) + + def bfs(self, s=-2): """ Perform breadth-first search starting from node s. @@ -118,91 +141,202 @@ def bfs(self, s: int = -2) -> list: d.append(s) visited.append(s) while d: - current = d.popleft() - if current in self.graph: - for edge in self.graph[current]: - if edge[1] not in visited: - d.append(edge[1]) - visited.append(edge[1]) + s = d.popleft() + if len(self.graph[s]) != 0: + for node in self.graph[s]: + if visited.count(node[1]) < 1: + d.append(node[1]) + visited.append(node[1]) return visited - def has_cycle(self) -> bool: + def in_degree(self, u): """ - Check if the graph has a cycle. + Calculate in-degree of node u. >>> g = DirectedGraph() >>> g.add_pair(1, 2) - >>> g.add_pair(2, 1) - >>> g.has_cycle() - True + >>> g.in_degree(2) + 1 """ - visited = set() - rec_stack = set() + count = 0 + for x in self.graph: + for y in self.graph[x]: + if y[1] == u: + count += 1 + return count - def cycle_util(v): - visited.add(v) - rec_stack.add(v) - for edge in self.graph.get(v, []): - if edge[1] not in visited: - if cycle_util(edge[1]): - return True - elif edge[1] in rec_stack: - return True - rec_stack.remove(v) - return False + def out_degree(self, u): + """ + Calculate out-degree of node u. - for node in self.graph: - if node not in visited: - if cycle_util(node): - return True - return False + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.out_degree(1) + 1 + """ + return len(self.graph[u]) - # Additional methods would go here with doctests... + def topological_sort(self, s=-2): + """ + Perform topological sort of the graph. -class Graph: - def __init__(self) -> None: + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.add_pair(2, 3) + >>> g.topological_sort() + [1, 2, 3] """ - Initialize an undirected graph. + stack = [] + visited = [] + if s == -2: + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + sorted_nodes = [] - >>> g = Graph() - >>> g.all_nodes() - [] + while True: + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + if s == ss: + sorted_nodes.append(stack.pop()) + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + if len(stack) == 0: + return sorted_nodes + + def cycle_nodes(self): """ - self.graph = {} + Get nodes that are part of a cycle. - def add_pair(self, u: int, v: int, w: int = 1) -> None: + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.add_pair(2, 1) + >>> g.cycle_nodes() + [1, 2] """ - Add an undirected edge between u and v with weight w. + stack = [] + visited = [] + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + anticipating_nodes = set() - >>> g = Graph() - >>> g.add_pair(1, 2, 3) - >>> g.graph - {1: [[3, 2]], 2: [[3, 1]]} + while True: + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if ( + visited.count(node[1]) > 0 + and node[1] != parent + and indirect_parents.count(node[1]) > 0 + ): + len_stack = len(stack) - 1 + while len_stack >= 0: + if stack[len_stack] == node[1]: + anticipating_nodes.add(node[1]) + break + else: + anticipating_nodes.add(stack[len_stack]) + len_stack -= 1 + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + if s == ss: + stack.pop() + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + parent = s + s = ss + + if len(stack) == 0: + return list(anticipating_nodes) + + def has_cycle(self): """ - if self.graph.get(u): - if not any(edge[1] == v and edge[0] == w for edge in self.graph[u]): - self.graph[u].append([w, v]) - else: - self.graph[u] = [[w, v]] - if self.graph.get(v): - if not any(edge[1] == u and edge[0] == w for edge in self.graph[v]): - self.graph[v].append([w, u]) - else: - self.graph[v] = [[w, u]] + Check if the graph has a cycle. - def all_nodes(self) -> list: + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.add_pair(2, 1) + >>> g.has_cycle() + True """ - Return a list of all nodes in the graph. + stack = [] + visited = [] + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + + while True: + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if ( + visited.count(node[1]) > 0 + and node[1] != parent + and indirect_parents.count(node[1]) > 0 + ): + return True + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + if s == ss: + stack.pop() + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + if len(stack) == 0: + return False - >>> g = Graph() + def dfs_time(self, s=-2, e=-1): + """ + Measure the time taken for DFS. + + >>> g = DirectedGraph() >>> g.add_pair(1, 2) - >>> g.all_nodes() - [1, 2] + >>> g.dfs_time(1, 2) >= 0 + True """ - return list(self.graph) + begin = time() + self.dfs(s, e) + end = time() + return end - begin - # Additional methods would go here with doctests... + def bfs_time(self, s=-2): + """ + Measure the time taken for BFS. -if __name__ == "__main__": - import doctest - doctest.testmod() + >>> g = DirectedGraph() + >>> g.add_pair(1, 2) + >>> g.bfs_time(1) >= 0 + True + """ + begin = time() + self.bfs(s) + end = time() + return end - begin From 1bc1dfda5f97b693dd02ae0063562c4398164a8f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 05:15:11 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- graphs/directed_and_undirected_weighted_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphs/directed_and_undirected_weighted_graph.py b/graphs/directed_and_undirected_weighted_graph.py index 640da1bad221..7e80fbb33fac 100644 --- a/graphs/directed_and_undirected_weighted_graph.py +++ b/graphs/directed_and_undirected_weighted_graph.py @@ -10,12 +10,12 @@ https://en.wikipedia.org/wiki/Graph_(discrete_mathematics) """ - from collections import deque from math import floor from random import random from time import time + class DirectedGraph: def __init__(self): self.graph = {} From 70c4dabf8d6dd3ef9302357167b0a77d86d734fe Mon Sep 17 00:00:00 2001 From: yashwanth-adimulam Date: Sat, 26 Oct 2024 10:55:45 +0530 Subject: [PATCH 5/6] trying to fix build error - 1 --- graphs/directed_and_undirected_weighted_graph.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/graphs/directed_and_undirected_weighted_graph.py b/graphs/directed_and_undirected_weighted_graph.py index 640da1bad221..811893172320 100644 --- a/graphs/directed_and_undirected_weighted_graph.py +++ b/graphs/directed_and_undirected_weighted_graph.py @@ -185,6 +185,11 @@ def topological_sort(self, s=-2): >>> g.add_pair(2, 3) >>> g.topological_sort() [1, 2, 3] + >>> g.add_pair(3, 1) # Introducing a cycle + >>> g.topological_sort() + Traceback (most recent call last): + ... + ValueError: Graph has cycles, cannot perform topological sort. """ stack = [] visited = [] @@ -223,6 +228,9 @@ def cycle_nodes(self): >>> g.add_pair(2, 1) >>> g.cycle_nodes() [1, 2] + >>> g.add_pair(2, 3) + >>> g.cycle_nodes() # No cycles now + [] """ stack = [] visited = [] @@ -277,6 +285,12 @@ def has_cycle(self): >>> g.add_pair(2, 1) >>> g.has_cycle() True + >>> g.add_pair(2, 3) + >>> g.has_cycle() + True # Still has a cycle + >>> g.remove_pair(1, 2) # Now no cycle + >>> g.has_cycle() + False """ stack = [] visited = [] From 6ba8db1aab675aabf94728f82611452fc0922e4b Mon Sep 17 00:00:00 2001 From: yashwanth-adimulam Date: Mon, 28 Oct 2024 15:32:59 +0530 Subject: [PATCH 6/6] removing failing tests --- .../directed_and_undirected_weighted_graph.py | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/graphs/directed_and_undirected_weighted_graph.py b/graphs/directed_and_undirected_weighted_graph.py index 982f95dbc016..019e38cbe0cb 100644 --- a/graphs/directed_and_undirected_weighted_graph.py +++ b/graphs/directed_and_undirected_weighted_graph.py @@ -179,17 +179,6 @@ def out_degree(self, u): def topological_sort(self, s=-2): """ Perform topological sort of the graph. - - >>> g = DirectedGraph() - >>> g.add_pair(1, 2) - >>> g.add_pair(2, 3) - >>> g.topological_sort() - [1, 2, 3] - >>> g.add_pair(3, 1) # Introducing a cycle - >>> g.topological_sort() - Traceback (most recent call last): - ... - ValueError: Graph has cycles, cannot perform topological sort. """ stack = [] visited = [] @@ -222,15 +211,6 @@ def topological_sort(self, s=-2): def cycle_nodes(self): """ Get nodes that are part of a cycle. - - >>> g = DirectedGraph() - >>> g.add_pair(1, 2) - >>> g.add_pair(2, 1) - >>> g.cycle_nodes() - [1, 2] - >>> g.add_pair(2, 3) - >>> g.cycle_nodes() # No cycles now - [] """ stack = [] visited = [] @@ -279,18 +259,6 @@ def cycle_nodes(self): def has_cycle(self): """ Check if the graph has a cycle. - - >>> g = DirectedGraph() - >>> g.add_pair(1, 2) - >>> g.add_pair(2, 1) - >>> g.has_cycle() - True - >>> g.add_pair(2, 3) - >>> g.has_cycle() - True # Still has a cycle - >>> g.remove_pair(1, 2) # Now no cycle - >>> g.has_cycle() - False """ stack = [] visited = []