算法——中位数的问题

给定一个问题:依次输入n个整数a1,a2,a3,...,an,输出b1,b2,b3,...,bn,其中bi表示a1,a2,a3,...,ai的中位数。

暴力解法:对于输入的ai,保证a1,a2,a3,...,ai-1有序,找到ai的正确位置插入,复杂度为O(n2)。

双堆解法:我们知道利用小顶堆的结构可以以O(nlogk)的时间复杂度计算n个数中的第k大的数。

  • 因此在这个问题中可以维护一个大顶堆和一个小顶堆,大顶堆保存最小的i/2个数,堆顶为A,小顶堆保存最大的i/2个数,堆顶为B;
  • 对于ai,若ai<A,则交换这两个元素,若ai>B,则交换这两个元素,得到的新ai'一定定满足A'<= ai' <=B';
  • 若大顶堆和小顶堆元素数量相等,则中位数为ai',并将ai'加入大顶堆中;
  • 若大顶堆元素数量多于小顶堆,则中位数为(ai'+A')/2,并将ai’加入小顶堆中;

该解法的算法复杂度为O(nlogn),基于c++的algorithm中的pop_heap和push_heap方法,实现代码示例如下:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

bool cmp_greater(const int& a, const int& b){ return a > b; }
bool cmp_less(const int& a, const int& b){ return a < b; }

void push(vector<int>& heap, int val, bool big){
    auto cmp = big ? cmp_less : cmp_greater;
    heap.push_back(val); 
    push_heap(heap.begin(), heap.end(), cmp);
}

void pop(vector<int>& heap, bool big){
    auto cmp = big ? cmp_less : cmp_greater;
    pop_heap(heap.begin(), heap.end(), cmp);
    heap.pop_back();
}

int main(){
    int n, val, tmp;
    vector<int> medians;
    vector<int> heap_big; // 存放前i个元素最小的i/2个 
    vector<int> heap_sml; // 存放前i个元素最大的i/2个 
    int A, B;             // A为heap_big堆顶,B为heap_sml堆顶
    
    cin >> n;
    if(n <= 0) return 0;
    if(n <= 1){
        cin >> val;
        cout << val << endl;
        return 0;
    }
    
    // 前两个数 
    cin >> val >> tmp;
    if(val > tmp){
        heap_big.push_back(tmp);
        heap_sml.push_back(val);
    }
    else{
        heap_big.push_back(val);
        heap_sml.push_back(tmp);
    }
    medians.push_back(val);
    medians.push_back((val + tmp) / 2);
    
    // 从第三个数开始 
    for(int i = 2; i < n; i++){
        cin >> val;
        A = heap_big[0];
        B = heap_sml[0];
        
        // 若是比最小的i/2个数中最大的小,则交换 
        if(val < A){
            pop(heap_big, true);
            push(heap_big, val, true);
            val = A;
            A = heap_big[0]; 
        }
        
        // 若是比最大的i/2个数中最小的大,则交换 
        else if(val > B){
            pop(heap_sml, false);
            push(heap_sml, val, false);
            val = B;
            B = heap_sml[0];
        }
        
        if(heap_big.size() == heap_sml.size()){
            medians.push_back(val);
            push(heap_big, val, true); 
        }
        else{
            medians.push_back((A + val) / 2);
            push(heap_sml, val, false);
        }  
    }
    
    for(int i = 0; i < medians.size(); i++){
        cout << medians[i] << " ";
    }
    cout << endl;
    return 0; 
} 

 

posted @ 2020-08-01 12:22  huochaitiantang  阅读(317)  评论(0编辑  收藏  举报