From 98db791d372f6ceab301ff029d3dd82924dcda71 Mon Sep 17 00:00:00 2001 From: A Safari Date: Wed, 28 Nov 2018 15:54:19 -0500 Subject: [PATCH 1/8] Create Non-crossing-lines-to-connect-points-in-a-circle --- .../Non-crossing-lines-to-connect-points-in-a-circle | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle diff --git a/dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle b/dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle new file mode 100644 index 000000000..a2eec0454 --- /dev/null +++ b/dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle @@ -0,0 +1,10 @@ +def count(n): + if (n & 1): + return 0 + val = n // 2 + dy_lst = [1 for i in range(val + 1)] + for i in range(2, val + 1): + dy_lst[i] = 0 + for j in range(i): + dy_lst[i] += (dy_lst[j] * dy_lst[i - j - 1]) + return dy_lst[val] From 1c29a455b855232f7309380b0ad822fb351f1076 Mon Sep 17 00:00:00 2001 From: A Safari Date: Wed, 28 Nov 2018 15:56:10 -0500 Subject: [PATCH 2/8] Delete Non-crossing-lines-to-connect-points-in-a-circle --- .../Non-crossing-lines-to-connect-points-in-a-circle | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle diff --git a/dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle b/dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle deleted file mode 100644 index a2eec0454..000000000 --- a/dynamic_programming/Non-crossing-lines-to-connect-points-in-a-circle +++ /dev/null @@ -1,10 +0,0 @@ -def count(n): - if (n & 1): - return 0 - val = n // 2 - dy_lst = [1 for i in range(val + 1)] - for i in range(2, val + 1): - dy_lst[i] = 0 - for j in range(i): - dy_lst[i] += (dy_lst[j] * dy_lst[i - j - 1]) - return dy_lst[val] From fa2eecdc30d766197dad634a9f87bd4b7fad58ef Mon Sep 17 00:00:00 2001 From: A Safari Date: Fri, 14 Dec 2018 10:22:18 +0330 Subject: [PATCH 3/8] Directed graph with optional weight assignment . Containing graph auto-fill, dfs and bfs. --- graphs/Directed (Weighted) Graph | 95 ++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 graphs/Directed (Weighted) Graph diff --git a/graphs/Directed (Weighted) Graph b/graphs/Directed (Weighted) Graph new file mode 100644 index 000000000..03ae572e8 --- /dev/null +++ b/graphs/Directed (Weighted) Graph @@ -0,0 +1,95 @@ +from collections import deque +import random as rand +import math as math + +# the dfault weight is 1 if not assigend but all the implementation is weighted + +class DirectedGraph: + # enter True or False for this constructor + def __init__(self): + self.graph = {} + + # adding vertices and edges + # note that self loops are not supported in undirected simpl graphs but it is in multigraphs + 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 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 From 687af17d470e1b8b4d6e2a96afa6f512f9bcd519 Mon Sep 17 00:00:00 2001 From: A Safari Date: Fri, 14 Dec 2018 10:31:45 +0330 Subject: [PATCH 4/8] Added some examples. Added examples and comments for more readable code. --- graphs/Directed (Weighted) Graph | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/graphs/Directed (Weighted) Graph b/graphs/Directed (Weighted) Graph index 03ae572e8..d3bafd103 100644 --- a/graphs/Directed (Weighted) Graph +++ b/graphs/Directed (Weighted) Graph @@ -5,12 +5,12 @@ import math as math # the dfault weight is 1 if not assigend but all the implementation is weighted class DirectedGraph: - # enter True or False for this constructor def __init__(self): self.graph = {} # adding vertices and edges - # note that self loops are not supported in undirected simpl graphs but it is in multigraphs + # 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: @@ -19,6 +19,8 @@ class DirectedGraph: self.graph[u] = [[w, v]] if not self.graph.get(v): self.graph[v] = [] + + # handels if the input does not exist def remove_pair(self, u, v): if self.graph.get(u): for _ in self.graph[u]: @@ -93,3 +95,13 @@ class DirectedGraph: d.append(__[1]) visited.append(__[1]) return visited + +if __name__ == "__main__": + g = DirectedGraph() + # add 50 random nodes to the graph + g.fill_graph_randomly(50) + # you can add or remove any edge and vertex + g.add_pair(3, 5) + g.remove_pair(3,5) + g.dfs() + g.bgs() From e97565d21f1a6ec7d88ce9665817b9dd3d2978d4 Mon Sep 17 00:00:00 2001 From: A Safari Date: Fri, 14 Dec 2018 15:08:37 +0330 Subject: [PATCH 6/8] Added (Weighted) Undirected graph Python version 3 --- graphs/Directed (Weighted) Graph | 115 ++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/graphs/Directed (Weighted) Graph b/graphs/Directed (Weighted) Graph index d3bafd103..0b3b3a2cb 100644 --- a/graphs/Directed (Weighted) Graph +++ b/graphs/Directed (Weighted) Graph @@ -96,12 +96,109 @@ class DirectedGraph: visited.append(__[1]) return visited -if __name__ == "__main__": - g = DirectedGraph() - # add 50 random nodes to the graph - g.fill_graph_randomly(50) - # you can add or remove any edge and vertex - g.add_pair(3, 5) - g.remove_pair(3,5) - g.dfs() - g.bgs() + +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 From 889f8fba3d10a91803b76a49421cf103bfe479e6 Mon Sep 17 00:00:00 2001 From: A Safari Date: Fri, 14 Dec 2018 15:28:45 +0330 Subject: [PATCH 7/8] Added getting node degree functionality to both directed and undirected graph Easy to use directed and undirected graph in python 3 --- ...raph => Directed and Undirected (Weighted) Graph} | 12 ++++++++++++ 1 file changed, 12 insertions(+) rename graphs/{Directed (Weighted) Graph => Directed and Undirected (Weighted) Graph} (95%) diff --git a/graphs/Directed (Weighted) Graph b/graphs/Directed and Undirected (Weighted) Graph similarity index 95% rename from graphs/Directed (Weighted) Graph rename to graphs/Directed and Undirected (Weighted) Graph index 0b3b3a2cb..74d741f5e 100644 --- a/graphs/Directed (Weighted) Graph +++ b/graphs/Directed and Undirected (Weighted) Graph @@ -95,6 +95,16 @@ class DirectedGraph: 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]) class Graph: @@ -202,3 +212,5 @@ class Graph: d.append(__[1]) visited.append(__[1]) return visited + def degree(self, u): + return len(self.graph[u]) From b3a15175bddb4d63551830b80b3840264ad99c4b Mon Sep 17 00:00:00 2001 From: A Safari Date: Fri, 14 Dec 2018 23:14:35 +0330 Subject: [PATCH 8/8] Added more functionality Added topological sort, cycle detection and a function to report the nodes participating in cycles in graph(for a use case I myself needed ). --- .../Directed and Undirected (Weighted) Graph | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/graphs/Directed and Undirected (Weighted) Graph b/graphs/Directed and Undirected (Weighted) Graph index 74d741f5e..7e7063823 100644 --- a/graphs/Directed and Undirected (Weighted) Graph +++ b/graphs/Directed and Undirected (Weighted) Graph @@ -106,6 +106,133 @@ class DirectedGraph: 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 class Graph: def __init__(self): @@ -214,3 +341,98 @@ class Graph: 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