期望为线性时间的选择算法

《算法导论》第3版9.2提到了期望为线性时间的选择算法
randomized_select 算法是以第7章的快速排序算法为模型的。
与快速排序一样,我们仍然将输入数组进行递归划分。
但与快速排序不同的是,快速排序会递归处理划分的两边,
而 randomized_select 只处理划分的一边。

数组 A[p..r] 被划分为两个子数组 A[p..q-1] 和 A[q+1..r]
使得 A[p..q-1] 中的每个元素都小于或等于 A[q],A[q+1..r] 中的每个元素都大于 A[q]
第4行计算 A[p..r] 的元素个数count,即处于划分的低区的元素的个数加1。
然后第5行检查 A[q] 是否是第 k 小的元素。如果是,就返回 A[q]
否则,算法要确定第 k 小的元素落在两个子数组 A[p..q-1] 和 A[q+1..r] 的哪一个之中。
如果 k < count,则在低区,如果 k > count,则在高区。然后递归查找。

代码如下

int partition(int A[], int p, int r)
{
    int x = A[r];
    int i = p - 1;

    for (int j = p; j < r; ++j)
    {
        if (A[j] <= x)
        {
            ++i;
            swap(A[i], A[j]);
        }
    }
    swap(A[i + 1], A[r]);

    return i + 1;
}

int ranged_rand(int range_min, int range_max)
{
    // Generate random numbers in the half-closed interval
    // [range_min, range_max). In other words,
    // range_min <= random number < range_max

    // Rand函数返回一个伪随机整数在范围 0 到 RAND_MAX (32767)
    int u = (double)rand() / (RAND_MAX + 1) * (range_max - range_min) + range_min;

    return u;
}


int randomized_partition(int A[], int p, int r)
{
    srand((unsigned)time(NULL));

    int i = ranged_rand(p, r + 1);
    swap(A[r], A[i]);

    return partition(A, p, r);
}

int randomized_select(int A[], int p, int r, int k)
{
    if (p == r)
    {
        return A[p];
    }

    int q = randomized_partition(A, p, r);
    int count = q - p + 1;

    if (k == count)
    {
        return A[q];
    }
    else if (k < count)
    {
        return randomized_select(A, p, q - 1, k);
    }
    else
        return randomized_select(A, q + 1, r, k - count);
}

猜你喜欢

转载自blog.csdn.net/Tao_Ba/article/details/81128976