1. 程式人生 > 實用技巧 >演算法——中位數的問題

演算法——中位數的問題

給定一個問題:依次輸入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; }