1. 程式人生 > 實用技巧 >資料流中的中位數

資料流中的中位數

題目描述

如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。

思路

  1. 思路一:

維護一個數組,每次加入後,進行排序,當總元素個數為奇數時,中位數就是陣列中間的元素;當總元素個數為偶數時,中位數就是陣列中間元素和前一個元素的平均數。

  1. 思路二:

    維護一個大頂堆,一個小頂堆,且保證兩點:
    小頂堆裡的元素全大於大頂堆裡的元素;
    兩個堆個數的差值小於等於1;
    當insert的數字個數為奇數時:使小頂堆個數比大頂堆多1;當insert的數字個數為偶數時,使大頂堆個數跟小頂堆個數一樣;
    當總元素個數為奇數時,中位數就是小頂堆堆頂;當總元素個數為偶數時,中位數就是兩個個堆堆頂平均數。

程式碼實現

package Tree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.PriorityQueue;

/**
 * 資料流中的中位數
 * 如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。
 * 如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。
 */

public class Solution43 {
    ArrayList<Integer> list = new ArrayList<>();
    // 大頂堆
    PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);
    // 小頂堆,並且大頂堆元素都大於小頂堆
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    // 當前資料流讀入的元素個數
    int N = 0;

    public static void main(String[] args) {
        Solution43 solution43 = new Solution43();
        solution43.Insert_2(3);
        System.out.println(solution43.GetMedian_2());
        solution43.Insert_2(4);
        System.out.println(solution43.GetMedian_2());
    }

    /**
     * 維護兩個堆,一個大頂堆、一個小頂堆
     *
     * @param val
     */
    public void Insert_2(Integer num) {
        // 插入要保證兩個堆存於平衡狀態
        if (N % 2 == 0) {
            // N 為偶數的情況下插入到小頂堆。
            // 因為大頂堆元素都要大於小頂堆,但是新插入的元素不一定比小頂堆元素來的大,
            // 因此需要先將元素插入小頂堆,然後利用小頂堆為大頂堆的特點,取出堆頂元素即為最大元素,此時插入大頂堆
            maxHeap.offer(num);
            minHeap.offer(maxHeap.poll());
        } else {
            minHeap.offer(num);
            maxHeap.offer(minHeap.poll());
        }
        N++;
    }

    public Double GetMedian_2() {
        if (N % 2 == 0) {
            return (maxHeap.peek() + minHeap.peek()) / 2.0;
        } else {
            return (double) minHeap.peek();
        }
    }
//---------------------------------------------------------------------------------------------------------------------------------------------

    /**
     * 維護陣列,加入時排序
     *
     * @param num
     */
    public void Insert(Integer num) {
        list.add(num);
        Collections.sort(list);
    }

    public Double GetMedian() {
        int n = list.size();
        if (n % 2 == 0) {
            return Double.valueOf((list.get(n / 2) + list.get(n / 2 - 1)) / 2.0);
        } else {
            return Double.valueOf(list.get(n / 2));
        }
    }
}

參考連結

https://group.cnblogs.com/topic/79227.html