版权声明:本文为博主原创文章,可以转载,但转载前请联系博主。 https://blog.csdn.net/qq_33528613/article/details/84877604
长度为 n 的无序数组,求中位数,如何尽快的估算出中位数,算法复杂度是多少?
算法 1(建立最小堆):
如果数组中元素有奇数个,可以采用这种算法:
步骤 1 :可以将数组的前 (n+1)//2 个元素,建立 1 个最小堆;
步骤 2 :遍历剩余元素,如果剩余元素小于堆顶元素,则丢弃或不作处理;如果剩余元素大于堆顶元素,则将其取代堆顶元素,并将当前堆调整为最小堆。
步骤 3 :返回堆顶元素,即 nums[0],就是所要寻找的中位数。
一点解释:
不管是步骤 1、2 还是整个过程中,最小堆的栈顶元素必然满足:
中位数 >= 最小堆的堆顶元素
例如,[7,8,9,10,11,12,13] 中位数是 10 ,n 等于 7 ,(n+1)//2 等于 4 ,不管是取前 4 个数、后 4 个数、任意 4 个数,构造的最小堆的堆顶元素,最小为 7 ,最大为 10。
因此,小于堆顶元素的元素,必然不可能是中位数,可以直接丢弃;中位数只有可能在最小堆、剩余元素中。
实现:
# coding:utf-8
#from heap_sort import filter_down
def filter_up(nums, p, n):
parentIdx = p
rootVal = nums[parentIdx]
while 2*parentIdx+1 <= n-1:
kidIdx = 2*parentIdx+1
if kidIdx != n-1 and nums[kidIdx] > nums[kidIdx+1]:
kidIdx += 1
if rootVal < nums[kidIdx]:
break
else:
nums[parentIdx] = nums[kidIdx]
parentIdx = kidIdx
nums[parentIdx] = rootVal
def changeToMinHeap(nums, n):
''' 建立最小堆 '''
for index in range(n//2-1, -1, -1):
filter_up(nums, index, n)
def find_median(nums, n):
assert n%2 == 1
aboutHalf = (n+1)//2
changeToMinHeap(nums, aboutHalf)
pointer = aboutHalf
for index in range(aboutHalf, n):
if nums[index] > nums[0]:
nums[0] = nums[index]
changeToMinHeap(nums, aboutHalf)
return nums[0]
def test():
nums = list(range(4, 10)) + list(range(0, 4)) + list(range(10, 15))
print('nums:', nums)
assert find_median(nums, 15) == 7
print('Pass!')
if __name__ == '__main__':
test()
复杂度分析:
暂时略。。
参考文献:
算法 2 (建立最大堆、最小堆)
时间复杂度
O(n)