Search code examples
javaalgorithmquicksort

Kth minimum element using quickselect with random pivot


I am trying to find the kth smallest in an array using quickselect algorithm. But, when I try to select the pivot randomly, the output coming is also random.

Following is my method implementation,

    static int findKthMin(int[]arr, int n, int k) {
        int l=0 , r=n-1;
        Random random = new Random();
        while(true) {
            int x = random.nextInt(r+1-l) + l; // When using x = r (works correctly)
            int pivot = arr[x];
            int idx = l;
            for(int i=l;i<=r;i++) {
                if(arr[i] < pivot) {
                    int temp = arr[idx];
                    arr[idx] = arr[i];
                    arr[i] = temp;
                    
                    idx++;
                }
            }
            arr[x] = arr[idx];
            arr[idx] = pivot;
            
            if(idx == k-1) return pivot;
            
            if(idx > k-1) {
                r = idx-1;
            } else {
                l = idx;
            }
        }
    }

Here, n is size of array and k is the kth minimum element to be found.
The code works fine when I use x=r.

My guess is that something is wrong in the condition

   for(int i=l;i<=r;i++) {
       if(arr[i] < pivot) {
            int temp = arr[idx];
            arr[idx] = arr[i];
            arr[i] = temp;

            idx++;
       }
   }          

But I can't figure out what is wrong and how to fix it. I have spent hours debugging it and changing the code but can figure out the problem.

Here are the test cases I'm trying,

6               // n
7 10 4 3 20 15  //arr
3               // k

and,

5             // n
7 10 4 20 15  // arr
4             // k

With these test cases, random pivot is giving any of the array element as the output.
Any hint of what might be the bug will be very helpful.


Solution

  • After the suggestion from @Nico, I just needed to swap the pivot element with the last one.
    Following is the complete working snippet,

        static int findKthMin(int[]arr, int n, int k) {
            int l=0 , r=n-1;
            Random random = new Random();
            while(true) {
                int x = random.nextInt(r+1-l) + l; // When using x = r (works correctly)
    
                //Swap random pivot with the last index element
                int temp = arr[x];
                arr[x] = arr[r];
                arr[r] = temp;
    
                int pivot = arr[r];
    
                int idx = l;
                for(int i=l;i<=r;i++) {
                    if(arr[i] < pivot) {
                        temp = arr[idx];
                        arr[idx] = arr[i];
                        arr[i] = temp;
    
                        idx++;
                    }
                }
                arr[r] = arr[idx];
                arr[idx] = pivot;
    
                if(idx == k-1) return pivot;
    
                if(idx > k-1) {
                    r = idx-1;
                } else {
                    l = idx;
                }
            }
        }