# Defines a class to manage a list of values with the following operations:
# - add a value in logarithmic time complexity;
# - delete the smallest value, delete the largest value in constant time complexity;
# - return the median in constant time complexity.
#
# Written by Eric Martin for COMP9021

from priority_queue import *

class Median:
    def __init__(self):
        # To store the first half of the values, the largest of which is of highest priority
        self.max_pq = MaxPriorityQueue()
        # To store the second half of the values, the smallest of which is of highest priority
        self.min_pq = MinPriorityQueue()

    def nb_of_elements(self):
        return len(self.max_pq) + len(self.min_pq)

    def median(self):
        if len(self.max_pq) > len(self.min_pq):
            return self.max_pq.top_priority()
        if len(self.min_pq) > len(self.max_pq):
            return self.min_pq.top_priority()
        return (self.max_pq.top_priority() + self.min_pq.top_priority()) / 2

    def insert(self, element):
        # Do not bother with two many cases in case we are adding the second element:
        # let it join the side with the first element and let rebalance() make sure
        # that both elements end up on the correct side.       
        if self.max_pq.top_priority() == None:
            self.min_pq.insert(element)
            self._rebalance()
        elif self.min_pq.top_priority() == None:
            self.max_pq.insert(element)
            self._rebalance()
        elif element < self.max_pq.top_priority():
            self.max_pq.insert(element)
            self._rebalance()
        elif element > self.min_pq.top_priority():
            self.min_pq.insert(element)
            self._rebalance()
        # In both cases, "element" is equal to the largest element from the first half
        # and to the smallest element from the second half, so it can join either side.
        # We chose a side so as to avoid rebalance.
        elif len(self.max_pq) <= len(self.min_pq):
            self.max_pq.insert(element)
        else:
            self.min_pq.insert(element)
            
    def _rebalance(self):
        if len(self.min_pq) > len(self.max_pq) + 1:
            self.max_pq.insert(self.min_pq.delete_top_priority())
        elif len(self.max_pq) > len(self.min_pq) + 1:
            self.min_pq.insert(self.max_pq.delete_top_priority())

if __name__ == '__main__':
    L = [2, 1, 7, 5, 4, 8, 0, 6, 3, 9]
    values = Median()
    for e in L:
        values.insert(e)
        print(values.median(), end = ' ')
    print()
        

Resource created Monday 26 October 2015, 11:21:53 AM.

file: question_1.py


Back to top

COMP9021 15s2 (Principles of Programming) is powered by WebCMS3
CRICOS Provider No. 00098G