选择问题是,在N个数中选择第k小的,有几种方法:
1.N个元素建立最小堆,k次deletemin,时间O(klogN)
2.k个元素建立最大堆,N次percdown,时间O(Nlogk)
3.使用分治算法,改进快速排序,每次解决两个子问题中的一个,平均时间O(N)
4.改进方法3中枢纽元的选择,使用五分化中项的中项或者七分化中项的中项,最坏时间O(N)
快速选择问题步骤:
1.若集合S中只有1个元素,那么返回,若使用了小数组的cutoff方法,那么直接插入排序并返回第k个最小元
2.选择一个枢纽元v
3.将分割成和
4.若,那么第k个最小元在中,返回quickselect(,k);若,那么枢纽元就是第k个最小元;否则,k在中,是的第个最小元,返回quickselect(,)
代码如下:
/* 快速选择问题主例程,选择第k小的 */
void Qselect(int *a, int k, int left, int right)
{
int i, j;
int Pivot;
if (left + cutoff <= right)
{
Pivot = Median3(a, left, right);;
i = left, j = right - 1;
for (;;)
{
while (a[++i] < Pivot);
while (a[--j] > Pivot);
if (i < j)
Swap(&a[i], &a[j]);
else
break;
}
Swap(&a[i], &a[right - 1]);
/* 这里和快速排序不同,因为只需要处理一个子问题 */
if (k <= i)
Qselect(a, k, left, i - 1);
else if (k > i + 1)
Qselect(a, k, i + 1, right);
}
}