zoukankan      html  css  js  c++  java
  • 数据流中的中位数

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

    解法一:

    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);
        }
    }
  • 相关阅读:
    python的模块future用法实例解析
    strcmp函数和memcmp函数的用法区别及联系
    esp8266 smartconfig-智能配网分析和使用及注意事项
    ubuntu 18.04 安装并配置adb
    Markdown的常用方法总结
    mac下使用minicom几个注意事项
    最强Linux shell工具Oh My Zsh 指南
    ESP8266源码分析--打印的基本用法
    atom 在Ubuntu 18.04 上安装及基本使用
    ubuntu 查看端口被占用并删除端口
  • 原文地址:https://www.cnblogs.com/tjuxqcui/p/5541877.html
Copyright © 2011-2022 走看看