def test_sort_on_one_element_list(self): list = [heap.HeapItem(1)] self.heap.sort_in_place(list) self.assertEqual([heap.HeapItem(1)], list) self.assertEqual(1, self.heap.size)
def test_sort_on_sorted_two_element_list(self): list = [heap.HeapItem(2), heap.HeapItem(1)] self.heap.sort_in_place(list) self.assertEqual([heap.HeapItem(2), heap.HeapItem(1)], list) self.assertEqual(2, self.heap.size)
def test_insert_on_empty_list(self): self.assertEqual(0, self.heap.size) self.assertEqual([], self.heap.elements) self.heap.insert(heap.HeapItem(1)) self.assertEqual(1, self.heap.size) self.assertEqual([heap.HeapItem(1)], self.heap.elements)
def test_change_priority_on_non_empty_list_with_exceeding_index(self): self.heap.build([ heap.HeapItem(9), heap.HeapItem(5), heap.HeapItem(6), heap.HeapItem(2), heap.HeapItem(3) ]) with self.assertRaisesRegex(IndexError, ''): self.heap.change_priority(self.heap.size, 1)
def test_change_priority_on_one_element_list(self): self.heap.build([heap.HeapItem(9)]) self.assertEqual(1, self.heap.size) self.assertEqual([heap.HeapItem(9)], self.heap.elements) self.heap.change_priority(0, 1) self.assertEqual(1, self.heap.size) self.assertEqual([heap.HeapItem(1)], self.heap.elements)
def test_str_on_three_element_heap(self): self.heap.build([ heap.HeapItem(1, 'datum1'), heap.HeapItem(2, 'datum2'), heap.HeapItem(3, 'datum3') ]) self.assertEqual( '[[priority=3, datum=datum3], ' + '[priority=2, datum=datum2], ' + '[priority=1, datum=datum1]]', str(self.heap))
def test_insert_on_one_element_list(self): self.heap.build([heap.HeapItem(2)]) self.assertEqual(1, self.heap.size) self.assertEqual([heap.HeapItem(2)], self.heap.elements) self.heap.insert(heap.HeapItem(1)) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(1), heap.HeapItem(2)], self.heap.elements)
def test_repr_on_three_element_heap(self): self.heap.build([ heap.HeapItem(1, 'datum1'), heap.HeapItem(2, 'datum2'), heap.HeapItem(3, 'datum3') ]) self.assertEqual( '[mode=HeapMode.max, size=3, ' + 'list=[[priority=3, datum=datum3], ' + '[priority=2, datum=datum2], ' + '[priority=1, datum=datum1]]]', repr(self.heap))
def dijkstra_shortest_paths(self, graph, start): """ Finds the shortest paths between nodes in a graph, which may represent, for example, road networks. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later. """ distance_map, predecessor_map = \ self._create_distance_and_previous_maps(graph) distance_map[start] = 0 priority_queue = heap.BinHeap(heap.HeapMode.min) for node, value in distance_map.items(): priority_queue.insert(heap.HeapItem(value, node)) while priority_queue.size > 0: min_item = priority_queue.extract() node = min_item.datum for neighbor in graph.neighbors(node): if self._relax(graph, distance_map, predecessor_map, node, neighbor): index = self._index_in_priority_queue( priority_queue, neighbor) edge_distance = (distance_map[node] + graph.weight( (node, neighbor))) priority_queue.change_priority(index, edge_distance) return distance_map, predecessor_map
def test_constructor_with_priority_and_datum(self): priority = 123 datum = 'datum' item = heap.HeapItem(priority, datum) self.assertEqual(priority, item.priority) self.assertEqual(datum, item.datum)
def test_build_on_five_element_list(self): self.heap.build([ heap.HeapItem(9), heap.HeapItem(5), heap.HeapItem(6), heap.HeapItem(2), heap.HeapItem(3) ]) self.assertEqual(5, self.heap.size) self.assertEqual([ heap.HeapItem(2), heap.HeapItem(3), heap.HeapItem(6), heap.HeapItem(5), heap.HeapItem(9) ], self.heap.elements)
def prim(self, graph): """ Given a connected undirected graph G = (V, E) with positive edge weights, computes a minimum spanning tree that consists of a subset of edges E′ ⊆ E of minimum total weight such that the graph (V, E′) is connected. Greedy Strategy: Repeatedly attach a node to the current tree by the next lightest edge. Note: The graph must be really connected undirected. """ minimum_spanning_tree = Graph() if (len(graph.nodes()) == 0): return minimum_spanning_tree distance_map, predecessor_map = \ self._create_distance_and_previous_maps(graph) # pick any initial node (the graph must be connected) start = next(iter(graph.nodes())) distance_map[start] = 0 priority_queue = heap.BinHeap(heap.HeapMode.min) for node, value in distance_map.items(): minimum_spanning_tree.add_node(node) priority_queue.insert(heap.HeapItem(value, node)) while priority_queue.size > 0: min_item = priority_queue.extract() node = min_item.datum for neighbor in graph.neighbors(node): edge = (node, neighbor) edge_distance = graph.weight(edge) neighbor_index = self._index_in_priority_queue( priority_queue, neighbor) if (neighbor_index != None and distance_map[neighbor] > edge_distance): distance_map[neighbor] = edge_distance priority_queue.change_priority(neighbor_index, edge_distance) predecessor_map[neighbor] = node for node, value in predecessor_map.items(): if value != None: edge = (value, node) edge_distance = graph.weight(edge) minimum_spanning_tree.add_undirected_edge( value, node, edge_distance) return minimum_spanning_tree
def test_sort_on_sorted_five_element_list(self): list = [ heap.HeapItem(9), heap.HeapItem(8), heap.HeapItem(5), heap.HeapItem(4), heap.HeapItem(2) ] self.heap.sort_in_place(list) self.assertEqual([ heap.HeapItem(9), heap.HeapItem(8), heap.HeapItem(5), heap.HeapItem(4), heap.HeapItem(2) ], list) self.assertEqual(5, self.heap.size)
def test_insert_on_two_element_list(self): self.heap.build([heap.HeapItem(3), heap.HeapItem(2)]) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(3), heap.HeapItem(2)], self.heap.elements) self.heap.insert(heap.HeapItem(4)) self.assertEqual(3, self.heap.size) self.assertEqual( [heap.HeapItem(4), heap.HeapItem(2), heap.HeapItem(3)], self.heap.elements)
def test_build_on_three_element_list_as_3_2_1(self): self.heap.build([heap.HeapItem(3), heap.HeapItem(2), heap.HeapItem(1)]) self.assertEqual(3, self.heap.size) self.assertEqual( [heap.HeapItem(3), heap.HeapItem(2), heap.HeapItem(1)], self.heap.elements)
def test_sort_on_unsorted_four_element_list(self): list = [ heap.HeapItem(1), heap.HeapItem(2), heap.HeapItem(3), heap.HeapItem(4) ] self.heap.sort_in_place(list) self.assertEqual([ heap.HeapItem(4), heap.HeapItem(3), heap.HeapItem(2), heap.HeapItem(1) ], list) self.assertEqual(4, self.heap.size)
def test_build_on_three_element_list_as_2_1_3(self): data = [heap.HeapItem(2), heap.HeapItem(1), heap.HeapItem(3)] self.heap.build(data) self.assertEqual(3, self.heap.size) self.assertEqual( [heap.HeapItem(1), heap.HeapItem(2), heap.HeapItem(3)], self.heap.elements)
def test_change_priority_on_two_element_list_without_sift(self): self.heap.build([heap.HeapItem(9), heap.HeapItem(6)]) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(6), heap.HeapItem(9)], self.heap.elements) self.heap.change_priority(0, 1) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(1), heap.HeapItem(9)], self.heap.elements) self.heap.change_priority(1, 2) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(1), heap.HeapItem(2)], self.heap.elements)
def test_change_priority_on_two_element_list_with_sift_down_up(self): self.heap.build([heap.HeapItem(9), heap.HeapItem(6)]) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(6), heap.HeapItem(9)], self.heap.elements) self.heap.change_priority(0, 10) self.assertEqual(2, self.heap.size) self.assertEqual( [heap.HeapItem(9), heap.HeapItem(10)], self.heap.elements) self.heap.change_priority(1, 8) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(8), heap.HeapItem(9)], self.heap.elements)
def kruskal(self, graph): """ Given a connected undirected graph G = (V, E) with positive edge weights, computes a minimum spanning tree that consists of a subset of edges E′ ⊆ E of minimum total weight such that the graph (V, E′) is connected. Greedy Strategy: Repeatedly adds the next lightest edge if this doesn’t produce a cycle. Note: The graph does not have to be undirected. """ minimum_spanning_tree = Graph() set = union_find.UnionFind() node_to_wrapper_node_map = {} priority_queue = heap.BinHeap(heap.HeapMode.min) for node in graph.nodes(): minimum_spanning_tree.add_node(node) wrapper_node = union_find.Node(node) node_to_wrapper_node_map[node] = wrapper_node set.make_set(wrapper_node) for u, v in graph.edges(): edge = (node_to_wrapper_node_map[u], node_to_wrapper_node_map[v]) priority_queue.insert(heap.HeapItem(graph.weight((u, v)), edge)) while priority_queue.size > 0: min_item = priority_queue.extract() u_node, v_node = min_item.datum if set.find(u_node) != set.find(v_node): minimum_spanning_tree.add_undirected_edge( u_node.value, v_node.value, min_item.priority) set.union(u_node, v_node) return minimum_spanning_tree
def test_build_on_two_element_list_as_1_2(self): self.heap.build([heap.HeapItem(1), heap.HeapItem(2)]) self.assertEqual(2, self.heap.size) self.assertEqual([heap.HeapItem(2), heap.HeapItem(1)], self.heap.elements)
def test_eq_with_priority_as_not_equal(self): item = heap.HeapItem(123) other = heap.HeapItem(456) self.assertFalse(item == other) self.assertFalse(other == item)
def test_build_on_one_element_list(self): self.heap.build([heap.HeapItem(1)]) self.assertEqual(1, self.heap.size) self.assertEqual([heap.HeapItem(1)], self.heap.elements)
def test_lt_with_priority_as_equal(self): item = heap.HeapItem(123) other = heap.HeapItem(123) self.assertFalse(item < other) self.assertFalse(other < item)
def test_insert_on_four_element_list(self): self.heap.build([ heap.HeapItem(2), heap.HeapItem(3), heap.HeapItem(4), heap.HeapItem(5) ]) self.assertEqual(4, self.heap.size) self.assertEqual([ heap.HeapItem(2), heap.HeapItem(3), heap.HeapItem(4), heap.HeapItem(5) ], self.heap.elements) self.heap.insert(heap.HeapItem(1)) self.assertEqual(5, self.heap.size) self.assertEqual([ heap.HeapItem(1), heap.HeapItem(2), heap.HeapItem(4), heap.HeapItem(5), heap.HeapItem(3) ], self.heap.elements)
def test_sort_on_seven_element_list_with_duplicates(self): list = [ heap.HeapItem(9), heap.HeapItem(5), heap.HeapItem(4), heap.HeapItem(2), heap.HeapItem(5), heap.HeapItem(2), heap.HeapItem(8) ] self.heap.sort_in_place(list) self.assertEqual([ heap.HeapItem(9), heap.HeapItem(8), heap.HeapItem(5), heap.HeapItem(5), heap.HeapItem(4), heap.HeapItem(2), heap.HeapItem(2) ], list) self.assertEqual(7, self.heap.size)
def test_constructor_with_priority(self): priority = 123 item = heap.HeapItem(priority) self.assertEqual(priority, item.priority) self.assertEqual(None, item.datum)
def test_lt_with_priority_and_datum_as_not_equal(self): item = heap.HeapItem(123, 'datum1') other = heap.HeapItem(456, 'datum2') self.assertTrue(item < other) self.assertFalse(other < item)
def test_eq_with_priority_and_datum_as_equal(self): item = heap.HeapItem(123, 'datum') other = heap.HeapItem(123, 'datum') self.assertTrue(item == other) self.assertTrue(other == item)
def test_change_priority_on_five_element_list_with_sift_up(self): self.heap.build([ heap.HeapItem(3), heap.HeapItem(4), heap.HeapItem(5), heap.HeapItem(6), heap.HeapItem(9) ]) self.assertEqual(5, self.heap.size) self.assertEqual([ heap.HeapItem(3), heap.HeapItem(4), heap.HeapItem(5), heap.HeapItem(6), heap.HeapItem(9) ], self.heap.elements) self.heap.change_priority(3, 0) self.assertEqual(5, self.heap.size) self.assertEqual([ heap.HeapItem(0), heap.HeapItem(3), heap.HeapItem(5), heap.HeapItem(4), heap.HeapItem(9) ], self.heap.elements)