数据流中的中位数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据流中的中位数相关的知识,希望对你有一定的参考价值。

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

 

解法一:

public class Median {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Median p = new Median();
        p.Insert(4);
        p.Insert(3);
        p.Insert(6);
        p.Insert(5);
        System.out.println(p.GetMedian());
    }

    List<Integer> t=new LinkedList<Integer>();//定义一个LinkedList,可以知道插入的顺序
    public void Insert(Integer num) {//该插入函数是将数值判断以后再插入,得到的数列是已经排序好的
        if (t.isEmpty()) t.add(num);//如果t为空,则不用判断直接插入
        else if (num<t.get(0)) t.add(0,num);//如果小于第一个数值,则插入到最前面
        else if (num>t.get(t.size()-1)) t.add(num);//如果大于最后一个数值,在直接插入(在最后)
        else 
            for (int i = 0; i < t.size(); i++) {//否则,是大于第一个值,小于最后值,插入的位置需要判断
                if (num>t.get(i)&&num<=t.get(i+1)){
                t.add(i+1,num);
                break;
            }
        }
         
    }
 
    public Double GetMedian() {
        int mid=t.size()/2;
        if (t.size()%2==1) return Double.valueOf(t.get(mid));
        else return (t.get(mid) + t.get(mid - 1)) / 2.0;
    }
 

}

解法二:

用Java中自带的工具类处理,更方便

public class Solution {
    ArrayList<Integer> list=new ArrayList<Integer>();
    public void Insert(Integer num) {
     list.add(num);
    }

    public Double GetMedian() {
        Collections.sort(list);//java自带的工具类可以实现排序
        int n=list.size();
        Double res=0.0;
        if(n%2==1){
           res= (Double)(list.get((n-1)/2)/2.0)*2.0;
        }
        if(n%2==0){
            res= (Double)((list.get(n/2-1)+list.get(n/2))/2.0);
        }
        return res;
    }
}

解法三:是从别人的代码中看到的,采用的是堆思想:

//解题思路就是用两个堆,一个大顶堆,一个小顶堆来过滤数据。
/**
* 插入有两种思路:
* 1:直接插入大堆中,之后若两堆尺寸之差大于1(也就是2),则从大堆中弹出堆顶元素并插入到小堆中
* 若两队之差不大于1,则直接插入大堆中即可。
* 2:奇数个数插入到大堆中,偶数个数插入到小堆中,
* 但是 可能会出现当前待插入的数比小堆堆顶元素大,此时需要将元素先插入到小堆,然后将小堆堆顶元素弹出并插入到大堆中
* 对于偶数时插入小堆的情况,一样的道理。why?
* 因为要保证最大堆的元素要比最小堆的元素都要小。
* @param num
*/

public void Insert(Integer num) {
    //若总尺寸为偶数,则插入大顶堆中
    if(((maxHeap.si敏感词Heap.size()) & 1) == 0){
        if(minHeap.size() != 0 && num > minHeap.peek()){
            minHeap.add(num);
            maxHeap.add(minHeap.pop());
        }else{
            maxHeap.add(num);
        }
    }else{
        if(maxHeap.size() != 0 && num < maxHeap.peek()){
            maxHeap.add(num);
            minHeap.add(maxHeap.pop());
        }else{
            minHeap.add(num);
        }
    }
}
public Double GetMedian() {
    double res = 0.0;
    if(((maxHeap.si敏感词Heap.size()) & 1) == 0){
        res = (maxHeap.peek() + minHeap.peek()) / 2.0;
    }else{
        res = maxHeap.peek();
    }
    return res;
}
}

//堆类,可直接设置最大堆最小堆

class Heap {
    public List<Integer> list = null;
    public static final boolean isMaxHeap = true;
    public static final boolean isMinHeap = false;
    private boolean flag = true;  //true表示最大堆,false表示最小堆
    public Heap(){
        this.list = new ArrayList<Integer>();
    }
    public Heap(boolean flag){
        this.list = new ArrayList<Integer>();
        this.flag = flag;
    }
    //获取堆大小
    public int size(){
        return this.list.size();
    }
    //获取堆顶元素
    public int peek(){
        if(list.size() == 0) return 0;
        return list.get(0);
    }
    //插入元素,从插入点开始向上调整堆
    public void add(int val){
        this.list.add(val);
        int i = list.size() - 1, index, parent, cur;
        while(i > 0){
            index = (i - 1) / 2;
            parent = list.get(index);
            cur = list.get(i);
            if(flag == true && parent < cur){
                swap(index, i);
            }else if(flag == false && parent > cur){
                swap(index, i);
            }
            i = index;
        }
    }
    /**
     * 将堆顶元素取出,并重新调整堆。
     * 1>取出堆顶元素
     * 2>将最后一个元素放到堆顶
     * 3>向下调整堆
     
    public int pop(){
        if(list.size() == 0) return -1;
        int res = list.get(0);
        list.set(0,list.get(list.size() - 1));
        list.remove(list.size()-1);
        int len = list.size() - 1 , i = 0;
        int left , right;
        while(i < len){
            left = (i << 1) + 1;
            right= (i << 1) + 2;
            int maxIndex = i;
            if(flag == true){
                if(left < len && list.get(left) > list.get(maxIndex)) maxIndex = left;
                if(right< len && list.get(right)> list.get(maxIndex)) maxIndex = right;
            }else{
                if(left < len && list.get(left) < list.get(maxIndex)) maxIndex = left;
                if(right< len && list.get(right)< list.get(maxIndex)) maxIndex = right;
            }
            if(maxIndex != i){
                swap(maxIndex,i);
                i = maxIndex;
            }else break;
        }
        return res;
    }
    //交换list中两个位置的元素
    public void swap(int i, int j){
        int temp = list.get(i);
        list.set(i, list.get(j));
        list.set(j,temp);
    }
}

 

以上是关于数据流中的中位数的主要内容,如果未能解决你的问题,请参考以下文章

剑指OFFER 数据流中的中位数

如何从 Firebase 获取数据到 Recyclerview 中的片段?

54. 数据流中的中位数

剑指 Offer 41. 数据流中的中位数

剑指 Offer 41 数据流中的中位数(优先队列堆排序)

片段中的Firebase数据不是持久的,会重新下载