如何使用 Python 堆实现动态中位数问题?
动态中位数问题即为在一个数列中,动态地插入和删除数字,求得数列的中位数。其中,中位数指的是有序数列中,中间位置的数字。如果数列长度为偶数,则中位数为中间两个数的平均值。
使用堆来实现动态中位数问题,需要维护两个堆:一个最大堆和一个最小堆。最大堆中存储的是数列中较小的一半数字,最小堆中存储的是数列中较大的一半数字。此时,如果两个堆的大小不同,则中位数为堆顶元素较多的那个堆的堆顶。如果两个堆的大小相同,则中位数为两个堆顶元素的平均值。
具体实现如下:
import heapq class DynamicMedian: def __init__(self): self.max_heap = [] # 最大堆,存储数列中较小的一半数字 self.min_heap = [] # 最小堆,存储数列中较大的一半数字 def insert(self, num): if not self.max_heap or num <= -self.max_heap[0]: heapq.heappush(self.max_heap, -num) else: heapq.heappush(self.min_heap, num) # 平衡两个堆的大小,使得差值不大于 1 if len(self.max_heap) - len(self.min_heap) > 1: temp = -heapq.heappop(self.max_heap) heapq.heappush(self.min_heap, temp) elif len(self.min_heap) - len(self.max_heap) > 1: temp = heapq.heappop(self.min_heap) heapq.heappush(self.max_heap, -temp) def find_median(self): # 两个堆中的元素个数相同时,中位数为两个堆顶元素的平均值 if len(self.max_heap) == len(self.min_heap): return (-self.max_heap[0] + self.min_heap[0]) / 2 # 否则中位数为堆顶元素较多的那个堆的堆顶 elif len(self.max_heap) > len(self.min_heap): return -self.max_heap[0] else: return self.min_heap[0] if __name__ == '__main__': median = DynamicMedian() nums = [5, 2, 3, 4, 1, 6, 7, 0, 8] for num in nums: median.insert(num) print('当前中位数为:', median.find_median())
输出结果如下:
当前中位数为: 5 当前中位数为: 3.5 当前中位数为: 3 当前中位数为: 3.5 当前中位数为: 3 当前中位数为: 3.5 当前中位数为: 4 当前中位数为: 3.5 当前中位数为: 4
如果需要使用字符串作为范例,可以将nums
列表中的数字改为字符串,例如nums = ['pidancode', 'com', 'python', 'heap', 'algorithm']
。
相关文章