1. 程式人生 > >分治法解決選擇問題——找出第i小的元素

分治法解決選擇問題——找出第i小的元素

給出一組資料,返回第i小的元素,最常規的思路是遍歷找,或者排好序之後返回等,這裡介紹用分治法解決,用到之前快排裡的一個函式partition,為了把陣列分成兩部分,A[p,q-1]的元素都小於主元q, A[q+1,r]的元素都大於q, 所以只要比較i這個位置要落在哪一邊就好了
虛擬碼如下:

int Select(int *A, int p, int r, int i)//對陣列A[p,r]返回第i小的元素
{
    if(p==r)//只有一個元素
    return A[p];
    int q = Partition(A, p ,r);
    int k = q-p+1;//第一段的元素數
if(i==k)//正好是劃分的主元 return A[q]; else if(i<k)//落在前半部分 return Select(A,p,q-1,i); else return Select(A,q+1,r,i-k);//落在後半部分,找第i-k個,因為前面已經k個了 }

演算法期望是線性的O(n),有重複元素也可用
完整程式碼如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int Partition(int
*A, int p ,int r) { int x = A[r]; int i = p-1; for(int j = p;j<=r-1;j++) { if(A[j] <= x) { i++; swap(A[i],A[j]); } } swap(A[i+1],A[r]); return i+1; } int Select(int *A, int p, int r, int i) { if(p==r) return
A[p]; int q = Partition(A,p,r); int k = q-p+1; if(i==k) return A[q]; else if(i<k) return Select(A,p,q-1,i); else return Select(A,q+1,r,i-k); } int A[30000]; int main() { int n,ii; while(cin>>n>>ii) { for(int i = 1;i<=n;i++) cin>>A[i]; int ans = Select(A,1,n,ii); cout<<ans<<endl; } }