Skip to content

Instantly share code, notes, and snippets.

@giserh
Forked from gnarmis/minmaxheap.py
Last active August 29, 2015 14:07
Show Gist options
  • Save giserh/9160f27a1945a89825d0 to your computer and use it in GitHub Desktop.
Save giserh/9160f27a1945a89825d0 to your computer and use it in GitHub Desktop.

Revisions

  1. @gnarmis gnarmis created this gist Jan 27, 2013.
    225 changes: 225 additions & 0 deletions minmaxheap.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,225 @@
    from math import log, floor, pow


    class MinMaxHeap(object):
    """an implementation of min-max heap using an array,
    which starts at 1 (ignores 0th element)
    """

    def __init__(self, array=[]):
    super(MinMaxHeap, self).__init__()
    self.heap = [0]
    for i in array:
    self.Insert(i)

    def Insert(self, value):
    """place value at an available leaf, then bubble up from there"""
    self.heap = self.heap + [value]
    self.BubbleUp(len(self.heap) - 1)

    def DeleteAt(self, position):
    """delete given position"""
    self.heap[position] = self.heap[-1]
    del(self.heap[-1])
    self.TrickleDown(position)

    def Index(self, value):
    return self.heap.index(value)

    def PeekMax(self):
    if len(self.heap) > 1:
    return self.heap[1]
    else:
    raise Exception

    def PeekMin(self):
    size = len(self.heap)
    if size > 1:
    c = [self.heap[1]]
    if size >= 2:
    c = c + [self.heap[2]]
    if size >= 3:
    c = c + [self.heap[3]]
    return min(c)
    else:
    raise Exception

    def PopMax(self):
    m = self.PeekMax()
    mi = self.Index(m)
    self.DeleteAt(mi)
    return m

    def PopMin(self):
    m = self.PeekMin()
    mi = self.Index(m)
    self.DeleteAt(mi)
    return m

    def TrickleDown(self, position):
    """delete key at position"""
    if self.OnMinLevel(position):
    self.TrickleDownMin(position)
    else:
    self.TrickleDownMax(position)

    def TrickleDownMin(self, position):
    if self.HasChildren(position):
    min_pair = self.SortPairs(self.ChildrenAndGrandChildren(position))[0]
    m = min_pair[0] # index of smallest kid
    if self.IsGrandChild(position, m):
    if self.heap[m] < self.heap[position]:
    self.Swap(m, position)
    if self.heap[m] > self.heap[self.Parent(m)]:
    self.Swap(m, self.Parent(m))
    self.TrickleDownMin(m)
    # if not grandchild, m must be a child
    else:
    if self.heap[m] < self.heap[position]:
    self.Swap(m, position)
    else:
    pass

    def TrickleDownMax(self, position):
    if self.HasChildren(position):
    max_pair = self.SortPairs(self.ChildrenAndGrandChildren(position))[-1]
    m = max_pair[0] # index of smallest kid
    if self.IsGrandChild(position, m):
    if self.heap[m] > self.heap[position]:
    self.Swap(m, position)
    if self.heap[m] < self.heap[self.Parent(m)]:
    self.Swap(m, self.Parent(m))
    self.TrickleDownMax(m)
    # if not grandchild, m must be a child
    else:
    if self.heap[m] > self.heap[position]:
    self.Swap(m, position)
    else:
    pass

    def BubbleUp(self, position):
    if self.OnMinLevel(position):
    if self.HasParent(position):
    if self.heap[position] > self.heap[self.Parent(position)]:
    self.Swap(position, self.Parent(position))
    self.BubbleUpMax(self.Parent(position))
    else:
    self.BubbleUpMin(position)
    else:
    if self.HasParent(position):
    if self.heap[position] < self.heap[self.Parent(position)]:
    self.Swap(position, self.Parent(position))
    self.BubbleUpMin(self.Parent(position))
    else:
    self.BubbleUpMax(position)

    def BubbleUpMin(self, position):
    grandparent = self.Parent(self.Parent(position))
    if self.HasGrandParent(position):
    if self.heap[position] < self.heap[grandparent]:
    self.Swap(position, grandparent)
    self.BubbleUpMin(grandparent)

    def BubbleUpMax(self, position):
    if self.HasGrandParent(position):
    grandparent = self.Parent(self.Parent(position))
    if self.heap[position] > self.heap[grandparent]:
    self.Swap(position, grandparent)
    self.BubbleUpMax(grandparent)

    def Swap(self, a, b):
    """swap values between a and b"""
    a_val = self.heap[a]
    b_val = self.heap[b]
    self.heap[a] = b_val
    self.heap[b] = a_val

    def Parent(self, child):
    """return child's parent"""
    return int(child) / 2

    def IsGrandChild(self, parent, grand_child):
    """tell whether grand_child is parent's grandchild or not"""
    if self.HasGrandChildren(parent):
    size = len(self.heap)
    if grand_child < size:
    return True
    else:
    return False
    else:
    return False

    def SortPairs(self, list_of_pairs):
    """return 2-tuple representing smallest, sorted by value in second"""
    return sorted(list_of_pairs, key=lambda tup: tup[1])

    def ChildrenAndGrandChildren(self, position):
    """
    return list of children's and grandchildren's indices
    Don't call if position doesn't have children!
    """
    if self.HasChildren(position):
    a = []
    a = a + [(int(pow(2, position)), self.heap[int(pow(2, position))])]
    a = a + [(int(pow(2, position)) + 1, self.heap[int(pow(2, position)) + 1])]
    if self.HasChildren(int(pow(2, position))):
    cpos = int(pow(2, position))
    a = a + [(int(pow(2, cpos)), self.heap[int(pow(2, cpos))])]
    a = a + [(int(pow(2, cpos)) + 1, self.heap[int(pow(2, cpos)) + 1])]
    if self.HasChildren(int(pow(2, position)) + 1):
    cpos = int(pow(2, position)) + 1
    a = a + [(int(pow(2, cpos)), self.heap[int(pow(2, cpos))])]
    a = a + [(int(pow(2, cpos)) + 1, self.heap[int(pow(2, cpos)) + 1])]
    return a
    else:
    raise Exception

    def HasParent(self, position):
    p = self.Parent(position)
    if p is not 0:
    return True
    else:
    return False

    def HasGrandParent(self, position):
    gp = self.Parent(self.Parent(position))
    if gp is not 0:
    return True
    else:
    return False

    def HasChildren(self, position):
    """check if 2^position and 2^(position)+1 exist"""
    size = len(self.heap)
    if (pow(2, position) < size) or ((pow(2, position) + 1) < size):
    return True
    else:
    return False

    def HasGrandChildren(self, position):
    """check if either of position's children have children of their own"""
    if self.HasChildren(int(pow(2, position))) or \
    self.HasChildren(int(pow(2, position)) + 1):
    return True
    else:
    return False

    def OnMinLevel(self, position):
    """returns bool - is it on a min level?"""
    test = self.OnLevel(position) % 2
    if test == 0:
    return False
    else:
    return True

    def OnMaxLevel(self, position):
    """returns bool - is it on a max level?"""
    test = self.OnLevel(position) % 2
    if test == 0:
    return True
    else:
    return False

    def OnLevel(self, position):
    """returns what level the key at position is on"""
    return floor(log(int(position), 2))