from collections import deque import random as rand import math as math import time # the dfault weight is 1 if not assigend but all the implementation is weighted class DirectedGraph: def __init__(self): self.graph = {} # adding vertices and edges # adding the weight is optional # handels repetition def add_pair(self, u, v, w = 1): if self.graph.get(u): if self.graph[u].count([w,v]) == 0: self.graph[u].append([w, v]) else: self.graph[u] = [[w, v]] if not self.graph.get(v): self.graph[v] = [] def all_nodes(self): return list(self.graph) # handels 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(_) # if no destination is meant the defaut value is -1 def dfs(self, s = -2, d = -1): if s == d: return [] stack = [] visited = [] if s == -2: s = list(self.graph.keys())[0] 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 __ in self.graph[s]: if visited.count(__[1]) < 1: if __[1] == d: visited.append(d) return visited else: stack.append(__[1]) visited.append(__[1]) ss =__[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 funtion the count # will be random from 10 to 10000 def fill_graph_randomly(self, c = -1): if c == -1: c = (math.floor(rand.random() * 10000)) + 10 for _ in range(c): # every vertex has max 100 edges e = math.floor(rand.random() * 102) + 1 for __ in range(e): n = math.floor(rand.random() * (c)) + 1 if n == _: continue self.add_pair(_, n, 1) def bfs(self, s = -2): d = deque() visited = [] if s == -2: s = list(self.graph.keys())[0] d.append(s) visited.append(s) while d: s = d.popleft() if len(self.graph[s]) != 0: for __ in self.graph[s]: if visited.count(__[1]) < 1: d.append(__[1]) visited.append(__[1]) return visited def in_degree(self, u): count = 0 for _ in self.graph: for __ in self.graph[_]: if __[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 = list(self.graph.keys())[0] 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 __ in self.graph[s]: if visited.count(__[1]) < 1: stack.append(__[1]) visited.append(__[1]) ss =__[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 = list(self.graph.keys())[0] stack.append(s) visited.append(s) parent = -2 indirect_parents = [] ss = s anticipating_nodes = set() while True: # check if there is any non isolated nodes if len(self.graph[s]) != 0: ss = s for __ in self.graph[s]: if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: l = len(stack) - 1 while True and l >= 0: if stack[l] == __[1]: anticipating_nodes.add(__[1]) break else: anticipating_nodes.add(stack[l]) l -= 1 if visited.count(__[1]) < 1: stack.append(__[1]) visited.append(__[1]) ss =__[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 = list(self.graph.keys())[0] stack.append(s) visited.append(s) parent = -2 indirect_parents = [] ss = s anticipating_nodes = set() while True: # check if there is any non isolated nodes if len(self.graph[s]) != 0: ss = s for __ in self.graph[s]: if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: l = len(stack) - 1 while True and l >= 0: if stack[l] == __[1]: anticipating_nodes.add(__[1]) break else: return True anticipating_nodes.add(stack[l]) l -= 1 if visited.count(__[1]) < 1: stack.append(__[1]) visited.append(__[1]) ss =__[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.time() self.dfs(s,e) end = time.time() return end - begin def bfs_time(self, s = -2): begin = time.time() self.bfs(s) end = time.time() return end - begin class Graph: def __init__(self): self.graph = {} # adding vertices and edges # adding the weight is optional # handels repetition def add_pair(self, u, v, w = 1): # check if the u exists if self.graph.get(u): # if there already is a edge if self.graph[u].count([w,v]) == 0: 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: self.graph[v].append([w, u]) else: # if u does not exist self.graph[v] = [[w, u]] # handels 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 defaut value is -1 def dfs(self, s = -2, d = -1): if s == d: return [] stack = [] visited = [] if s == -2: s = list(self.graph.keys())[0] 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 __ in self.graph[s]: if visited.count(__[1]) < 1: if __[1] == d: visited.append(d) return visited else: stack.append(__[1]) visited.append(__[1]) ss =__[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 funtion the count # will be random from 10 to 10000 def fill_graph_randomly(self, c = -1): if c == -1: c = (math.floor(rand.random() * 10000)) + 10 for _ in range(c): # every vertex has max 100 edges e = math.floor(rand.random() * 102) + 1 for __ in range(e): n = math.floor(rand.random() * (c)) + 1 if n == _: continue self.add_pair(_, n, 1) def bfs(self, s = -2): d = deque() visited = [] if s == -2: s = list(self.graph.keys())[0] d.append(s) visited.append(s) while d: s = d.popleft() if len(self.graph[s]) != 0: for __ in self.graph[s]: if visited.count(__[1]) < 1: d.append(__[1]) visited.append(__[1]) return visited def degree(self, u): return len(self.graph[u]) def cycle_nodes(self): stack = [] visited = [] s = list(self.graph.keys())[0] stack.append(s) visited.append(s) parent = -2 indirect_parents = [] ss = s anticipating_nodes = set() while True: # check if there is any non isolated nodes if len(self.graph[s]) != 0: ss = s for __ in self.graph[s]: if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: l = len(stack) - 1 while True and l >= 0: if stack[l] == __[1]: anticipating_nodes.add(__[1]) break else: anticipating_nodes.add(stack[l]) l -= 1 if visited.count(__[1]) < 1: stack.append(__[1]) visited.append(__[1]) ss =__[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 = list(self.graph.keys())[0] stack.append(s) visited.append(s) parent = -2 indirect_parents = [] ss = s anticipating_nodes = set() while True: # check if there is any non isolated nodes if len(self.graph[s]) != 0: ss = s for __ in self.graph[s]: if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: l = len(stack) - 1 while True and l >= 0: if stack[l] == __[1]: anticipating_nodes.add(__[1]) break else: return True anticipating_nodes.add(stack[l]) l -= 1 if visited.count(__[1]) < 1: stack.append(__[1]) visited.append(__[1]) ss =__[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): return list(self.graph) def dfs_time(self, s = -2, e = -1): begin = time.time() self.dfs(s,e) end = time.time() return end - begin def bfs_time(self, s = -2): begin = time.time() self.bfs(s) end = time.time() return end - begin