def test_create_many(self): def is_invariant_node(i, my_heap): if i < 0 or i >= my_heap.size: raise IndexError(f"Index i should be between [0 and {my_heap.size})") if i != 0: pt = (i - 1) // 2 if my_heap.arr[pt] < my_heap.arr[i]: return False lf, rt = 2*i + 1, 2*i + 2 if lf >= my_heap.size: return True elif rt == my_heap.size: if my_heap.arr[lf] > my_heap.arr[i]: return False else: if my_heap.arr[i] < max(my_heap.arr[lf], my_heap.arr[rt]): return False return True def check_heap_inv(my_heap): is_invariant = True for i in range(my_heap.size): is_invariant = is_invariant and is_invariant_node(i, my_heap) return is_invariant n_cases = 100 n_nums = 50 for _ in range(n_cases): num_list = list(np.random.rand(n_nums)) h = Heap(num_list) self.assertTrue(check_heap_inv(h), "Heap invariant check failed")
def heapsort(arr): """ Implements heapsort O(n*log(n)) """ heap = Heap(arr) for i in range(heap.size - 1, 0, -1): heap.heap[0], heap.heap[heap.size - 1] = heap.heap[heap.size - 1], heap.heap[0] heap.size -= 1 heap.max_heapify(0) return heap.heap # Ordered array
def heap_sort(num_arr): """ Returns num_arr sorted in ascending fashion. The original array is not modified. Sorting is implemented using heap sort algorithm. The algorithm has O(n * log(n)) complexity. How it works: The array is put into max heap. The root of max heap is always the largest number. The sorting is done by repeated popping of the root. This implementation does not conserve the order of equal elements ("unstable sort"). """ hp = Heap(num_arr) result = [] while not hp.is_empty(): result.insert(0, hp.pop_max()) return result
def test_create(self): num_list = [1, 4, 7, 5, -3, 2, 8, 9] h = Heap(num_list) result = [9, 5, 8, 4, -3, 2, 7, 1] self.assertTrue(h.arr == result, f"Heap construction failed {h.arr}")