繁体   English   中英

quickSelect算法返回第k个最小元素

[英]quickSelect algorithm to return kth smallest element

我遵循quickSelect来理解和实现quickSelect算法。 我不确定的一件事是:为什么他们要进行k-pivotpivot-first+1

尽管我的实现与该链接完全相似,但无法正常工作。

#include <stdio.h>
#include <string.h>

#define DEBUG 1

#define debug(fmt, ...)\
    do{\
        if(DEBUG)\
            fprintf(stdout, "%s(%d) :   " fmt "\n", __FUNCTION__, __LINE__, __VA_ARGS__);\
    }while(0)

#define swap(a, b)\
    do{\
        if(a != b) {\
            a = a ^ b;\
            b = a ^ b;\
            a = a ^ b;\
        }\
    }while(0)


int
partition(int *a, int low, int high)
{
    int i = low, j = high;

    int pivot = a[i];
    i++;
    while(i < j)
    {
    while(pivot >= a[i])
        i++;
    while(pivot < a[j])
        j--;
    if(i < j)
        swap(a[i], a[j]);
    }

    swap(a[low], a[j]);
    return j;
}


int
quick_select(int *a, int start, int end, int k)
{
    if(start < end)
    {
    int pivot = partition(a, start, end);

    if(k < (pivot - start + 1))
       return quick_select(a, start, pivot, k);
    else if( k > (pivot - start + 1))
       return quick_select(a, pivot+1, end, k - pivot);
    else
    return a[pivot];
    }
}

int
main()
{
    int a[100], k, n;
    int ret, i;

    while(1)
    {
    printf("# of items  :   ");
    scanf("%d", &n);

    printf("Items   :   ");
    for(i = 0; i<n; i++)
        scanf("%d", &a[i]);

    printf("<k> :   ");
    scanf("%d", &k);

    ret = quick_select(a, 0, n-1, k);
    printf("[%d] smallest element = [%d]\n", k, ret);
    }

    return 0;
}

输出:

./a.out 
# of items  :   10
Items   :    1 2 3 4 5 6 7 8 9 10
<k> :   9
[9] smallest element = [32767]

首先,诺曼是对的。 第二个quick_select是

quick_select(a, pivot+1, end, k - (pivot-start+1));

其次,注意输入的含义。 startend是原始列表中与当前递归调用相对应的绝对位置 k是当前列表中的相对位置 [start, end]

  1. pivot-start+1是索引的相对位置pivot在当前子列表开始于start
  2. k - (pivot-start+1) (在您的alg中, k - pivot )是列表中第k个最小元素的相对位置,以pivot开头。 例如,在6 [1, 2, 3, 4, 5, 6]列表中的第4个最小元素是从3 [3, 4, 5, 6] 3、4、5、6]开始的子列表中的第2个最小元素。

只是您没有在一种情况下执行数据透视1,并且没有从K中减去正确的值来找到下一个K。

假设您有8个数字,并且枢轴为5。那5意味着什么? 这意味着,如果以非降序排序,并且小于5个索引的所有数字都小于5,则位于5个索引的数字是最小的5个元素。 因此,如果您要寻找7个最小的数字(我们称其为K),应该在哪里搜索? 您应该在6到8中搜索对吗? 但是K数会怎样,您是否仍应搜索6到8范围内的7个最小数? 没有权利?

您不认为应该从7中减去6(0到5)个数字吗? 如果您仍然认为否? 然后继续阅读,否则在这里停止阅读。

假设您有5个弟弟,而您是他们中最高的。 一个瞎子来到你家,想知道谁是你们中第五高的人,所以你告诉他说两个名字,然后告诉他这两个兄弟中谁是最高的。 这是他唯一想找出的第五高的问题。 因此,他的工作类似于quicksort。 如果他选择您的三兄弟作为枢轴并排列您的兄弟,这些兄弟的身高小于左边的三分之一,而右边的其他三分之一,那么如果他算出您的第三兄弟的站立位置,他就会知道您的第三兄弟是第三高在你的房子。 现在他应该在哪里寻找第五高的位置,显然是在右边?

但是他不知道第四高的位置在右边。 对? 他只知道第四高和第五高是向右。 因此,您有两个人朝右站立,而且两个人的身高都超过了第三,而盲人想知道第五高,但是在这两个之中,您应该在右组中寻找第四高还是第二高(5-3) (范围是4到5)?

我确定您现在已经了解了。

quick_select(int *a, int start, int end, int k)
{
    if(start < end)
    {
        int pivot = partition(a, start, end);

        if(k < (pivot - start + 1))
            return quick_select(a, start, pivot-1, k);
        else if( k > (pivot - start + 1))
            return quick_select(a, pivot+1, end, k - (pivot-start+1));
        else
            return a[pivot];
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM