刷题笔记21——(暴力、大小堆)求数据流的中位数

时间:2019-01-18
本文章向大家介绍刷题笔记21——(暴力、大小堆)求数据流的中位数,主要包括刷题笔记21——(暴力、大小堆)求数据流的中位数使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

解法1:暴力解

每进来一个都对它做排序,然后再求中位数

解法2:使用大小堆

这里使用STL中的优先队列,它底层是用堆实现的

测试结果及代码

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

void printArray(int a[], int N) {
    for (int i = 0; i < N; ++i) {
        cout << a[i] << " ";
    }
    // cout << endl;
}

void compare(vector<int> a) {
    vector<int> t;
    for (int i = 0; i < a.size(); ++i) {
        t.push_back(a[i]);
        sort(t.begin(), t.end());
        cout << "\n当前序列:";
        for (const auto &j : t) {
            cout << j << " ";
        }
        double res = 0;
        size_t sz = t.size();
        cout << ",size为:" << sz;
        if (sz % 2 == 1)
            res = t[sz / 2];
        else {
            int left = sz / 2 - 1;
            int right = sz / 2;
            res = 0.5 * (t[left] + t[right]);
        }
        cout << ",中位数为:" << res << endl;
    }
}

void printResult(const priority_queue<int, vector<int>, less<int>> &maxHeap, 
            const priority_queue<int, vector<int>, greater<int>> &minHeap) {

    priority_queue<int, vector<int>, less<int>> tp = maxHeap;
    priority_queue<int, vector<int>, greater<int>> tq = minHeap;
    cout << "\n当前序列:";
    vector<int> t;
    while (!tq.empty()) {
        t.push_back(tq.top());
        tq.pop();
    }
    
    while (!tp.empty()) {
        t.push_back(tp.top());
        tp.pop();
    }
    sort(t.begin(), t.end());
    auto it = t.begin();
    while (it != t.end()) {
        cout << *it << " ";
        it++;
    }
    cout << ",size为:" << t.size();
    t.clear();
}

void Insert(int num, 
            priority_queue<int, vector<int>, less<int>> &maxHeap, 
            priority_queue<int, vector<int>, greater<int>> &minHeap) {
    // p是大根堆,q是小根堆
    if (maxHeap.empty() || num <= maxHeap.top())
        maxHeap.push(num);
    else
        minHeap.push(num);
    
    if (maxHeap.size() == minHeap.size() + 2) {
        minHeap.push(maxHeap.top());
        maxHeap.pop();
    }
    if (minHeap.size() == maxHeap.size() + 2) {
        maxHeap.push(minHeap.top());
        minHeap.pop();
    }

    printResult(maxHeap, minHeap);
}

double getMedian(priority_queue<int, vector<int>, less<int>> &maxHeap,
                priority_queue<int, vector<int>, greater<int>> &minHeap) {
    int max_sz = maxHeap.size();
    int min_sz = minHeap.size();
    if (((max_sz + min_sz) & 1) == 0)
        return 0.5 * (maxHeap.top() + minHeap.top());
    if (max_sz > min_sz) {
        return maxHeap.top();
    }
    return minHeap.top();
}

void test(vector<int> a) {
    priority_queue<int, vector<int>, less<int>> maxHeap;
    priority_queue<int, vector<int>, greater<int>> minHeap;
    for (int i = 0; i < a.size(); ++i) {
        Insert(a[i], maxHeap, minHeap);
        cout << ",中位数为:" << getMedian(maxHeap, minHeap) << endl;
    }
}

int main (int argc, char* argv[]) {

    srand(time(NULL));
    // const int size = 5;           // 随机生成的数组大小
    const int test_time = 120;      // 测试次数
    vector<int> a;
    vector<int> tmp1;
    vector<int> tmp2;


    for (int cnt = 0; cnt < test_time; ++cnt) {
        int N = rand() % 10 + 1;
        cout << "\n第 " << cnt << " 次生成:";
        for (int i = 0; i < N; ++i) {
            a.push_back(rand() % 20 + 1);
            cout << a[i] << " ";
        }
        cout << endl;
        tmp1 = a;
        tmp2 = a;
        cout << "\n第 " << cnt << " 次对比:";

        compare(tmp1);
        // cout << "tmp1:";
        // for (const auto &j : tmp1) {
        //     cout << j << " ";
        // }
        // cout << endl;
        // cout << "tmp2:";
        cout << "\n第 " << cnt << " 次测试:";

        test(tmp2);
        // for (const auto &k : tmp2) {
        //     cout << k << " ";
        // }
        cout << endl;
        a.clear();
        tmp1.clear();
        tmp2.clear();
    }
   
    return 0;
}