查找 n 个元素中第 k 小元素,其基本思路是对输入数组进行递归划分,模仿快排的算法,不同点在于,它只对划分出的子数组之一进行递归处理。可认为问题是在 O(n) 的时间内得到解决的。
此算法也比较常用于求中位数
#include<stdio.h>
#include<stdlib.h>
// 线性时间选择, 查找数组中第 k 小元素
// 基于快速排序算法,每次划分后只对其中一个子数组进行递归排序
#define Type int
Type a[10];
void Swap( Type &x, Type &y)
{
Type t;
t = x;
x = y;
y = t;
}
Type RandomizedPartion(Type a[], int p, int r)
{
int i = rand()%(r-p+1) + p, j = r+1;
Type x = a[i];
Swap(a[i], a[p]);
i = p;
while(1)
{
while(a[++i] < x && i < r)
{}
while(a[--j] > x && j > p)
{}
if(i >= j)
break;
Swap(a[i], a[j]);
}
a[p] = a[j]; // 只能这样做,假如不事先把 a[p] 单独拿出来,不然直接交换结束后,i 和 j 到底哪个指的是值为 x 的,是不确定的
a[j] = x;
return j;
}
Type RandomizedSelect(Type a[], int p, int r, int k)
{
if(p == r)
return a[p]; // 注意喽,函数返回值是第 k 小元素的值,不是位置==!
int i = RandomizedPartion(a, p, r);
int j = i - p + 1; // a[i] 是第 j 小的元素
if(k <= j) // 通过判断,只对子数组之一进行递归处理
return RandomizedSelect(a, p, i, k);
else
return RandomizedSelect(a, i+1, r, k-j);
}
int main()
{
int i;
printf("Please enter 10 elements:");
for( i = 0; i < 10; i++)
scanf("%d", &a[i]);
i = RandomizedSelect( a, 0, 9, 2);
printf("%d\n", i);
i = RandomizedSelect( a, 0, 9, 4);
printf("%d\n", i);
return 0;
}