题目
如何得到一个数据流中的中位数?如果数据流中读出奇数个值,那么中位数就是所有
数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值
排序后中间两个数的平均值。
思路
关键在于选择合适的数据结构,使得求中位数和插入元素的时间复杂度尽可能小。
- 乱序数组:新数据插入数组后方,求中位数时排序。
- 排序数组:排序插入数组,中位数返回中间值。
- 二叉搜索树:添加属性表示子树的节点数,求中位数即寻找子树节点数为总结点数一半的节点。
- AVL树:使左右树节点差保持平衡,根节点就是中位数。
- 最大堆+最小堆:用最大堆维护数组中较小的半部分,最小堆维护较大的半部分。奇数时,中位数时最小堆的顶,偶数时,两个堆顶的平均值。
数据结构 | 插入时间复杂度 | 求中位数时间复杂度 |
---|---|---|
乱序数组 | O(1) | O(n) |
排序数组 | O(n) | O(1) |
二叉搜索树 | 平均O(logn),最差O(n) | 平均O(logn),最差O(n) |
AVL树 | O(logn) | O(1) |
最大堆+最小堆 | O(logn) | O(1) |
代码
思路5:插入时间复杂度:O(logn),求中位数时间复杂度:O(1)
def stream_median(stream):
"""
:param stream: list
:return:None
"""
from datstru import Heap
class StreamList(object):
"""
extended heap data structure
"""
def __init__(self):
self.left = Heap() # big top
self.right = Heap(cmp = lambda x,y:x < y) # small top
def insert(self, n):
if len(self) % 2:
if self.right and n > self.right.top():
self.right.insert(n)
self.left.insert(self.right.pop())
else:
self.left.insert(n)
else:
if self.left and n < self.left.top():
self.left.insert(n)
self.right.insert(self.left.pop())
else:
self.right.insert(n)
return
def get_median(self):
if len(self) % 2:
return self.right.top()
else:
return (self.left.top() + self.right.top()) / 2
def __len__(self):
return len(self.left) + len(self.right)
con = StreamList()
for n in stream:
con.insert(n)
print(con.get_median())
return
思考
- AVL树没有实现过,下次实现一下。