I've written a min-max heap, i.e. an heap where finding the minimum and the maximum are constant operations. Now I want to create tests for my class, so I decided to implement a function that checks if a heap is a min-max-heap. Here it is, but I'm not sure it's 100% correct.
def is_min_max_heap(h):
if not isinstance(h, MinMaxHeap):
return False
if h.heap:
for item in h.heap:
if not isinstance(item, HeapNode):
return False
for i, item in reversed(list(enumerate(h.heap))):
g = h.grandparent_index(i)
if g is not None:
if h.is_on_even_level(i):
if h.heap[g] > item:
return False
else:
if h.heap[g] < item:
return False
return True
Note that elements of this heap are represented with the class HeapNode
, and that's why I am checking if self.heap
only contains objects of that class. Even levels are for example 0, 2, 4, etc. The minimum of this heap is found at self.heap[0]
. The maximum is max(self.heap[1], self.heap[2])
(provided that both exist). h.grandparent_index(i)
returns None
if the grandparent of the node at i
does not exist.
The idea of my algorithm is very simple. I start from the bottom, and I check if I'm on an even of odd level. If on an even level, then I must make sure that the element is greater than its grandparent. If I'm on a odd level, I must make sure it's smaller than its grandparent.
Is my algorithm correct? Am I missing some points? If it's correct, suggestions to improve it are well-accepted.
Eventually my implementation might be useful for someone else.
Edit 1
I've just noticed that my function checks if the elements in the even (and respectively odd) levels are correctly disposed to each other, but it does not check if the maximum element is found either at self.heap[1]
or self.heap[2]
and that the minimum element is at self.heap[0]
.
Edit 2
I'm adding the new updated code according to edit 1 and to the answer of @goCards.
def is_min_max_heap(h) -> bool:
"""Returns `True` if `h` is a valid `MinMaxHeap` object. `False` otherwise."""
if not isinstance(h, MinMaxHeap):
return False
if h.heap:
for item in h.heap:
if not isinstance(item, HeapNode):
return False
if h.size() == 1:
return True
if h.size() == 2:
return max(h.heap) == h.heap[1] and min(h.heap) == h.heap[0]
if h.size() >= 3:
if (h.heap[0] != min(h.heap) or
(h.heap[1] != max(h.heap) and
h.heap[2] != max(h.heap))):
return False
for i, item in reversed(list(enumerate(h.heap))):
p = h.parent_index(i)
if p != -1:
if h.is_on_even_level(i):
if h.heap[p] < item:
return False
else:
if h.heap[p] > item:
return False
g = h.grandparent_index(i)
if g != -1:
if h.is_on_even_level(i):
if h.heap[g] > item:
return False
else:
if h.heap[g] < item:
return False
return True