1. 程式人生 > >BFPRT(中位數的中位數)演算法

BFPRT(中位數的中位數)演算法

BFPRT 演算法

又稱為 “中位數的中位數演算法”,該演算法由 Blum、Floyd、Pratt、Rivest、Tarjan 在1973年提出,最壞時間複雜度為 O(n),最差的空間複雜度為O(logn)

演算法步驟

(1):將 n 個元素劃分為 ⌊n/5⌋ 個組,每組 5 個元素,若有剩餘,捨去;
(2):使用排序方法找到 ⌊n/5⌋ 個組中每一組的中位數;
(3):對於(2)中找到的所有中位數,遞迴(1)(2)查詢中位數的中位數,作為Partition劃分過程的主元
(4):進行Partition劃分,即一次快排
(5):判斷主元的位置與 k 的大小,有選擇的對左邊或右邊遞迴。

演算法應用

BFPRT演算法的一個經典應用就是TOP-K問題,即在一組資料中尋找第K大或第K小的元素。
這類問題可以分為對資料完全排序,部分排序和不排序。
完全排序情況下可以使用快速排序等排序方法能達到O(nlogn)的時間複雜度。
部分排序可以使用氣泡排序,選擇排序等方法也能達到O(kn)的時間複雜度。
不排序的情況可以使用堆排序的方法,時間複雜度為O(nlogk)
而BFPRT演算法解決這類問題能達到O(n)的時間複雜度!!

實現程式碼

#include <iostream>
#include <algorithm>
using namespace
std; int array[]={1,12,3,4,1,5,2,7,8,88,5,2,32,1,35,-1,7,5,38,-11}; // 插入排序,返回中位數下標 int insertSort(int left,int right){ for(int i=left+1;i<=right;i++){ int temp=array[i],j; for(j=i;j>left&&array[j-1]>temp;j--) array[j]=array[j-1]; array[j]=temp; } return
(left+right)>>1; } int BFPRT(int,int,int); //返回中位數的中位數的下標 int getPivotIndex(int left,int right){ if(right-left<5) return insertSort(left,right); int back=left-1; for(int i=left;i+4<right;i+=5){ int index=insertSort(i,i+4); swap(array[++back],array[index]); } return BFPRT(left,back,((left+back)>>1)+1); } //一趟快排 int partition(int left,int right,int pivotIndex){ swap(array[right],array[pivotIndex]); int mid=left; for(int i=left;i<right;i++){ if(array[i]<array[right]) swap(array[i],array[mid++]); } swap(array[right],array[mid]); return mid; } int BFPRT(int left,int right,int k){ int pivotIndex=getPivotIndex(left,right); int mid=partition(left,right,pivotIndex); int count=mid-left+1; if(count==k){ return mid; }else if(count>k){ return BFPRT(left,mid-1,k); } else{ return BFPRT(mid+1,right,k-count); } } int main(){ int k=5; int length=sizeof(array)/sizeof(array[0]); for(int i=0; i<length; i++) { cout<<array[i]<<" "; } cout<<endl<<"第"<<k<<"小為:"; cout<<array[BFPRT(0,length-1,k)]<<endl; return 0; }

演算法複雜度分析

中位數的遞迴呼叫不超過最壞的線性情況,因為中位數列表是整個列表大小的20%,而其他的遞迴呼叫列表的最多70%,令T(n)為時間複雜度,則
這裡寫圖片描述

  • T(2n/10)部分是查詢⌊n/5⌋ 的中位數中的中位數,通過執行單獨的Quickselect
  • T(7n/10)部分是實際的Quickselect遞迴
  • O(n) 部分 c·n 是創造分界,其中的一邊遞迴進行Quickselect

使用歸納法,可以得到這裡寫圖片描述