Heap
A heap is a complete binary tree, where every parent has a key greater than or equal to (max heap) or less than or equal to (min heap) its child’s key.
Properties
- Height of a heap with n nodes: log2(n)+1
- Except for the last level, i-th level has 2^(i-1) nodes.
- Left child’s index = parent’s index * 2
- Right child’s index = parent’s index * 2 + 1
- Parent’s index = Child’s index/2
Insertion (upheap)
- Insert the new element next to the last node
- Keep exchanging with its parent until it satisfies max/min heap condition
Time complexity: height of a heap, O(log2(n))
Deletion (downheap)
- Move the last element to the deleted node
- Keep exchanging with its larger (smaller) child until it satisfies max (min) heap condition
Time complexity: height of a heap, O(log2(n))
Heap sort
Sorting algorithm which utilize heap structure. For n elements,
- Add elements with upheap
- Delete and pop element with downheap. Popped element is saved to the sorted array
Time complexity: For each element, maximum number of upheap or downheap operation is equal to the tree height, O(log2(n)) Total complexity for n elements: O(nlog2(n))
Implementation
Array can represent heap elements.
class Heap:
'''
Max Heap
'''
def __init__(self):
self.list = [None] # to make root index 1
def show(self):
if len(self.list)==1:
print('Empty heap')
else:
print('List:',self.list)
h=int(np.log2(len(self.list)-1))+1
for i in range(h):
min_idx=2**i
max_idx=min(len(self.list),2**(i+1))
print('lvl {0}:'.format(i+1),self.list[min_idx:max_idx])
# END OF HEAP HELPER METHODS
def add(self, element):
# Add
self.list.append(element)
# Upheap
idx = len(self.list)-1
while idx//2 > 0:
child = self.list[idx]
parent = self.list[idx//2]
if parent < child:
self.list[idx] = parent
self.list[idx//2] = child
idx = idx//2
def delete(self):
if len(self.list)<2:
print('Empty heap')
else:
# Delete and Downheap
max_element=self.list[1]
#print("Remove: {0} from {1}".format(max_element, self.list))
self.list[1] = self.list[-1]
self.list.pop()
#print(self.list)
idx=1
# loop as long as left child exists
while idx*2<len(self.list):
larger_child_idx = None
# Get larger child index
if (idx*2+1)>=len(self.list):
# Only left child
larger_child_idx = idx*2
else:
left_child = self.list[idx*2]
right_child = self.list[idx*2+1]
if left_child>right_child:
larger_child_idx=idx*2
else:
larger_child_idx=idx*2+1
child = self.list[larger_child_idx]
parent = self.list[idx]
#print('hi',child,parent,self.list)
if parent<child:
self.list[idx]=child
self.list[larger_child_idx]=parent
#else:
#break
idx = larger_child_idx
#print(idx,len(self.list))
return max_element
def heap_sort(arr):
arr_sorted=[]
heap = Heap()
for i in arr:
heap.add(i)
heap.show()
while len(heap.list)>1:
max_element = heap.delete()
arr_sorted.insert(0, max_element)
return arr_sorted
print('Sorted:',heap_sort([2,5,8,3,10,6,9,4,1,7,11]))
print('Sorted:',heap_sort([10,9,8,7,6,5,4,3,2,1]))
print('Sorted:',heap_sort([1,2,3,4,5,6,7,8]))
Output:
List: [None, 11, 10, 9, 4, 8, 5, 6, 2, 1, 3, 7]
lvl 1: [11]
lvl 2: [10, 9]
lvl 3: [4, 8, 5, 6]
lvl 4: [2, 1, 3, 7]
Sorted: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
List: [None, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
lvl 1: [10]
lvl 2: [9, 8]
lvl 3: [7, 6, 5, 4]
lvl 4: [3, 2, 1]
Sorted: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
List: [None, 8, 7, 6, 4, 3, 2, 5, 1]
lvl 1: [8]
lvl 2: [7, 6]
lvl 3: [4, 3, 2, 5]
lvl 4: [1]
Sorted: [1, 2, 3, 4, 5, 6, 7, 8]
Leave a comment