def dijkstra(graph, s, e): """Simple dijkstra algo to work out shortest path to an end node""" pq = MinHeap() # Set the distance for the start node to zero then build heap s.set_distance(0) pq.build_heap([(v.get_distance(),v) for v in graph]) while not pq.is_empty(): cv = pq.del_min() current_v = cv[1] current_v.set_as_visited() if current_v.get_key() == e.get_key(): break else: for v in current_v.adj: new_dist = current_v.get_distance() + current_v.get_weight(v) if new_dist < v.get_distance(): v.set_distance(new_dist) v.set_pred(current_v) pq.decrease_val(v, new_dist) # if queue empties before end is found it means there are no paths from source to end if pq.is_empty() == True: print 'No path to exists' else: shortest(e)
def dsp(graph: list, s, t) -> int: """ Find shortest path from two vertices via Dijkstra's shortest-path algorithm. Args: s: source vertex t: the target vertex Returns: Shortest path from `s` to `t` vertices """ if s == t: return 0 # Vertices seen so far visited = [] heap = MinHeap([(10000000, v) for v in range(1, len(graph))]) heap.update_min(0, s) while not heap.is_empty(): dist, u = heap.pop() visited.append(u) if u == t: return dist for v, d in graph[u]: if v not in visited: heap.update_min(dist + d, v)
class TestMinHeap(unittest.TestCase): def setUp(self): self.heap = MinHeap() def test_clear(self): """Calling clear for a heap sets its array to an empty list and size to zero. (0p)""" self.heap.array = [(1, 1)] self.heap.size = 1 self.heap.clear() self.assertListEqual( [], self.heap.array, "heap.clear() should set heap.array to an empty list.") self.assertEqual(0, self.heap.size, "heap.clear() should set heap.size to 0.") def test_empty_heap_size(self): """The size of an empty heap is zero. (0p)""" self.assertEqual(0, self.heap.size, "The size of an empty heap should be zero.") def test_empty_heap_is__empty(self): """is_empty returns True for an empty heap. (0p)""" self.assertTrue( self.heap.is_empty(), "Calling is_empty should return True for an empty heap instance.") def test_higher_priority_high_low(self): """_higher_priority returns True when comparing an element with a higher priority to an element with a lower priority. (1p)""" self.heap.array = [(1, 'important'), (2, 'not important')] self.assertTrue( self.heap._higher_priority(0, 1), "_higher_priority priority should return True when comparing {0} to {1}" .format(self.heap.array[0], self.heap.array[1])) def test_higher_priority_low_high(self): """_higher_priority returns False when comparing an element with a lower priority to an element with a higher priority. (1p)""" self.heap.array = [(1, 'important'), (2, 'not important')] self.assertFalse( self.heap._higher_priority(1, 0), "_higher_priority priority should return False when comparing {0} to {1}" .format(self.heap.array[1], self.heap.array[0])) def test_size_after_insert(self): """Inserting values into the heap increments the size counter. (1p)""" inserted_tasks = generate_tasks_with_priorities() for pair in inserted_tasks: self.heap.insert(pair) inserted_count = len(inserted_tasks) current_size = self.heap.size self.assertEqual( inserted_count, current_size, "After inserting {0} pairs, the size of the heap should be {0}, not {1}" .format(inserted_count, current_size) + '\n' + heap_array_to_string(self.heap.array)) def test_empty_heap_top(self): """Calling top on an empty heap returns None. (1p)""" self.assertIsNone( self.heap.top(), "Calling heap.top() should return None for an empty heap instance." ) def test_empty_heap_pop(self): """Calling pop on an empty heap raises an exception. (1p)""" msg = "Calling heap.pop() should raise a RuntimeError for an empty heap instance." with self.assertRaises(RuntimeError, msg=msg): self.heap.pop() def test_top_after_insert(self): """Calling top always returns the object with the smallest priority value. (1p)""" inserted_tasks = generate_tasks_with_priorities() shuffled = list(inserted_tasks) random.shuffle(shuffled) for pair in shuffled: self.heap.insert(pair) expected_value = inserted_tasks[0][1] returned_value = self.heap.top() self.assertIs( returned_value, expected_value, "Calling top should have returned {0}, not {1}.".format( expected_value, returned_value) + '\n' + heap_array_to_string(self.heap.array)) def test_pop_after_insert(self): """Calling pop always returns the object with the smallest priority value and removes it from the heap. (1p)""" inserted_tasks = generate_tasks_with_priorities() shuffled = list(inserted_tasks) random.shuffle(shuffled) for pair in shuffled: self.heap.insert(pair) for i, pair in enumerate(inserted_tasks): assertmsg = "Before calling pop, the heap array in your solution looked like this:" heap_array_before_pop = self.heap.array[:] popped_value = self.heap.pop() expected_value = pair[1] self.assertIs( popped_value, expected_value, "Calling pop should have returned {0}, not {1}.".format( expected_value, popped_value) + '\n' + heap_array_to_string(heap_array_before_pop, assertmsg)) removed_count = i + 1 self.assertEqual( len(self.heap.array), len(inserted_tasks) - removed_count, "Calling pop should remove the object with the smallest priority value from the heap array." + '\n' + heap_array_to_string(heap_array_before_pop, assertmsg))
class TestMinHeap(unittest.TestCase): def setUp(self): self.h = MinHeap(elements=[2, 4, 5, 12, 13, 6, 10]) def test_parent_index(self): self.assertLess(self.h._parent_index(0), 0) self.assertEqual(self.h._parent_index(1), 0) self.assertEqual(self.h._parent_index(2), 0) self.assertEqual(self.h._parent_index(4), 1) self.assertEqual(self.h._parent_index(6), 2) def test_left_child_index(self): self.assertGreaterEqual(self.h._left_child_index(3), len(self.h)) self.assertGreaterEqual(self.h._left_child_index(5), len(self.h)) self.assertEqual(self.h._left_child_index(0), 1) self.assertEqual(self.h._left_child_index(1), 3) self.assertEqual(self.h._left_child_index(2), 5) def test_right_child_index(self): self.assertGreaterEqual(self.h._right_child_index(3), len(self.h)) self.assertGreaterEqual(self.h._right_child_index(6), len(self.h)) self.assertEqual(self.h._right_child_index(0), 2) self.assertEqual(self.h._right_child_index(1), 4) self.assertEqual(self.h._right_child_index(2), 6) def test_is_empty(self): self.assertFalse(self.h.is_empty()) self.assertTrue(MinHeap().is_empty()) def test_peek(self): self.assertEqual(self.h.peek(), self.h.h[0]) self.assertIsNone(MinHeap().peek()) def test_heapify_init(self): elements = [2, 4, 5, 6, 10, 12, 13] h = MinHeap(elements) self.assertEqual(h.h, [2, 4, 5, 6, 10, 12, 13]) def test_heapify_after_init(self): elements = [2, 4, 5, 6, 10, 12, 13] h = MinHeap() self.assertEqual(h.h, []) h._heapify(elements) self.assertEqual(h.h, [2, 4, 5, 6, 10, 12, 13]) def test_insert_1(self): self.assertEqual(self.h.insert(1), 0) self.assertEqual(self.h.h, [1, 2, 5, 4, 13, 6, 10, 12]) def test_insert_3(self): self.assertEqual(self.h.insert(3), 1) self.assertEqual(self.h.h, [2, 3, 5, 4, 13, 6, 10, 12]) def test_insert_10(self): self.assertEqual(self.h.insert(9), 3) self.assertEqual(self.h.h, [2, 4, 5, 9, 13, 6, 10, 12]) def test_insert_15(self): self.assertEqual(self.h.insert(15), 7) self.assertEqual(self.h.h, [2, 4, 5, 12, 13, 6, 10, 15]) def test_update_min(self): self.assertTrue(9 not in self.h) self.assertTrue(10 in self.h) self.h.update_min(9, 10) self.assertTrue(9 in self.h) self.assertTrue(10 not in self.h) self.assertEqual(self.h.h, [2, 4, 5, 12, 13, 6, 9]) def test_pop_empty(self): h = MinHeap() self.assertIsNone(h.pop()) self.assertEqual(h.h, [])