算法思想:利用快速排序的方法将a[p:r]被划分成两个子数组a[p:i]和a[i+1:r],使a[p:i]中的每个元素都不大于a[i+1:r]中每个元素。接着算法计算子数组a[p:i]中元素个数j。如果k≤j,则第k小的数落在左区间,否则落在右区间,直到k=j时,找到第k小的数。
对于有重复数字的无法解决。其实维护小顶堆感觉更好,无论时间复杂度还是代码复杂程度。
int Partiotion(int a[], int p, int r) {
int i = p;
int j = r + 1;
int x = a[p];//划分的基准
while (true) {
while (a[++i] < x && i < r);//找到第一个比基准大的元素
while (a[--j] > x);//找到比基准大的元素
if (i >= j) {
break;
}
swap(a[i], a[j]);//交换两个位置不正确的元素
}
a[p] = a[j];
a[j] = x;
return j;
}
int RandomizedPartition(int a[], int p, int r) {//随机选择基准优化快速排序,区间对称性
int i = rand() % (p - r + 1) + p;
swap(a[i], a[p]);
return Partiotion(a, p, r);
}
int RandomizedSelect(int a[], int low, int high, int k) {
if (low == high) {
return a[low];
}
int i = Partiotion(a, low, high);
int j = i - low + 1;
if (k <= j) {
return RandomizedSelect(a, low, i, k);
}
else {
return RandomizedSelect(a, low+1, high, k-j);
}
}