Finding kth smallest number using quick sort - java

I am implementing an algorithm to find the Kth smallest element in an unsorted array using quick select. I am not sure where I am making a mistake. I am using the version of quick sort to find the kth smallest element. Rather than recursing through both partition , I am only recursing through one. Can anyone help me with this.
public class quickselect {
public static void main(String[] args){
int[] a={1,5,3,4,8,11};
int ans=quick_select(a, 4, 0, a.length-1);
System.out.println(ans);
}
private static int quick_select(int[] a, int k, int left, int right) {
int pivot=findpivot(a,left,right);
if(pivot==k-1){
return a[pivot];
}
if(k-1<pivot){
return quick_select(a, k, left, pivot-1);
}
else {
return quick_select(a, k, pivot+1, right);
}
}
private static int findpivot(int[] a, int left, int right) {
int pivot = a[(left+right)/2];
while(left<=right){
while(a[left]<pivot){
left++;
}
while(a[right]>pivot){
right--;
}
if(left<=right){
swap(a,left,right);
left++;
right--;
}
}
return left;
}
private static void swap(int[] a, int i, int j) {
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
I would really appreciate if anyone could give an explanation of where my mistake would be.

The problem is in findpivot (which should be findPivot in CamelCase) :
while(left <= right)
should be
while(left < right)
Plus, you can write your quick_selectmethod in a nicer fashion :
private static int quick_select(int[] a, int k, int left, int right) {
int pivot = findpivot(a,left,right);
return pivot == k - 1 ? a[pivot] : k - 1 < pivot ?
quick_select(a, k, left, pivot - 1) :
quick_select(a, k, pivot + 1, right);
}

Related

Why do I have to do (k-pivot+left-1) in case of right subarray while finding kth smallest element in an array?

I am running this script to find kth smallest element by using modified Quick Sort Algorithm. Ignore the comments they might be wrong.
I am not able to understand why do I have to (k-pivot+left-1) for right subarray. I have some idea the right subarray is shifted by pivot but I am not able to grasp it completely.
import java.util.Arrays;
public class kthMaxMin {
public static void Swap(int[] A, int id1, int id2){
int temp = A[id1];
A[id1] = A[id2];
A[id2] = temp;
}
public static int Partition(int[] A, int left, int right){
// Returns pivot index
int pivot = A[right];
int i = left; // Last position of smaller element pointer
for(int j=left;j<=right-1;j++){ // j is loop pointer
if(A[j]<=pivot){
Swap(A, i, j); // Put that element in the new position
i++;
}
}
Swap(A, i, right); // Put pivot where it belongs i.e. middle
return (i); // Location of pivot
}
public static int QuickSortModified(int[] A, int left, int right, int k){
// Returns kth smallest element
if(k>0 && k<=right-left+1){ // k is within bounds of the array
int pivot = Partition(A, left, right);
if(pivot - left == k-1){ // If number of elements in left subarray is equal to k
return A[pivot]; // then return pivot as it is kth smallest element
}
if(pivot-left > k-1){ // If size of left subarray is greater than k
return QuickSortModified(A, left, pivot-1, k); // Search in left subarray more
}
return QuickSortModified(A, pivot+1, right, k-pivot+left-1); // Else Search in right subarray
// k-pivot because right subarray is shifted by value = pivot?
}
return (-1);
}
public static void main(String[] args) {
int[] Arr = new int[10];
Arr[0] = 99;
Arr[1] = 9;
Arr[2] = 56;
Arr[3] = 78;
Arr[4] = 12;
Arr[5] = 18;
Arr[6] = 76;
Arr[7] = 19;
Arr[8] = 12;
Arr[9] = 5;
System.out.println("Array: "+Arrays.toString(Arr));
int k =5;
int min = QuickSortModified(Arr, 0, Arr.length-1, k);
System.out.println(k+"th Smallest Element: "+min);
}
}
why do I have to (k-pivot+left-1) for right subarray
Because the code is checking for pivot-left == k-1. The way the code in the question is implemented allows for finding the kth element of a portion of an array, rather than the entire array.
With an entry | helper function (QuickSelect() in this example code), the code can be simplfied:
public static int QuickSortModified(int[] A, int left, int right, int k){
int pivot = Partition(A, left, right);
if(pivot == k) // if k == pivot
return A[pivot];
if(pivot > k) // if k is in left partition
return QuickSortModified(A, left, pivot-1, k);
else // if k is in right partition
return QuickSortModified(A, pivot+1, right, k);
}
public static int QuickSelect(int[] A, int left, int right, int k){
k = k-1;
if(k < left || k > right)
return -1;
return QuickSortModified(A, left, right, k+left);
}
// ...
// calling example
// ...
int left = 2; // normally left = 0
int right = 8; // normally right = Arr.length-1
int k = 4;
int min = QuickSelect(Arr, left, right, k);

Recursive Quick Sort in java

This is my quicksort Code. It gives me a wrong answer but i think my partition function is correct.
public class Quick_Sort {
public static void main(String[] args)
{
int a[] = {99,88,5,4,3,2,1,0,12,3,7,9,8,3,4,5,7};
quicksort(a, 0, a.length-1);
}
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
int j = hi-1;
while(i<j)
{
if(a[i]<=a[pivot])
{
i++;
}
if(a[i]>a[pivot])
{
if((a[i]>a[pivot]) && (a[j]<=a[pivot]))
{
int temp= a[i];
a[i]=a[j];
a[j]=temp;
i++;
}
if(a[j]>a[pivot])
{
j--;
}
}
}
int temp= a[i];
a[i]=a[pivot];
a[pivot]=temp;
return i;
}
static void quicksort(int[] a, int low, int hi)
{
if(low>=hi)
{
return;
}
int split = partition(a, low, hi);
quicksort(a, low, split-1);
quicksort(a, split+1, hi);
}
}
This is the final output:
1 0 3 2 3 4 4 5 5 7 3 7 8 9 12 88 99
Tried dry running it, couldn't see the error
In your partition method you have assigned j to hi - 1. It should be set to hi only.
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
// int j = hi-1; // CHANGE THIS TO
int j = hi; // THIS
while(i<j)
I got this output after I made that change:
[0, 1, 2, 3, 3, 3, 4, 4, 5, 5, 7, 7, 8, 9, 12, 88, 99]
Hope this helps!
This is C# code:
public void RecursiveQuickSort(int[] array, int start, int end)
{
if (start < end)
{
int pivot = start;
int left = start + 1;
int right = end;
while (true)
{
while (array[left] <= array[pivot] && left < right)
left++;
while (array[right] > array[pivot] && left < right)
right--;
if (left < right)
{
Swap(array, left, right);
}
else
{
pivot = (array[pivot] > array[left]) ? left : left - 1;
Swap(array, start, pivot);
RecursiveQuickSort(array, start, pivot - 1);
RecursiveQuickSort(array, pivot + 1, end);
return;
}
}
}
}
private void Swap(int[] array, int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
This is a very good implementation and is much more Java standard. Maybe you want to take a look here, obviously all credits go to the original author.
http://www.vogella.com/tutorials/JavaAlgorithmsQuicksort/article.html
this is how I made it C:
private static List<Integer> recursive_quick_sort (List<Integer> list){
if (list.size()< 2){
return list;
}else {
int pivot = list.get(0);
List<Integer> less = list.stream().filter(element -> element < pivot ).collect(Collectors.toList());
List <Integer> greater = list.stream().filter(element -> element > pivot ).collect(Collectors.toList());
List<Integer> newList = Stream.of(recursive_quick_sort(less),List.of(pivot),recursive_quick_sort(greater))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return newList;
}
}

Quick Sort Java . ArrayIndexoutofBoundsException

I want to quicksort algoritm.I am learning the quicksort algoritm.
Out: ArrayIndexoutofBoundsException error.I could not find the fault.
I not good English.Sorry.
How do I solve this problem?
public class Quickort {
static int partition(int arr[],int left,int right){
int i=left;
int j=right;
int tmp;
int pivot=(left/right)/2;
while(i<=j){
while(arr[i]<pivot)
i++;
while(arr[j]>pivot)
j--;
if(i<=j){
tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
i++;
j--;
}
}
return i;
}
static void quicksort(int arr[],int left,int right){
int index=partition(arr,left,right);
if(left<index-1)
quicksort(arr, left, index-1);
if(index<right)
quicksort(arr, index, right);
}
public static void main(String[] args) {
int [] arr={8,4,1,7,9,4,3,2,5};
quicksort(arr,0,arr.length-1);
}
}
value of pivot variable should be an element from your array (int pivot = arr[right];).
Try this:
static int partition(int arr[], int left, int right) {
int pivot = arr[right];
int i = left - 1;
int tmp;
for (int j = left; j <= right; j++) {
if (arr[j] <= pivot) {
i++;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
return i;
}
static void quicksort(int arr[], int left, int right) {
if(left < right){
int index = partition(arr, left, right);
quicksort(arr, left, index - 1);
quicksort(arr, index + 1, right);
}
}
change int pivot=(left/right)/2; to int pivot=(left+right)/2;
According to your code
int pivot=(left/right)/2;
You will get pivot as zero. and because of this loop
while(arr[j]>pivot)
j--;
j becomes -1 and as array not contains this, it is throwing ArrayIndexoutofBoundsException

In-Place Quicksort w/ Last Element Pivot?

I am trying to implement In-Place Quicksort, with the last element as my pivot. Attached below is my code
public static void main(String[] args){
int[] input = {3,2,4,6,10,1,9,7,5};
quickSort(input, 0, input.length-1);
}
public static void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static int partition(int arr[], int left, int right) {
int pivot = arr[right];
int high = right-1;
while(left < high){
while(arr[left] < pivot){
left++;
}
while(arr[high] > pivot){
high--;
}
swap(arr,left, high);
left++;
high--;
}
swap(arr, left, pivot);
System.out.println(Arrays.toString(arr));
return left;
}
public static void quickSort(int arr[], int left, int right) {
int index = partition(arr, left, right);
quickSort(arr, left, index - 1);
quickSort(arr, index, right);
}
For some reason, my code is giving me an IndexOutOfBounds Exception, and it does not accurately sort the array. I am not sure why I am getting this error.
If I understand correctly, we should make the last element our pivot. Then, we iterate the left pointer right, until we find an element greater than the pivot. After that, we do the same from the right side (keep moving left), until we find an element smaller than the pivot. Then we swap these elements and continue doing the same thing.
Finally, when the left/right pointer are the same, we swap the center value with our pivot.
Is this the correct way of thinking about it? And if so, what errors does my code have? Any help would be appreciated
A few errors:
Add left < high checks to your inner loops. You should check it every time you modify left or right.
Check arr[high] >= pivot not arr[high] > pivot.
swap(arr, left, pivot); is wrong. You should swap left with pivot using positions, not values. It should be swap(arr, left, right);.
You should check left < right in your quicksort method.
When you fix these errors, your code should look like this:
public static void main(String[] args){
int[] input = {3,2,4,6,10,1,9,7,5};
quickSort(input, 0, input.length-1);
}
public static void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static int partition(int arr[], int left, int right) {
int pivot = arr[right];
int high = right;
while(left < high){
while(left < high && arr[left] < pivot){
left++;
}
while(left < high && arr[high] >= pivot){
high--;
}
swap(arr,left, high);
}
swap(arr, left, right);
System.out.println( Arrays.toString(arr));
return left;
}
public static void quickSort(int arr[], int left, int right) {
if( left < right)
{
int index = partition(arr, left, right);
quickSort(arr, left, index - 1);
quickSort(arr, index, right);
}
}
Trace through this code on the assumption that the final array element is the smallest element. The loop to adjust high will continuously decrement high because each other array element is bigger than the pivot, so eventually high will drop off the front of the array, leading to your out of bounds access.
To fix this, add in another check in that loop to ensure you haven't had high and left cross. You may then need to add in some extra logic afterwards to handle that as a special case.

multithreaded quick sort does not give answer as expected

I modified quick sort to make it multithread.
I expected it to work , coz the original algorithm was working.
After partitioning, for the recursive calls to left and right of pivot .. I am creating a new thread.
public class QuickSort extends Thread{
private int[] arr;
private int left;
private int right;
public QuickSort(int[] arr){
this.arr= arr;
this.left=0;
this.right=arr.length -1;
this.start();
}
public QuickSort(int[] arr, int left , int right){
this.arr= arr;
this.left=left;
this.right=right;
this.start();
}
int partition( int left, int right)
{
int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
};
return i;
}
void quickSort(int left, int right) {
int index = partition(left, right);
if (left < index - 1)
new QuickSort(arr, left , index -1);
if (index < right)
new QuickSort(arr ,index, right);
}
public void run(){
quickSort(left , right);
}
public static void main(String arg[])
{
int[] s = {100,99,98,97,96,95,94,93,92,91};
new QuickSort(s);
for(int i: s)
System.out.println(i);
}
}
Your first problem is that you aren't waiting for any thread to exit, so you are printing the data while the threads are still running. You need some Thread.join() calls.
I'm not saying there aren't other problems ... Your sort fails if there are already sorted elements, e.g. if you add 89,90 to your test array.
For one thing, you're never waiting for any of the threads to finish. So by the time you go to print out the array who knows how much work has been done.
You'll need to somehow join() the threads you've spun up (or come up with some other mechanism to figure out they're done).

Categories

Resources