剑指Offer——数据流中的中位数

题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

定义:1、最大堆:当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆。

          2、最小堆:当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆。

          3、平衡二叉树(AVL):平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

         4、二叉搜索树(二叉查找树):二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树

        5、红黑树:一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是红或黑(非红即黑)。通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍,因此,红黑树是一种弱平衡二叉树(由于是弱平衡,可以看到,在相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,它的旋转次数少,所以对于搜索,插入,删除操作较多的情况下,我们就用红黑树。

       6、B树,B+,B-树:

       B-树: B-tree树即B树,B即Balanced;B-tree就是指的B树,是一种多路搜索树(并不是二叉的);

       B+树:是对B-树的变体,也是一种多路搜索树:

各种数据结构复杂度对比:

时间复杂度对比
数据结构插入数据的时间复杂度得到中位数的时间复杂度
没有排序的数组O(1)O(n)
排序的数组O(n)O(1)
排序的链表O(n)O(1)
二叉搜索树平均O(logN),最差O(n)平均O(logN),最差(n)
AVL树O(logN)O(1)
最大堆和最小堆O(logN)O(1)

思路:用一个最大堆来实现左边数据的容器,用一个最小堆来实现右边数据的容器。往堆中插入一个数据的时间效率是O(logn)。

1、先把新的数据插入最大堆,接着把最大堆中的最大数字拿出来插入最小堆。

2、最终插入最小堆的数字是原最大堆中最大的数字。

import java.util.Comparator;
import java.util.PriorityQueue;

/**
 * 数据流中的中位数
 * @Author: AnNing
 * @Description:
 * @Date: Create in 17:35 2019/7/22
 */
public class Median {
    /* 大顶堆,存储左半边元素
     * 不指定Comparator,默认为小顶堆*/
    private PriorityQueue<Integer> left = new PriorityQueue<Integer>(11, new Comparator<Integer>(){
        @Override
        public int compare(Integer i1, Integer i2) {
            return i2-i1;
        }
    });
    /* 小顶堆,存储右半边元素,并且右半边元素都大于左半边 */
    private PriorityQueue<Integer> right = new PriorityQueue<Integer>();
    /* 当前数据流读入的元素个数 */
    private int N = 0;

    public void Insert(Integer val) {

        /* 插入要保证两个堆存于平衡状态 */
        if (N % 2 == 0) {
            /* N 为偶数的情况下插入到右半边。
             * 因为右半边元素都要大于左半边,但是新插入的元素不一定比左半边元素来的大,
             * 因此需要先将元素插入左半边,然后利用左半边为大顶堆的特点,取出堆顶元素即为最大元素,此时插入右半边 */
            left.add(val);
            right.add(left.poll());
        } else {
            right.add(val);
            left.add(right.poll());
        }
        N++;
    }

    public Double GetMedian() {
        if (N % 2 == 0)
            return (left.peek() + right.peek()) / 2.0;
        else
            return (double) right.peek();
    }
    
    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值