简体   繁体   中英

quickSelect algorithm to return kth smallest element

I have followed quickSelect to understand and implement quickSelect algorithm. One thing I am not sure here is : why do they do k-pivot and pivot-first+1 .

Though my implementation is exactly similar to this link, it is not working.

#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;
}

Output :

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

First off, noman is right. The second quick_select is

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

Second, pay attention to the meaning of the inputs. start and end are absolute position in the original list corresponding to the current recursive call. k is the relative position in the current list [start, end]

  1. pivot-start+1 is the relative position of the index pivot in the current sublist starting at start .
  2. k - (pivot-start+1) (in your alg k - pivot ) is the relative position of the k smallest element in the list starting with pivot. For instance the 4th smallest element in a list of 6 [1, 2, 3, 4, 5, 6] is the 2nd smallest in the sublist starting at 3 [3, 4, 5, 6]

Just that you didn't do pivot-1 in one case and you were not subtracting the right value from K to find the next K.

Let's suppose you have 8 numbers and you get the pivot as 5. What that 5 means? It means that the number at the 5th index is the 5 smallest element if you are sorting in non-decreasing order and all number less than 5th index is less than that. So if you are looking for 7 smallest number(Let's call it K) where should you search? You should search in 6 to 8 right? But what should happen to the K number, should you still search for 7 smallest number in the range 6 to 8? No right?

Don't you think you should subtract 6(0 to 5) numbers from 7? If you still think no? Then read on otherwise stop reading here.

Suppose you have 5 younger brothers and you are the tallest among all of them. A blind man comes to your house and wants to know who is the 5th tallest among all of you.So you tell him to say two names and you will tell him who is tallest between those brothers. That is the only question he can ask to find out 5th tallest. So what he does is something similar to quicksort. If he picks your 3rd brother as pivot and arranges your brothers whose height is less than third to the left and other to the right.After this if he counts where your third brother is standing he will come to know that your 3rd brother is 3rd tallest in your house. Now where should he search for 5th tallest, obviously to the right?No?

But he doesn't know where the 4th tallest is standing towards the right. Right? All he knows is that 4th and 5th tallest is towards the right. So you have two people standing towards the right and both of them are having heights more than 3rd and blind man wants to know 5th tallest but among these two, should you look for 4th tallest or 2nd tallest (5-3) in the right group(range is 4 to 5)?

I am sure by now you would have understood.

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];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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