Skip to content

Instantly share code, notes, and snippets.

@ox
Created March 17, 2020 05:11
Show Gist options
  • Save ox/2322c988fe9d45909a6bb697a6bbbdbe to your computer and use it in GitHub Desktop.
Save ox/2322c988fe9d45909a6bb697a6bbbdbe to your computer and use it in GitHub Desktop.
MinHeap implementation in python3
from random import shuffle
class MinHeap:
def __init__(self):
self.arr = []
def __len__(self):
return len(self.arr)
def __nth_child(self, i, n):
if i < 0 or i > len(self.arr):
return (None, None)
child_pos = i * 2 + n
if child_pos > len(self.arr) - 1:
return (None, None)
return (child_pos, self.arr[child_pos])
def __swap(self, a, b):
self.arr[a], self.arr[b] = self.arr[b], self.arr[a]
def left_child(self, i):
return self.__nth_child(i, 1)
def right_child(self, i):
return self.__nth_child(i, 2)
def add(self, value):
if not self.arr:
self.arr.append(value)
return
# add the value to the back of the list
self.arr.append(value)
position = len(self.arr) - 1
parent = (position - 1) // 2
# now compare it to it's parent and swap them if the parent is smaller than the new value
while parent >= 0 and self.arr[position] < self.arr[parent]:
self.arr[parent], self.arr[position] = self.arr[position], self.arr[parent]
position = parent
parent = (position - 1) // 2
def peek(self):
return self.arr[0] if self.arr else None
def pop(self):
if not self.arr:
return None
if len(self.arr) == 1:
return self.arr.pop()
# store the return value
value = self.arr[0]
# take last element and set it to the first
self.arr[0] = self.arr.pop()
# now swap the top element with the smallest of it's children while it's larger
# than them
pos = 0
while True:
curr = self.arr[pos]
(lpos, left) = self.left_child(pos)
(rpos, right) = self.right_child(pos)
if not left and not right:
return value
if left and right and (curr > left or curr > right):
self.__swap(pos, lpos if left < right else rpos)
pos = lpos if left < right else rpos
elif not right and curr > left:
self.__swap(pos, lpos)
return value
else:
return value
def verify(self):
for x in self.arr:
_, right = self.right_child(x)
_, left = self.left_child(x)
if right and right < x:
return False
if left and left < x:
return False
return True
if __name__ == "__main__":
arr = [55, 87, 2, 90, 7, 4, 50]
for i in range(25):
heap = MinHeap()
shuffle(arr)
for x in arr:
heap.add(x)
assert(heap.verify())
assert(heap.pop() == 2)
assert(heap.pop() == 4)
assert(heap.pop() == 7)
assert(heap.pop() == 50)
assert(heap.pop() == 55)
assert(heap.pop() == 87)
assert(heap.pop() == 90)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment