random selection

转自算法导论中文版第9.2节


线性时间期望的选择算法


randomized-select的期望运行时间为Θ(n)。该算饭是一个随机算法,只处理划分的一边。


伪代码

RANDOMIZED-SELECT(A, p, r, i)

1    if p = r

2        then return A[p]

3    q = RANDOMIZED-PARTATION(A, p, r)

4    k = q - p +1

5    if i = k

6        then return A[q]

7    elseif i < k

 8       then return RANDOMIZED-SELECT(A, p, q-1 i)

 9   else return RANDOMIZED-SELECT(A, q+1, r, i-k)


在算法第3行的RANDOMIZED-PARTATION执行之后,数组A[p...r]被划分成两个(可能是空的)子数组A[p...q-1], A[q+1...r],使得A[p...q-1]中的每一个元素都小于或等于A[q],A[q+1...r]中的每一个元素都大于A[q]。与快速排序中一样,称A[q]为主元素(povit element)。RANDOMIZED-SELECT的第4行计算子数组A[p...q]内的元素个数k,即处于划分低区的元素的个数机上一个主元元素。然后第5行检查A[q]是不是第i小的元素。如果是,就返回A[q]。否则,算法要确定第i小的元素落在两个子数组A[p...q-1]和 A[q+1...r]中的哪一个之中。如果i< k,则要找的元素落在划分的低区中,于是第8行就在低区的子数组中进一步递归选择。如果i>k,则要找的元素落在划分的高区子数组中。因为我们已经知道有k个值(即A[p...q]中的所有元素)小于A[p...r]中的第i小元素,故所求原色必是A[q+1...r]中的第(i-k)元素,它在第9行中被递归地选取。


RANDOMIZED-SELECT的最坏情况运行时间为Θ(n^2),即使是要选择最小元素也是如此,因为在每次划分时可能极不走运,总是按余下的元素中最大的进行划分,而划分操作需要Θ(n)的时间。该算法的平均情况性能较好,又因为它是随机化的,故没有哪一种特别的输入会导致其最坏情况发生。


#include <stdio.h>
#include <stdlib.h>

void swp(int *a, int *b)
{
	int tmp = *a;
    *a = *b;
    *b = tmp;
}

int randomize(int p, int q)
{
	int size = q - p +1;
    return p + rand() % size;
}

int partation(int a[], int p, int r)
{
    int x = a[r];
	int i = p -1;
    int j;

    for (j = p; j < r; j++) {
		if (a[j] <= x) {
			i++;
            swp(&a[j], &a[i]);
		}
	}
    swp(&a[i+1], &a[r]);

    return i+1;
}

int random_partation(int a[], int p, int r)
{
	int i;

    i = randomize(p, r);
    swp(&a[i], &a[r]);

    return partation(a, p, r);
}

/* 
 * int random_select(int a[], int p, int r, int i)
 * {
 *     int q, k;
 * 
 * 	if (p == r) {
 * 		return a[p];
 * 	}
 * 
 *     q = random_partation(a, p, r);
 *     k = q - p + 1;
 * 
 *     if (i == k) {
 * 		return a[q];
 * 	} else if (i < k) {
 * 		return random_select(a, p, q -1, i);
 * 	} else {
 * 		return random_select(a, q +1, r, i -k);
 * 	}
 * }
 */

int random_select(int a[], int start, int end, int i)
{
    int p = start, r = end;
	int q, k;

    if (p == r) {
		return a[p];
	}

    while (p < r) {
        q = random_partation(a, p, r);
        k = q - start + 1;
 
        if (i == k) {
			return a[q];
		} else if (i < k) {
			r = q - 1;
		} else {
			p = q + 1;
		}
	}
}

int main(void) 
{
    int k;
    int a[] = {
		0, 1, 2, 3, 4, 5, 9, 7, 8, 6, 10,
	};

    k = random_select(a, 1, 10, 9);

    printf("the 9th is %d", k);

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值