class _Iterator: def __init__(self, root_node): self.root_node = root_node self.current_node = root_node self.queue = Queue_LinkedList() # Build the queue (default is from least node to greatest node) self.build_queue(self.current_node) def __next__(self): if self.queue.isEmpty() == True: raise StopIteration returned_node = self.queue.dequeue() return returned_node def build_queue(self, current_node): if current_node == None: return self.build_queue(current_node.left) self.queue.enqueue(current_node) #print(current_node.key) self.build_queue(current_node.right)
class Shortest_Paths: def __init__(self, ewdg, s): self._distTo = [float('inf') for i in range(ewdg.V())] self._distTo[s] = 0 self.edgeTo = [None] * ewdg.V() self.s = s self.vertex_queue = Queue_LinkedList() self.vertex_queue.enqueue(self.s) self.on_queue = [False] * ewdg.V() self.on_queue[self.s] = True self.cycle = None # Keeps track of the number of relax calls that are required in a pass # self.num_rcip = self.num_vaip after each pass self.num_rcip = 1 # Keeps track of the number of edges that were eligible to be relaxed in the pass self.num_vaip = 0 # Keeps track of the number of "passes" in the algorithm # When self.num_rcip reaches 0, we know we are starting a new "pass" self.pass_count = 1 # some way of determining the order methodology of choosing v # In this case, we only look at edges coming from vertices that were relaxed in the previous pass instead of all of the edges as in sp_bellmanford_manual. print('Pass: '******'\n\n Negative cycle is reachable from s. Shortest paths cannot be computed.' ) print( '--------------------------------------------------------------------------------- \n\n' ) self.findNegativeCycle() return v = self.vertex_queue.dequeue() self.on_queue[v] = False if self.num_rcip == 0: self.num_rcip = self.num_vaip self.num_vaip = 0 self.pass_count += 1 print('\n') print('Pass: '******'Queue is empty. Shortest paths for all reachable vertices from s have been found.' ) print( '--------------------------------------------------------------------------------- \n\n' ) def relax(self, ewdg, v): print("from vertex: ", v, " (removed from queue)") for edge in ewdg.adjacent(v): print('Edge: ', edge) v = edge.from_vert() w = edge.towards_vert() if self._distTo[v] + edge.weight() < self._distTo[w]: # number of vertices added on this relax self.num_vaip += 1 print('This edge is eligible and will be relaxed') self.edgeTo[w] = edge self._distTo[w] = self._distTo[v] + edge.weight() print("towards vertex", w) if self.on_queue[w] == True: print('The vertex ', w, ' is already on the queue') else: print('The vertex ', w, ' was not already on the queue. Added to queue.') self.vertex_queue.enqueue(w) self.on_queue[w] = True else: print('This edge is ineligible') def distTo(self, v): return self._distTo[v] def hasPathTo(self, v): return self._distTo[v] != float('inf') # Returns stack of directed edges from the source vertex s to a given vertex v. def pathTo(self, v): path_stack = Stack_ResizingArray() directed_edge = self.edgeTo[v] if v == self.s: return "No edges required to reach source vertex from source vertex" vert_from = directed_edge.from_vert() while vert_from != self.s: path_stack.push(directed_edge) directed_edge = self.edgeTo[vert_from] vert_from = directed_edge.from_vert() path_stack.push(directed_edge) return path_stack # This method is not required for the algorithm, I just added this to keep track of the number of "passes" def num_passes(self): return self.pass_count def hasNegativeCycle(self): return self.cycle is not None def findNegativeCycle(self): # Build ew_digraph from edges in edgeTo new_graph = Edge_Weighted_Digraph(V=len(self._distTo)) for edge in self.edgeTo: # The entry for self.edgeTo[s] is None # Reminder that the 'is' and 'is not' operators test for reference/identity equality # In python, there is only one location for None in a python script, no matter how many variables are set to None # ie id(edge) == id(None) if edge is not None: new_graph.addEdge(edge) # We know there is a (negative) cycle in this ew_digraph cycle_finder = Directed_Weighted_Cycle(new_graph) self.cycle = cycle_finder.cycle() def negativeCycle(self): return self.cycle