剑指offer-面试题64:数据流中的中位数

题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是就是所有数值排序后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

思路:问题本身不难,关键在于采取哪种数据结构和算法。(1)如果用未排序的数组实现,那么插入的时间复杂度为O(1),查找的时间复杂度为O(n)(半快速排序法);(2)如果是排序的数组,那么插入的时候要维护顺序,插入的时间开销要大一些,为O(n),查找时间复杂度为O(1)。(3)用排序的链表实现,时间复杂度和排序的数组情况完全一样;(4)二叉搜索树可以使插入操作更快一点,时间复杂度为O(logn),查找操作为O(logn)。但是在树极度不平衡的情况下这两种操作时间复杂度都是O(n)。(5)还可以用AVL树实现(说实话关于AVL树现在脑子里已经是一片空白,实现起来太复杂)。

    作者用到的方法非常巧妙,注意到我们只需要位于中间的两个数就可以得出中位数,当元素个数为奇数个时可以看成这两个数一样。中位数在前半部分它是最大的,右半部分是最小的。我们只要始终知道前半部分数里的最大的那个数,后半部分里那个最小的数就可以了,其他的不用关心。这明显是堆的功用,前半部分用一个最大堆,后半部分建一个最小堆。中位数要保持两个堆的数目之差不超过1.为了实现平均分配,可以在数据的总数目是偶数时把新数据插入到最小堆中,否则插入最大堆中。

    另一个问题是保持最大堆的所有数据都小于最小堆中的数据。如果插入一个数使得总数目和为偶数,根据之前的原则应该插入最小堆中,但是新插入的元素可能比最大堆中的元素小怎么办?这就违反了最小堆的数据一定大于最大堆得原则。实际上这里插入的元素应该是新元素和最大堆中所有元素的最大值,最大堆正好有返回一个最大值的作用,所以新插入的元素先插入最大堆,然后取出最大值再插入最小堆中。如果插入元素使得数据总数目和为奇数,处理方法类似。

    代码很简单,只是注意一下堆的实现,对于动态的数据可以用vector来保存,堆的操作最重要的就是上滤和下滤,可以自己实现,也可以用STL里的heap来实现,heap操作见:

http://blog.csdn.net/moses1213/article/details/51332599

你可能感兴趣的:(剑指offer)