Quick sort partition tweak - java

but I am trying to figure out how I can make so I may choose which ever pivot point I wish, Say for example on this list of integers, 8, 7, 1, 9 , 11, 5 , 6, I wished to choose say key 6 as the pivot point in my code. Or if I wanted to choose 9 or whatever. How could I write this into my code? Any help is much appreciated.
package quicksort;
public class quicky {
private 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);
}
private static int partition (int[] arr, int left, int right) {
int pivot = arr[(left + right) / 2];
while(left<= right) {
while(arr[left] < pivot) left++;
while(arr[right]> pivot) right--;
if(left<= right) {
int tmp = arr[left];
arr[left] =arr[right];
arr[right] = tmp;
left++;
right--;
}
}
return left;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = new int [] { 8, 7, 1, 9, 11, 5, 6};
quicksort(array, 0 , array.length-1);
for(int i = 0; i <array.length; i++)
System.out.print(array[i]+ " ");
}
}
}

Here in your code
private static int partition (int[] arr, int left, int right) {
/*
Here in below code only you need to make your changes and that needs to be through out the same as you are calling this from quicksort also you need to make use of the left and right for that, as everytime you will be passing that otherwise it will be static value.
like you can do
int pivot = arr[left] // for left most as pivot, if you want the last one then have arr[right] as pivot, right now you have mid element as pivot.
*/
int pivot = arr[(left + right) / 2];
while(left<= right) {
while(arr[left] < pivot) left++;
while(arr[right]> pivot) right--;
if(left<= right) {
int tmp = arr[left];
arr[left] =arr[right];
arr[right] = tmp;
left++;
right--;
}
}
return left;
}

Simple method:
Check if value exists in array.
If it does, swap value with value in default pivot index.
Proceed using same code/ lomuto partition.

Related

Why is the pivot element included while sorting the left partition in Quicksort?

I am learning Quicksort from the implementation given in the famous book Cracking the Coding Interview. I understand that the partition function chooses the middle element as the pivot and returns the index where the right partition just starts (inclusive) so the quickSort function will next perform Quicksort recursively on right partition i.e. quickSort(arr, index, right). So far it is good.
The problem is that the left partition now contains the pivot element (at index - 1 location exactly) as well which is already sorted so why is it not doing quickSort(arr, left, index - 2) instead of quickSort(arr, left, index - 1) to skip the pivot element. I tried skipping the pivot but some elements were not sorted properly e.g. with this array: [29, 99, 27, 41, 66, 28, 44, 78, 87, 19, 31, 76, 58, 88, 83, 97, 12, 21, 44]
The complete code is given below:
public class Quicksort {
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[left + (right - left) / 2]; // Pick a pivot point. Can be an element
while (left <= right) { // Until we've gone through the whole array
// Find element on left that should be on right
while (arr[left] < pivot) {
left++;
}
// Find element on right that should be on left
while (arr[right] > pivot) {
right--;
}
// Swap elements, and move left and right indices
if (left <= right) {
swap(arr, left, right);
left++;
right--;
}
}
return left;
}
public static void quickSort(int[] arr, int left, int right) {
int index = partition(arr, left, right);
if (left < index - 1) { // Sort left half
quickSort(arr, left, index - 1);
}
if (index < right) { // Sort right half
quickSort(arr, index, right);
}
}
public static void main(String[] args) {
int[] arr = AssortedMethods.randomArray(20, 0, 6);
AssortedMethods.printIntArray(arr);
quickSort(arr, 0, arr.length - 1);
AssortedMethods.printIntArray(arr);
}
}
The partition function does not necessarily return the index of the pivot. The actual pivot value may be at the left of it or at the right. It really depends when it was encountered and swapped. This can happen some time before left and right cross each other.
For this reason you cannot skip the value at index.
If you want partition to return the index of the pivot value, should swap the pivot value to one side of the current partition before the loop starts, and swap it back into place after the loop finishes -- and then you know its index. In that case you can exclude it in the recursive calls. As the pivot value is thus excluded from the loop (unless it is duplicate), the loop condition should be checked at every change of left and right:
public static int partition(int[] arr, int left, int right) {
int mid = left + (right - left) / 2;
int pivot = arr[mid];
int store = right--;
swap(arr, mid, store);
while (left <= right) {
if (arr[left] < pivot) {
left++;
} else if (arr[right] > pivot) {
right--;
} else if (left < right) {
swap(arr, left, right);
left++;
right--;
} else {
return left;
}
}
swap(arr, left, store);
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 + 1, right);
}
}
The targeted benefit of excluding the value at index from the recursive calls comes with the cost of the extra swaps of the pivot value and more evaluations of the loop condition.

Java QuickSort algorithm

