random select algorithm(选择算法)

选择算法:在一个未排序的的序列中,选取第K小的元素。

 

static int random_select(int begin, int end, int k)
{
        assert(begin < end);
        assert(k >= 0);
        assert(k < end-begin);

        int rand = randint(begin, end);
        int left, right;

        partition(begin, end, rand, &left, &right);
        int idx = k+begin;
        if (idx < left)
                return random_select(begin, left, k);
        else if (idx >=left && idx<=right)
                return idx;
        else
                return random_select(right+1, end, idx-right-1);

}

static void partition(int begin, int end, int pivot_index, int *ret_left, int *ret_right)
{
#if 0
        printf("***********in partition*****************\n");
        print_array(begin, end);
        printf("pivot_index = %d\n", pivot_index);
#endif
        int pivot = A[pivot_index];
        swap(begin, pivot_index);

        int left = begin;
        int right = begin;
        int i;
        for (i=begin+1; i<end; i++)
        {
                if (A[i] > pivot)
                        ;
                else if (A[i] == pivot)
                {
                        swap(right+1, i);
                        right += 1;
                }
                else
                {
                        swap(left, i); left += 1;
                        swap(right+1, i); right += 1;
                }

        }
        *ret_left = left;
        *ret_right = right;
#if 0
        print_array(begin, end);
        printf("left = %d, right = %d \n", left, right);
        printf("***********end partition*****************\n");
#endif
}

用pseudo code写完,我会用了不到5分钟,而实际转换成代码调试,却花费了我半个多小时。以下是几点原因。

1. 平常写pseudo code时,是和人的正常思维一直,数组开始于1,最小的第k个元素就是最小的第k个元素。而实际写代码是,数组时从0开始的。这一点,很容易混淆。我的感觉是,定义一套自己的符号和规则,使得pseudo code和程序代码的约定一致。比如,排名可以从0开始,第0小,第1小,..,第k小。比如,集合统一采取半开半闭的表示方法,所有有关数组的调用传入的参数(begin,end)都是半开半闭的.A[begin:end)

2. 用divide-and-conque方法解决问题时,边界条件很容易搞错。我认为,在写边界条件时,最好用简单示例看看对不对。否则,等程序跑起来,崩溃了,就悲剧了。

3. 函数的定义要明确,其表示的含义一定要明确。传入的参数的意义,返回的值的意义。我这次有一个bug就是因为random_select函数一开始定义返回的值的含义没有明确。

磨刀不误砍柴工,定义明确了再动手。

转载于:https://my.oschina.net/u/158589/blog/57612

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值