Continuous Median

refer to: https://www.algoexpert.io/questions/Continuous%20Median


Problem statement

Analysis

O(N) for insert one number into a sorted array

Code

def MAX_HEAP_FUNC(a, b):
        return a > b
    
def MIN_HEAP_FUNC(a, b):
        return a < b

class ContinuousMedianHandler:
    def __init__(self):
        self.lowers = Heap(MAX_HEAP_FUNC, []) #create a maxheap for lower half of the numbers
        self.greaters = Heap(MIN_HEAP_FUNC, []) #create a minheap for greater half of the numbers
        self.median = None

    def insert(self, number): 
        if not self.lowers.length or number < self.lowers.peek():#empty lower heap or the new number < the peek of the lower maxheap
            self.lowers.insert(number)
        else:
            self.greaters.insert(number)
        self.rebalanceHeaps() # balance the lower and greater heaps, make sure the different between their lengths <= 1
        self.updateMedian() #update new median value
        
    def rebalanceHeaps(self):
        if self.lowers.length - self.greaters.length == 2: # lower heap has more values
            self.greater.insert(self.lowers.remove())# remove the peek(max value) of the lower heap into the greater heap
        elif self.greaters.length - self.lowers.length == 2:
            self.lowers.insert(self.greaters.remove())
    def updateMedian(self): 
        if self.lowers.length == self.greaters.length: # same length, the two mid values are peeks of low and great heaps
            self.median = (self.lowers.peek() + self.greaters.peek())/2
        elif self.lowers.length > self.greaters.length: # lower heap has more one valye, the peek one of lower heap
            self.median = self.lowers.peek()
        else: # higher heap has more one value
            self.median = self.greaters.peek()
    def getMedian(self):
        return self.median

Time and space complexity

time: log(n) time for insert, remove in heaps.

space: store all the numbers in heap->O(N)

The Heap class

class Heap:
    def __init__(self, comparisonFunc, array):
        self.comparisonFunc = comparisonFunc
        self.heap = self.buildHeap(array)
        self.length = len(self.heap)
    def buildHeap(self, array):
        firstParentIdx = (len(array) - 2) //2
        for currentIdx in reversed(range(firstParentIdx + 1)):
            self.siftDown(currentIdx, len(array) - 1, array)
        return array
    def siftDown(self, currentIdx, endIdx, heap):
        childOneIdx = currentIdx *2 + 1
        while childOneIdx <= endIdx:
            childTwoIdx = currentIdx * 2 + 2 if currentIdx * 2 + 2 <= endIdx else - 1
            if childTwoIdx != -1:
                if self.comparisonFunc(heap[childTwoIdx], heap[childOneIdx]):
                    idxToSwap = childTwoIdx
                else:
                    idxToSwap = childOneIdx
            else:
                idxToSwap = childOneIdx
            if self.comparisonFunc(heap[idxToSwap], heap[currentIdx]):
                self.swap(currentIdx, idxToSwap, heap)
                currentIdx = idxToSwap
                childOneIdx = currentIdx * 2 + 1
            else:
                return
    
    def siftUp(self, currentIdx, heap):
        parentIdx = (currentIdx - 1) // 2
        while currentIdx > 0:
            if self.comparisonFunc(heap[currentIdx], heap[parentIdx]):
                self.swap(currentIdx, parentIdx, heap)
                currentIdx = parentIdx
                parentIdx = (currentIdx - 1) // 2
            else:
                return
    
    def peek(self):
        return self.heap[0]

    
    def remove(self):
        self.swap(0, self.length - 1, self.heap)
        valueToRemove = self.heap.pop()
        self.length -= 1
        self.siftDown(0, self.length - 1, self.heap)
        return valueToRemove
    
    def insert(self, value):
        self.heap.append(value)
        self.length += 1
        self.siftUp(self.length - 1, self.heap)
        
    def swap(self, i, j, array):
        array[i],array[j] = array[j], array[i]
        
原文地址:https://www.cnblogs.com/LilyLiya/p/14869578.html