I am trying to learn Quick Sort algorithm and this is my code so far:
import java.util.Arrays;
public class JavaFiddle {
static int[] myArray = new int[]{35, 12, 25, 1, 5, 33, 56};
public static void QuickSort(int[] array) {
QuickSort(array, 0, array.length - 1);
}
public static void QuickSort(int[] array, int left, int right) {
if (left < right) {
int pivot = left + ((right - left) / 2);
int index = partition(array, left, right, pivot);
QuickSort(array, left, index - 1);
QuickSort(array, index + 1, right);
}
}
public static int partition(int[] array, int left, int right, int pivot) {
while (left < right) {
while (array[left] < pivot) {
left++;
}
while (array[right] > pivot) {
right--;
}
if (left < right) {
swap(array, left, right);
left++;
right--;
}
}
return left;
}
public static void swap(int[] array, int left, int right) {
int temp = array[left];
array[left] = array[right];
array[right] = temp;
}
public static void main(String[] args) {
System.out.println(Arrays.toString(myArray));
QuickSort(myArray);
System.out.println(Arrays.toString(myArray));
}
}
However, this code gives me an incorrect result:
[35, 12, 25, 1, 5, 33, 56] - before sort
[1, 12, 25, 35, 5, 33, 56] - after sort
What do I have wrong here? I cannot find the flaw in the logic.
Multiple errors here,
You define pivot in main method, but quick sort algorithm will swap pivot from right element to the middle.
You edit left and right values in your while loop in a while loop, which result right and left to be smaller/taller than your pivot and skipping some swaps.
Here's the correct implementation without your while { while { ... } } and a correct pivot (from right to middle)
import java.util.Arrays;
public class Main
{
static int[] myArray = new int[] {35, 12, 25, 1, 5, 56, 33};
public static void QuickSort(int[] array) {
QuickSort(array, 0, array.length - 1);
}
public static void QuickSort(int[] array, int left, int right){
if(left < right) {
int index = partition(array, left, right);
QuickSort(array, left, index - 1);
QuickSort(array, index + 1, right);
}
}
public static int partition(int[] array, int left, int right){
int pivot = array[right];
int first = left - 1;
for (int j = left; j <= right - 1; j++) {
if(array[j] < pivot) {
first ++;
swap(array, first, j);
}
}
swap(array, first + 1, right);
return first + 1;
}
public static void swap(int[] array, int left, int right) {
int temp = array[left];
array[left] = array[right];
array[right] = temp;
}
public static void main(String[] args)
{
System.out.println(Arrays.toString(myArray));
QuickSort(myArray);
System.out.println(Arrays.toString(myArray));
}
}
Also you compare pivot which is an index with array[...] which is a value

Cannot call the sort method in my quicksort implementation

I'm trying to code the quick sort algorithm using java. My problem is, that i cannot call the sort method. This is my code:
public class quickSort
{
int partition(int a[], int left, int right)
{
int i= left, j= right, temp;
int pivot=a[j];
//System.out.println(pivot+"pivot");
while(i<=j)
{
while(a[i]<pivot)
i++;
while(a[j-1]>pivot)
j++;
if(i<j)
{
temp=a[i];
a[i]=a[j-1];
a[j-1]=temp;
System.out.println(a[i] +"i");
System.out.println(a[j-1] +"j");
i++;
j--;
}
}
System.out.println(i);
System.out.println(j);
return i;
}
int[] sort(int[] numbers, int left, int right)
{
int x = partition(numbers, left, right);
System.out.println(x +"Qi");
if(left < right)
sort(numbers, left, x-1);
sort(numbers, x+1, right);
return numbers;
}
public static void main(String[] args)
{
quickSort q= new quickSort();
int[] numbers = {2,6,4,9,7,0,1,3,5};
int left = 0, right=numbers.length-1;
q.sort(numbers, left, right);
}
}
problem:
sort(numbers, left, x-1);
sort(numbers, x+1, right);
this recursion is not getting executed
It also results in an out of bounds exception, when i try to code in the partition method.
This is a screenshot of the output I m using it just to display the output and show the IDE I used to execute :
https://drive.google.com/file/d/1j6lHuEONZkO_Dr3ZszoPKh4bNXZgkgbT/view?usp=sharing.
The current code produces in the partition-method either an endless loop or an ArrayIndexOutOfBoundsException depending on your choosen numbers-array. A possible fix is e.g.:
private int partition(int a[], int left, int right) {
int i = left, j = right, temp;
int pivot = a[j];
while (i <= j) {
if (a[i] > pivot) {
temp = a[i];
for (int k = i; k < right; k++) { // remove a[i] and move all elements...
a[k] = a[k + 1]; // ...following a[i] to the left
}
j--; // decrement pivot's index
a[right] = temp; // move a[i] to the right end
} else {
i++;
}
}
return j; // return pivot's modified index
}
Furthermore, in the sort-method you have to ensure for both recursive sort-calls that the left boundary is smaller than the right boundary, e.g.:
private int[] sort(int[] numbers, int left, int right) {
int x = partition(numbers, left, right);
if (left < right) { // left boundary smaller than right one
sort(numbers, left, x - 1);
sort(numbers, x + 1, right);
}
return numbers;
}

QuickSort giving incorrect sorting order

