选择问题

选择问题是,在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.将S-\left [ v \right ]分割成S_{1}S_{2}

4.若k\leqslant \left | S_{1} \right |,那么第k个最小元在S_{1}中,返回quickselect(S_{1},k);若k= 1+ \left | S_{1} \right |,那么枢纽元就是第k个最小元;否则,k在S_{2}中,是S_{2}的第k- \left | S_{1} \right |-1个最小元,返回quickselect(S_{2}k- \left | S_{1} \right |-1)

代码如下:

/* 快速选择问题主例程,选择第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);
    }
}

猜你喜欢

转载自blog.csdn.net/kdb_viewer/article/details/83009278