BFPRT算法

BFPRT 算法

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

算法步驟

(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)的時間複雜度!!ui

實現代碼

#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)爲時間複雜度,則
這裏寫圖片描述spa

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

使用概括法,能夠獲得這裏寫圖片描述code

分析過程參考Median of medians排序

相關文章
相關標籤/搜索