I am new to Java and I am trying to implement QuickSort.
Here is my script below.
public class QuickSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] ={5,6,7,4,1,3};
QuickSort qs = new QuickSort();
qs.quickSort(a,0,a.length-1);
for(int i=0;i<a.length;i++) {
System.out.println(a[i]);
}
}
public void quickSort(int[] a,int left, int length) {
if(left >= length) return;
int index = partition(a,left,length);
if(left < index) {
quickSort(a,left,index-1);
}
else {
quickSort(a,index,length);
}
}
private int partition(int[] a,int l, int length) {
// TODO Auto-generated method stub
int left = l;
int right = length;
int pivot = a[(left+right)/2];
while(left <= right) {
while(left < length && a[left] < pivot) {
left++;
}
while(right >= 0 && a[right] > pivot) {
right--;
}
if(left <= right) {
int temp = a[left];
a[left]=a[right];
a[right]=temp;
left++;
right--;
}
}
return left;
}
}
When , I print the solution I get the following order-
[1,3,6,4,5,7]
I am unable to figure out the error, can anyone please help me fix this problem.
just change this
if(left < index) {
quickSort(a,left,index-1);
}
else {
quickSort(a,index,length);
}
to this
quickSort(a,left,index-1);
quickSort(a,index+1,length);
Since you need to sort array recursively on every partition of the array!
Quicksort breaks the array into two smaller arrays, on either side of the pivot. This means that each call to quicksort should result in two more calls to quicksort. Your code currently calls quicksort recursively, but only on one half.
Quicksort(array)
pick a pivot
Arrays left, right
For each value in array
If value < pivot
Append to left array
Else
Append to right array
Quicksort(left)
Quicksort(right)
Return join(left, right)
Try the following code:
import java.util.ArrayList;
public class MyQuickSort {
/**
* #param args
*/
public static void main(String[] args) {
//int[] a = { 1, 23, 45, 2, 8, 134, 9, 4, 2000 };
int a[]={23,44,1,2009,2,88,123,7,999,1040,88};
quickSort(a, 0, a.length - 1);
System.out.println(a);
ArrayList al = new ArrayList();
}
public static void quickSort(int[] a, int p, int r)
{
if(p<r)
{
int q=partition(a,p,r);
quickSort(a,p,q);
quickSort(a,q+1,r);
}
}
private static int partition(int[] a, int p, int r) {
int x = a[p];
int i = p-1 ;
int j = r+1 ;
while (true) {
i++;
while ( i< r && a[i] < x)
i++;
j--;
while (j>p && a[j] > x)
j--;
if (i < j)
swap(a, i, j);
else
return j;
}
}
private static void swap(int[] a, int i, int j) {
// TODO Auto-generated method stub
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
Taken from here
Below are the edited code you can replace it,
public void quickSort(int[] a,int left, int length) {
if(left >= length) return;
int index = partition(a,left,length);
if (left < index)
quickSort(a, left, index); // left subarray
if (length > index + 1)
quickSort(a, index + 1, length);
}
private int partition(int[] arr,int l, int length) {
// TODO Auto-generated method stub
int pivot = arr[(l + length)/2];
int left = l - 1; // index going left to right
int right = length + 1; // index going right to left
while (true) {
do {
left++;
} while (arr[left] < pivot);
do {
right--;
} while (arr[right] > pivot);
if (left < right){
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
else
return right; // index of last element in the left subarray
}
}
Quicksort is a divide and conquer algorithm. It first divides a large list into two smaller sub-lists and then recursively sort the two sub-lists. If we want to sort an array without any extra space, quicksort is a good option. On average, time complexity is O(n log(n)).
The basic step of sorting an array are as follows:
Select a pivot, normally the middle one
From both ends, swap elements and make all elements on the left less than the pivot and all elements on the right greater than the pivot
Recursively sort left part and right part
Arrays.sort() method in Java use quicksort to sort array of primitives e.g. array of integers or float and uses Mergesort to sot objects e.g. array of String.

Simple QuickSort implementation with first element pivot and brute-force counting comparisons

I'm using this simple implementation. I just want to count the comparisons. Below the code actually works.
The list is [3, 9, 8, 4, 6, 10, 2, 5, 7, 1].
The answer for comparison count is 25 but I'm getting 30. I can't figure out why. What causes this code to do "more work" than it is supposed to? Thanks in advance!
public void sort(int[] values){
int length = values.length;
if(values == null || length == 0){
return;
}
quicksort(values, 0, length-1);
}
private int partition(int arr[], int left, int right){
int i = left+1;
int pivot = arr[left];
for(int j=(left+1); j<=right; j++){
comparisonCount++;
if(arr[j] < pivot){
swap(arr,i,j);
i++;
}
}
swap(arr,left, i-1);
return i;
}
private 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);
}
}
private void swap(int[] arr, int i, int j){
int tmp;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
Well, I appear to have found where the discrepancy is coming from:
quicksort(values, 0, length - 1); // initial call in sort()
for (int j = (left + 1); j <= right; j++) { // loop in partition()
Versus
quicksort(values, 0, length); // initial call in sort()
for (int j = (left + 1); j < right; j++) { // loop in partition()
First one gives 30 comparisons, second gives 25.
Why this is the case? I suspect it has something to do with how the loop invariant is set up. My guess is that you're comparing some pivot multiple times due to the way the bounds were set up. I'm too brain-dead to figure out the exact bounds, so I'll try to remember to come back once I get that figured out.

Categories