通过全部排序O(nlogn),部分排序O(nk),用堆代替数组O(nlogk)都可以完成
还可以通过线性选择算法:O(n)
选取数组S中一个元素作为主元(pivot)v,将集合S-{v}分割成Sa和Sb,就像快速排序那样:
1)如果k <= |Sa|,那么第k个最小的元素必然在Sa中,这时,返回QuickSelect(Sa,k);
2)如果k=1+|Sa|,那么主元就是第k个最小元素,即找到,直接返回它;
3)否则,这第k个最小元素就在Sb中,即Sb中的第k-|Sa|-1个最小元素,我们递归调用QuickSelect(Sb,k-|Sa-1|)并返回。
// QuickSelect将第k小的元素放在S[k-1]
void QuickSelect(int S[], int k, int left, int right)
{
int i,j;
int pivot;
if (left <= right)
{
pivot = median3(S, left, right);
// 取3个数的中值作为主元,可以很大程度上避免最坏情况
i = left;
j = right - 1;
for (;;)
{
while (S[++i] < pivot){}
while (S[--j] > pivot){}
if (i < j)
{
swap(S[i], S[j]);
}
else
{
break;
}
}
// 重置主元
swap(S[i], S[right - 1]);
if (k <= i)
{
QuickSelect(S, k, left, i - 1);
}
else if(k > i + 1)
{
QuickSelect(S, k, i + 1, right);
}
}
else
{
// 如果left > right, 利用插入排序调整一下
InsertSort(S + left, right - left + 1);
}
}