def __init__(self): self.graph = Graph() self.pages = []
# TODO # https://www.geeksforgeeks.org/detect-cycle-in-an-undirected-graph-using-bfs/ def detect_cycle_using_BFS(graph: Graph[T]) -> Tuple[bool, List[Vertex[T]]]: pass # TODO # https://www.geeksforgeeks.org/detect-cycle-in-the-graph-using-degrees-of-nodes-of-graph/?ref=rp def detct_cycle_using_degree(graph: Graph[T]) -> bool: pass if __name__ == '__main__': graph1: Graph[str] = Graph() graph1.add_edge('A', 'B', reverse=False) graph1.add_edge('B', 'C', reverse=False) graph1.add_edge('C', 'D', reverse=False) print('Graph:') print(graph1, '\n') # (B-->A, A-->C, B-->C, C-->A, A-->B, C-->B) print("All edges:", graph1.edges) # (B---A, A---C, B---C) print("Undirected/unique edges:", graph1.undirected_edges) has_cycle = detect_cycle_using_disjoint_set(graph1) print("\nUsing Disjoint set - " +
# We could randomly start from any vertex and all __DFS__(random_vertex, visited) only once. But then, if graph # would be disconnected then, we might miss a few vertex while traversing the graph. for data, ver in all_data_vertex_mapping.items(): if not visited.get(data, False): __DFS__(ver) return dfs if __name__ == '__main__': # a -- b x # | | \ / \ # | | e y z # | | / # c -- d graph1 = Graph() graph1.add_edge('a', 'b', is_directed=False) graph1.add_edge('b', 'e', is_directed=False) graph1.add_edge('b', 'd', is_directed=False) graph1.add_edge('e', 'd', is_directed=False) graph1.add_edge('d', 'c', is_directed=False) graph1.add_edge('c', 'a', is_directed=False) graph1.add_edge('x', 'y', is_directed=False) graph1.add_edge('x', 'z', is_directed=False) print(graph1) bfs_arr = BFS(graph1) # [b, a, e, d, c, x, z, y] print("\nBFS:", bfs_arr) dfs_arr = DFS_recursive(graph1)
is_acyclic, top_order = topological_sort_using_BFS(graph) return not is_acyclic if __name__ == '__main__': # # ⟶ B ⟶ D ⟵ F # | | | | # A ⭣ ⭣ ⭣ # ⭡___ C ⟶ E G # # A - C - B - A # C - B - A - C graph1 = Graph() graph1.add_edge('A', 'B', is_directed=True) graph1.add_edge( 'B', 'C', is_directed=True) # Replace edge B -> C to B -> G it to remove cycle. # graph1.add_edge('B', 'G', is_directed=True) graph1.add_edge('B', 'D', is_directed=True) graph1.add_edge('C', 'A', is_directed=True) graph1.add_edge('C', 'E', is_directed=True) graph1.add_edge('D', 'E', is_directed=True) graph1.add_edge('F', 'D', is_directed=True) graph1.add_edge('F', 'G', is_directed=True) # A: A-->B # B: B-->D, B-->C # C: C-->E, C-->A
def __init__(self): self.trie = Trie() # Only change Trie <-> Trie2 here to test the other class self.graph = Graph() self.pages = [] self.dict = {} # Dictionary is used to keep record of pages, in the format <PageNumber>:<PageName> self.files = []
def test_find_love(self): ''' Función encargada de probar la función find love. :return: ''' # Primer test start, goal = 0, 4 arcs = [(0, 1), (0, 2), (0, 3), (3, 4)] g = Graph(goal + 1) for arc in arcs: g.add_edge(arc[0], arc[1]) self.assertEqual(g.find_love(start, goal), (2, ['3', '4'])) # Segundo test start, goal = 0, 9 arcs = [(0, 1), (0, 2), (0, 3), (1, 5), (2, 4), (3, 7), (4, 9), (5, 6), (7, 8), (6, 9), (8, 9)] g = Graph(goal + 1) for arc in arcs: g.add_edge(arc[0], arc[1]) self.assertEqual(g.find_love(start, goal), (3, ['2', '4', '9'])) # Tercer test start, goal = 0, 4 arcs = [(0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (2, 4)] g = Graph(goal + 1) for arc in arcs: g.add_edge(arc[0], arc[1]) self.assertEqual(g.find_love(start, goal), (2, ['2', '4']))
for neighbor in current_vert.get_neighbors(): # print(current_vert, neighbor) if queue.contains(neighbor.key): new_dist = current_vert.dist + current_vert.get_weight(neighbor) # print(new_dist, 'new dist') if new_dist < neighbor.dist: neighbor.dist = new_dist neighbor.predecessor = current_vert # print(neighbor.predecessor) # The problem is herede # queue.percolate_up(neighbor.key, queue.node_position[neighbor.key]) queue.percolate_up(queue.node_position[neighbor.key], neighbor.key) g = Graph() a = ['A', 'B', 'C', 'D', 'E'] for key in a: g.add_vertex(key) g.add_edge('A', 'B', 3) g.add_edge('B', 'A', 3) g.add_edge('A', 'C', 2) g.add_edge('C', 'A', 2) g.add_edge('A', 'E', 4) g.add_edge('E', 'A', 4) g.add_edge('B', 'C', 8) g.add_edge('C', 'B', 8) g.add_edge('E', 'D', 3) g.add_edge('D', 'E', 3) g.add_edge('D', 'C', 1)
# Encoding: UTF-8 """ Run Graph program from CLI Usage : python run.py {start_node} {end_node} {path/to/csv} """ from Graph.graph import Graph from Converter.csv_converter import CsvConverter import pprint import argparse # Get arg from CLI argparser = argparse.ArgumentParser(description="Run Graph program from CLI") argparser.add_argument('start_node', help="The start node for pathfinding") argparser.add_argument('end_node', help="The end node for pathfinding") argparser.add_argument('csv_file', help="csv file representing graph as : ['source', 'target', 'cost']") args = argparser.parse_args() graph = Graph() graph.set_converter(CsvConverter()) graph.convert(args.csv_file) print "Graph loaded :" graph.print_graph() path = graph.find_path(args.start_node, args.end_node) pprint.pprint("A path exists from %s to %s" % (args.start_node, args.end_node)) pprint.pprint(path) shortest_path = graph.djikstra(args.start_node, args.end_node) print "And the minimum cost path is :" pprint.pprint(shortest_path)
class GraphApi(Resource): def __init__(self): # Arcos self._arcs = [] # Nodo inicial self._start = None # Nodo final self._goal = None # Instancia de la clase 'Graph' self._g_instance = None # Mensaje de respuesta al usuario self._data = None # Getters y setters @property def arcs(self): ''' Getter de la variable 'arcs'. :return: La variable 'arcs' ''' return self._arcs @arcs.setter def arcs(self, arcs): ''' Setter de la variable 'arcs'. :return: None ''' self._arcs = arcs @property def start(self): ''' Getter de la variable 'start'. :return: La variable 'start' ''' return self._start @start.setter def start(self, start): ''' Setter de la variable 'start'. :return: None ''' self._start = start @property def goal(self): ''' Getter de la variable 'goal'. :return: La variable 'goal' ''' return self._goal @goal.setter def goal(self, goal): ''' Setter de la variable 'goal'. :return: None ''' self._goal = goal @property def g_instance(self): ''' Getter de la variable 'g_instance'. :return: La variable 'g_instance' ''' return self._g_instance @g_instance.setter def g_instance(self, g_instance): ''' Setter de la variable 'g_instance'. :return: None ''' self._g_instance = g_instance @property def data(self): ''' Getter de la variable 'data'. :return: La variable 'data' ''' return self._data @data.setter def data(self, data): ''' Setter de la variable 'data'. :return: None ''' self._data = data def get(self): ''' Función que devuelve la lista de arcos del árbol (si la hay) al hacer una petición GET al endpoint '/graph'. :return: Un JSON con los arcos del grafo. ''' return {"data": "Graph API working..."} def put(self): ''' Función encargada de recibir los datos necesarios para crear un grafo. Los recibe en formato JSON cuando se hace una petición PUT al endpoint. :return: Una tupla de la forma (num_personas_necesarias, [lista_de_personas_necesarias]) ''' # Verificamos que cumpla con los datos que necesitamos args = graph_put_args.parse_args() # Función encargada de tratar la entrada self.clean_data(args) # Iniciamos el grafo self.start_graph() # Le damos formato al JSON de respuesta self.data = {"distance": self.data[0], "nodes": self.data[1]} return self.data, 201 def clean_data(self, args): # Guardamos el inicio y el objetivo self.start = args['start'] self.goal = args['goal'] # Separamos los arcos por parejas edges = args['edges'].split(',') # Separamos cada pareja edges = [tuple(map(int, edge.split('-'))) for edge in edges] # Guardamos los arcos en su variable respectiva self.arcs = edges # Modificamos la variable global for el in self.arcs: temp_graph.append(el) def delete(self): temp_graph.clear() return {"message": "Arcos borrados satisfactoriamente"} def are_arcs_empty(self): if len(temp_graph) == 0: abort(404, message="No se puede consultar un grafo sin nodos") def start_graph(self): self.g_instance = Graph(self.goal + 1) # Agregamos los arcos al grafo for pair in self.arcs: self.g_instance.add_edge(pair[0], pair[1]) # Buscamos la cantidad de personas necesarias para llegar de 'start' a 'goal' self.data = self.g_instance.find_love(self.start, self.goal)
head_node = head_node.next_element # remove the node from the recursive call rec_node_stack[node] = False return False # g1 = Graph(4) # g1.add_edge(0, 1) # g1.add_edge(1, 2) # g1.add_edge(1, 3) # g1.add_edge(3, 0) # # g2 = Graph(3) # g2.add_edge(0, 1) # g2.add_edge(1, 2) g3 = Graph(10) g3.add_edge(0, 1) g3.add_edge(0, 2) g3.add_edge(1, 4) g3.add_edge(1, 5) g3.add_edge(2, 6) g3.add_edge(2, 7) g3.add_edge(3, 8) g3.add_edge(3, 9) g3.add_edge(9, 0) # print(detect_cycle(g1)) # print(detect_cycle(g2)) print(detect_cycle(g3))
while not queue.is_empty(): # Dequeue a vertex/node from queue and add it to result current_node = queue.dequeue() result += str(current_node) # Get adjacent vertices to the current_node from the list, # and if they are not already visited then enqueue them in the Q temp = g.array[current_node].head_node while temp is not None: if not visited[temp.data]: queue.enqueue(temp.data) visited[temp.data] = True # Visit the current Node temp = temp.next_element return result g = Graph(7) g.add_edge(1, 2) g.add_edge(1, 3) g.add_edge(2, 4) g.add_edge(2, 5) g.add_edge(3, 6) print(bfs_traversal(g, 1)) # g = Graph(6) # # num_of_vertices = g.vertices # # if num_of_vertices == 0: # print("Graph is empty") # else: # g.add_edge(0, 1) # g.add_edge(0, 2)
return True # Continue BFS by obtaining first element in linked list adjacent = g.array[node].head_node while adjacent: # enqueue adjacent node if it has not been visited if visited[adjacent.data] is False: queue.enqueue(adjacent.data) visited[adjacent.data] = True adjacent = adjacent.next_element # Destination was not found in the search return False g1 = Graph(9) g1.add_edge(0, 2) g1.add_edge(0, 5) g1.add_edge(2, 3) g1.add_edge(2, 4) g1.add_edge(5, 3) g1.add_edge(5, 6) g1.add_edge(3, 6) g1.add_edge(6, 7) g1.add_edge(6, 8) g1.add_edge(6, 4) g1.add_edge(7, 8) g2 = Graph(4) g2.add_edge(0, 1) g2.add_edge(1, 2)
def check_cycle(g, node, visited, parent): # Mark node as visited visited[node] = True # Pick adjacent node and run recursive DFS adjacent = g.array[node].head_node while adjacent: if visited[adjacent.data] is False: if check_cycle(g, adjacent.data, visited, node) is True: return True # If adjacent is visited and not the parent node of the current node elif adjacent.data is not parent: # Cycle found return True adjacent = adjacent.next_element return False g = Graph(5) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(0, 3) g.add_edge(3, 4) g.add_edge(1, 0) g.add_edge(2, 0) g.add_edge(3, 0) g.add_edge(4, 3) print(is_tree(g))
# References: # https://www.geeksforgeeks.org/kruskals-algorithm-simple-implementation-for-adjacency-matrix/?ref=rp if __name__ == '__main__': # # 1 6 # A ---- D ---- E # | /| /| # 3 | 3/ |1 /5 | 2 # | / | / | # B ---- C ---- F # 1 4 # graph: Graph[T] = Graph() graph.add_edge('A', 'B', weight=3, reverse=False) graph.add_edge('A', 'D', weight=1, reverse=False) graph.add_edge('B', 'C', weight=1, reverse=False) graph.add_edge('B', 'D', weight=3, reverse=False) graph.add_edge('C', 'D', weight=1, reverse=False) graph.add_edge('C', 'E', weight=5, reverse=False) graph.add_edge('C', 'F', weight=4, reverse=False) graph.add_edge('D', 'E', weight=6, reverse=False) graph.add_edge('E', 'F', weight=2, reverse=False) print("Adjacency list:") # A: A--(3)-->B, A--(1)-->D # B: B--(3)-->D, B--(1)-->C # C: C--(1)-->D, C--(4)-->F, C--(5)-->E # D: D--(6)-->E
class HtmlLoader(object): """ Class which is in charge of everything data-wise. Within its fields, it holds the Trie structure, Graph and a dictionary with every page name linked to a certain page number (later used as ID). """ def __init__(self): self.trie = Trie() # Only change Trie <-> Trie2 here to test the other class self.graph = Graph() self.pages = [] self.dict = {} # Dictionary is used to keep record of pages, in the format <PageNumber>:<PageName> self.files = [] def loadTrieViaHTML(self, path): """ Collects all the '.html' files from the given path and its subfolders into a list. Then proceeds to call Parser.parse() for each file in the list. Words from every file are then inserted into the Trie structure. After filling the Trie, it creates the Graph structure. """ parser = Parser() start = time.time() """ By using 'self.getAllFiles(path), we collect the absolute paths for every '.html' file in the given directory. Paths are kept within the list 'self.files'. Using a for loop and a parser, we iterate through the list, and parse every file, add its words to the Trie structure, and subsequently build a Graph. """ page_counter = -1 self.getHtmlFiles(path) for file in self.files: page_counter += 1 self.dict[page_counter] = file parser.parse(file) # Parse the page at the given path page = Page(file, parser.links, len(parser.words)) # Create a new Page object to be used for Graphing self.pages.append(page) for word in parser.words: # Insert every word from the page into Trie self.trie.insertWord(word, page_counter) " Graph creation below: " " Creating a Vertex for every page " for page in self.pages: self.graph.insert_vertex(Graph.Vertex(page.path)) " Adding edges for every link between pages " for page in self.pages: for link in page.links: self.graph.insert_edge(Graph.Vertex(page.path), Graph.Vertex(link)) end = time.time() print("Parsed files, loaded Trie and formed a Graph in " + str((end - start).__round__(2)) + " seconds.") " Returns a page name corresponding to the page number which is passed as a parameter. " def getPageName(self, pageNum): return self.dict.get(pageNum) " Return a corresponding page number for a given page name. " def getPageNum(self, pageName): for key in self.dict.keys(): if self.dict[key] == pageName: return key return -1 " Iterates through all the files and subfolders in the given path folder, and adds .html file names to self.files " def getHtmlFiles(self, path): for file in os.scandir(path): filepath = file.path if file.name.endswith('html'): self.files.append(filepath) elif file.is_dir(): self.getHtmlFiles(filepath)
def num_edges(g): # For undirected graph, just sum up the size of # all the adjacency lists for each vertex sum_ = 0 for i in range(g.vertices): temp = g.array[i].head_node while temp is not None: sum_ += 1 temp = temp.next_element # Half the total sum as it is an undirected graph return sum_ // 2 g = Graph(9) g.add_edge(0, 2) g.add_edge(0, 5) g.add_edge(2, 3) g.add_edge(2, 4) g.add_edge(5, 3) g.add_edge(5, 6) g.add_edge(3, 6) g.add_edge(6, 7) g.add_edge(6, 8) g.add_edge(6, 4) g.add_edge(7, 8) g.add_edge(2, 0) g.add_edge(5, 0) g.add_edge(3, 2)
def main(): g = Graph(int(input("Enter Number Of Nodes of Your Graph: "))) g.create_graph_with_edges(int( input("Enter The Number Of Edges : "))) # Take The Graph Input g.sort_edges_by_value() # Sort The Edges By Weight krushkal_algo(g)