分治法解決選擇問題——找出第i小的元素
阿新 • • 發佈:2019-01-01
給出一組資料,返回第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;
}
}