流求中位数

package day5;

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

/*
 * 问题:
 * 如何得到一个数据流中的中位数?
 * 如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。
 * 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
 * 
 * 思路:
 * 采用堆,一个大根堆,一个小根堆。(小根堆存放偏大得数,大根堆存放偏小的数)
 * 第一个数先读到大根堆中,
 * 后面的数,对比大根堆堆顶,如果小于等于堆顶放入大根堆,
 * 否则尝试放入小根堆,如果小根堆空,放入,否者对比小根堆堆顶,大于堆顶放入小根堆。否则放入大根堆。
 * 
 * 如果两个堆相差>1;取出堆顶,放到数目少的里面。
 * 
 */
public class Code04_MedianInDatastream {
    
    
    public static class MedianHolder{
        PriorityQueue<Integer> minHeap;
        PriorityQueue<Integer> maxHeap; 
        public MedianHolder(){
            this.minHeap = new PriorityQueue<>();
            this.maxHeap = new PriorityQueue<>(new MaxHeapComparator());
        }
        public void modify() {
            int count = maxHeap.size() - minHeap.size();
            if (Math.abs(count) >1) {
                if(count >0) {
                    minHeap.add(maxHeap.poll());
                }else {
                    maxHeap.add(minHeap.poll());
                }
            }
        }
        //naive!!!!!要考虑全面!!为空呢?
        
        public void add (int num) {
            if(maxHeap.isEmpty()) {
                maxHeap.add(num);
                return ;
            }
            if(num <= maxHeap.peek()) {//注意这里是小于大根堆堆顶
                maxHeap.add(num);
            }else {//否者尝试放入小根堆,尝试!!!尝试!!!
                if(minHeap.isEmpty()) {
                    minHeap.add(num);
                    return ;
                }
                if(num >= minHeap.peek()) {
                    minHeap.add(num);
                }else {
                    maxHeap.add(num);
                }
            }
            modify();
        }
        public Integer getMedian() {
            int maxHeapSize = maxHeap.size();
            int minHeapSize = minHeap.size();
            if (maxHeap.isEmpty() && minHeap.isEmpty()) {
                return null;
            }
            Integer maxHeapHead =  maxHeap.peek();
            Integer minHeadHead = minHeap.peek();
            if(((maxHeapSize + minHeapSize) & 1) == 0){
                return (maxHeapHead + minHeadHead)/2;
            }
            return minHeapSize > maxHeapSize ? minHeadHead :maxHeapHead;
        }
    }
    
    
    public static class MaxHeapComparator implements Comparator<Integer>{

        @Override
        public int compare(Integer o1, Integer o2) {
            // TODO Auto-generated method stub
            return o2 -o1;
        }

    
        
    }
    

    // for test
        public static int[] getRandomArray(int maxLen, int maxValue) {
            int[] res = new int[(int) (Math.random() * maxLen) + 1];
            for (int i = 0; i != res.length; i++) {
                res[i] = (int) (Math.random() * maxValue);
            }
            return res;
        }

        // for test, this method is ineffective but absolutely right
        public static int getMedianOfArray(int[] arr) {
            int[] newArr = Arrays.copyOf(arr, arr.length);
            Arrays.sort(newArr);
            int mid = (newArr.length - 1) / 2;
            if ((newArr.length & 1) == 0) {
                return (newArr[mid] + newArr[mid + 1]) / 2;
            } else {
                return newArr[mid];
            }
        }

        public static void printArray(int[] arr) {
            for (int i = 0; i != arr.length; i++) {
                System.out.print(arr[i] + " ");
            }
            System.out.println();
        }

        public static void main(String[] args) {
            boolean err = false;
            int testTimes = 200000;
            for (int i = 0; i != testTimes; i++) {
                int len = 30;
                int maxValue = 1000;
                int[] arr = getRandomArray(len, maxValue);
                MedianHolder medianHold = new MedianHolder();
                for (int j = 0; j != arr.length; j++) {
                    medianHold.add(arr[j]);
                }
                if (medianHold.getMedian() != getMedianOfArray(arr)) {
                    err = true;
                    printArray(arr);
                    System.out.println(medianHold.getMedian());
                    break;
                }
            }
            System.out.println(err ? "Oops..what a fuck!" : "today is a beautiful day^_^");

        }


}

 

posted @ 2019-09-08 23:05  白清欢  阅读(315)  评论(0编辑  收藏  举报