【问题标题】:quickSelect algorithm to return kth smallest elementquickSelect 算法返回第 k 个最小元素
【发布时间】:2015-10-19 04:03:54
【问题描述】:

我已经关注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]

【问题讨论】:

  • “一模一样”...

标签: c algorithm sorting quickselect


【解决方案1】:

首先,noman 是对的。第二个 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)(在您的算法中k - pivot)是列表中以枢轴开头的 k 个最小元素的相对位置。例如,6 [1, 2, 3, 4, 5, 6] 列表中的第 4 小元素是从 3 [3, 4, 5, 6] 开始的子列表中的第 2 小元素

【讨论】:

  • 我已修改代码以包含上述更改。但它仍然无法正常工作。 int quick_select(int *a, int start, int end, int k) { if(start (pivot - start + 1)) return quick_select(a, pivot+1, end, k - (pivot-start+1));否则返回一个[pivot]; } }
  • “不工作”不是一个有用的提示。使用调试器并找出发生了什么。
【解决方案2】:

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

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

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

假设你有 5 个弟弟,你是他们中最高的。一个盲人来到你家,想知道谁是你们中第五个最高的。所以你告诉他说两个名字,你会告诉他在这些兄弟中谁最高。这是他可以问的唯一问题,以找出第五高。所以他做的是类似于快速排序的事情。如果他选择你的第三个兄弟作为支点,并将你身高小于第三个的兄弟排列在左边,另一个在右边。在这之后如果他计算你的第三个兄弟站在哪里,他会知道你的第三个兄弟是第三个最高的在你的房子。现在他应该在哪里搜索第 5 高,显然在右边?不?

但他不知道第四高的人站在右边的哪个位置。对?他只知道第 4 和第 5 高在右边。所以你有两个人站在右边,他们的身高都超过了第三,盲人想知道第五高,但是在这两个中,你应该在正确的组中寻找第四高还是第二高(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];
    }
}

【讨论】:

  • 你能解释一下原因吗?
猜你喜欢
  • 2019-08-13
  • 2015-01-15
  • 1970-01-01
  • 2021-08-29
  • 2021-08-29
  • 2021-09-23
  • 2012-10-22
  • 1970-01-01
  • 2020-03-13
相关资源
最近更新 更多