实现1:
#include <iostream>
using namespace std;
int partition(int a[], int left, int right)
{
//从左、中、右3个元素中取中间值放在最右边
int mid = (right - left)/2;
if (a[left] > a[mid])
swap(a[left], a[mid]);
if (a[right] < a[left])
swap(a[right], a[left]);
if (a[right] > a[mid])
swap(a[right], a[mid]);
int i = left - 1;
for(int j = left; j < right; j++)
if (a[j] <= a[right])
swap(a[++i], a[j]);
swap(a[++i], a[right]);
return i;
}
int topk(int a[], int left, int right, int k)
{
if (left == right)
return a[left];
int mid = partition(a, left, right);
int cur = mid - left + 1;
if (cur == k)
return a[k - 1];
else if (k < cur)
return topk(a, left, mid - 1, k);
else
return topk(a, mid+1, right, k-cur);
}
int main()
{
int a[] = {1,2,3,4,5,6,7};
cout << topk(a, 0, 6, 3) << endl;
}
实现2:BFPRT
#include <iostream>
using namespace std;
void insertionSort(int a[], int left, int right)
{
int i, j;
for(i = left; i < right; i++){
int tmp = a[i+1];
for(j = i; j >= 0; j--){
if (a[j] > tmp)
a[j+1] = a[j];
else
break;
}
a[j+1] = tmp;
}
}
int partition(int a[], int l, int r, int pivotId) //对数组a下标从l到r的元素进行划分
{
//以pivotId所在元素为划分主元
swap(a[pivotId],a[r]);
int j = l - 1; //左边数字最右的下标
for (int i = l; i < r; i++)
if (a[i] <= a[r])
swap(a[++j], a[i]);
swap(a[++j], a[r]);
return j;
}
int BFPRT(int a[], int l, int r, int id) //求数组a下标l到r中的第id个数
{
if (r - l + 1 <= 5) //小于等于5个数,直接排序得到结果
{
insertionSort(a, l, r);
return a[l + id - 1];
}
int t = l - 1; //当前替换到前面的中位数的下标
for (int st = l, ed; (ed = st + 4) <= r; st += 5) //每5个进行处理
{
insertionSort(a, st, ed); //5个数的排序
t++; swap(a[t], a[st+2]); //将中位数替换到数组前面,便于递归求取中位数的中位数
}
int pivotId = (l + t) >> 1; //l到t的中位数的下标,作为主元的下标
BFPRT(a, l, t, pivotId-l+1);//不关心中位数的值,保证中位数在正确的位置
int m = partition(a, l, r, pivotId), cur = m - l + 1;
if (id == cur) return a[m]; //刚好是第id个数
else if(id < cur) return BFPRT(a, l, m-1, id);//第id个数在左边
else return BFPRT(a, m+1, r, id-cur); //第id个数在右边
}
int main()
{
int a[] = {2, 6, 3, 5, 4, 23, 56, 78};
cout << BFPRT(a, 0, 7, 6) << endl;
}