1. 程式人生 > 其它 >【劍指offer中等部分26】資料流中得中位數(java)

【劍指offer中等部分26】資料流中得中位數(java)

技術標籤:劍指offer演算法java資料結構

題目描述

如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前讀取資料的中位數。

分析

這題挺難的,我是看了別人得文章,理解演算法後,再編了一遍。
關於大小頂堆概念見:https://www.cnblogs.com/lanhaicode/p/10546257.html

主要思路:
主要的思想是:因為要求的是中位數,那麼需要兩個堆,大頂堆用來存較小的數,小頂堆存較大的數,並且保證過程中大小頂堆中資料數目最多相差1,程式碼如下:

(仔細閱讀程式碼與註釋)

import java.util.TreeSet;
public class Solution {
    //注意此處要求小頂堆中最小的,都要大於等於大頂堆中最大的,如小頂堆[6,8,9],大頂堆[1,3,4]
    //保證大小頂堆中數字個數最多隻能相差1
    TreeSet<Integer> max = new TreeSet<Integer>();  //大頂堆,用於存放前面一半的元素(小的)
    TreeSet<Integer> min = new TreeSet<Integer>();  //小頂堆,用於存放後面一般的元素(大的)
public void Insert(Integer num) { if (((max.size() + min.size()) & 1) == 0) { //兩堆相加為偶數,即10,110,1110等,反正第一位不是0,所以&後得0 //num值大於小頂堆中最小的值,則小頂堆根節點值(最小值)放入小頂堆,如num=7,7>6,則將7加入小頂堆,再把6加入大頂堆 if (min.size() > 0 && num > min.first()) { min.add
(num); //值插入小頂堆中 num = min.first(); min.remove(num);//拿出小頂堆中的根節點值, } max.add(num); }else { //如小頂堆[7,8,9],大頂堆[1,3,4,6],num=5, 5<6,則將6加入小頂堆,變為[6,7,8,9],[1,3,4,5] if (max.size() > 0 && num < max.last()) { max.add(num); num = max.last(); max.remove(num); } min.add(num); } } public Double GetMedian() { int size = max.size() + min.size(); if (size == 0) { return 0.0; } if ((size & 1) == 0) { return (max.last() + min.first()) / 2.0; //偶數求和,如[6,7,8,9],[1,3,4,5]情況,取(5+6)/2.0 }else { return (double)max.last();//奇數,如小頂堆[7,8,9],大頂堆[1,3,4,6]情況,取6.0 } } }

在這裡插入圖片描述