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
Related
I've implemented the quick sort algorithm below, the array gets sorted but it doesn't exit the recursive loop. Can someone analyze my quick sort algorithm below and check what am I'm doing wrong?
Please see my code below:
package sort;
import java.util.Arrays;
public class QuickSort {
public int array[];
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
quickSort(0, this.array.length);
}
private void quickSort(int low, int high)
{
if (low < high)
{
int j = partition(low, high);
quickSort(low, j);
quickSort(j+1, high);
}
}
private int partition(int low, int high) {
int pivot = this.array[low];
int i = low;
int j = high;
while (i<j) {
do {
i++;
} while (this.array[i] <= pivot);
do {
j--;
} while (this.array[j] > pivot);
}
swap(low,j);
return j;
}
private void swap(int i, int j) {
int temp = this.array[i];
this.array[i] = this.array[j];
this.array[j] = temp;
}
}
The Hoare partition scheme should look like this or similar (use middle value for pivot):
private int partition(int low, int high) {
int pivot = this.array[low+(high-low)/2];
int i = low-1;
int j = high+1;
while (true) {
while (this.array[++i] < pivot); // not <=
while (this.array[--j] > pivot);
if(i >= j)
return j;
swap(i,j);
}
}
I have a quicksort code in java which I want to improve. The improved code should take less time than the quicksort code. However when using my improved code which implement median of 3 partitioning, it takes 400 miliseconds more. Can anybody help me solve this out? if possible, can you suggest me other possible ways to improve my code. I have from 10,000 to 10 million integers to sort.
Quicksort
public void quickSort(int arr[], int begin, int end) {
if (begin < end) {
int partitionIndex = partition(arr, begin, end);
quickSort(arr, begin, partitionIndex-1);
quickSort(arr, partitionIndex+1, end);
}
}
private int partition(int arr[], int begin, int end) {
int pivot = arr[end];
int i = (begin-1);
for (int j = begin; j < end; j++) {
if (arr[j] <= pivot) {
i++;
int swapTemp = arr[i];
arr[i] = arr[j];
arr[j] = swapTemp;
}
}
int swapTemp = arr[i+1];
arr[i+1] = arr[end];
arr[end] = swapTemp;
return i+1;
}
}
Improved code
package sorting;
public class improvement {
Clock c = new Clock();
public void quickSort(int[] intArray) {
recQuickSort(intArray, 0, intArray.length - 1);
}
public static void recQuickSort(int[] intArray, int left, int right) {
int size = right - left + 1;
if (size <= 3)
manualSort(intArray, left, right);
else {
double median = medianOf3(intArray, left, right);
int partition = partitionIt(intArray, left, right, median);
recQuickSort(intArray, left, partition - 1);
recQuickSort(intArray, partition + 1, right);
}
}
public static int medianOf3(int[] intArray, int left, int right) {
int center = (left + right) / 2;
if (intArray[left] > intArray[center])
swap(intArray, left, center);
if (intArray[left] > intArray[right])
swap(intArray, left, right);
if (intArray[center] > intArray[right])
swap(intArray, center, right);
swap(intArray, center, right - 1);
return intArray[right - 1];
}
public static void swap(int[] intArray, int dex1, int dex2) {
int temp = intArray[dex1];
intArray[dex1] = intArray[dex2];
intArray[dex2] = temp;
}
public static int partitionIt(int[] intArray, int left, int right, double
pivot) {
int leftPtr = left;
int rightPtr = right - 1;
while (true) {
while (intArray[++leftPtr] < pivot)
;
while (intArray[--rightPtr] > pivot)
;
if (leftPtr >= rightPtr)
break;
else
swap(intArray, leftPtr, rightPtr);
}
swap(intArray, leftPtr, right - 1);
return leftPtr;
}
public static void manualSort(int[] intArray, int left, int right) {
int size = right - left + 1;
if (size <= 1)
return;
if (size == 2) {
if (intArray[left] > intArray[right])
swap(intArray, left, right);
return;
} else {
if (intArray[left] > intArray[right - 1])
swap(intArray, left, right - 1);
if (intArray[left] > intArray[right])
swap(intArray, left, right);
if (intArray[right - 1] > intArray[right])
swap(intArray, right - 1, right);
}
}
}
I'm implementing a recursive quicksort however I'm receiving stackoverflow and not sure where the bug lies :(
I'm sorting 1 million ints from 10-50.
I works for sizes less than 1 million like 100 thousand etc.
public Quicksort(int NUM_TESTS, int NUM_ELEMENTS){
num_tests = NUM_TESTS;
num_elements = NUM_ELEMENTS;
}
private void start(){
for (int i = 0; i < num_tests; i++){
int[] d1 = dataGeneration(num_elements);
qSortRecursive(d1,0,d1.length-1);
}
}
public static void main(String args[]){
Quicksort q = new Quicksort(1,1000000);
q.start();
}
private int[] dataGeneration(int n) {
int[] d1 = new int[n];
for (int i = 0; i < n; i++){
d1[i] = (int)(Math.random() * ((50 - 10) + 1) + 10);
}
return d1;
}
private void qSortRecursive(int[] data, int left, int right){
if(left < right){
int pivot = partition(data,left,right);
qSortRecursive(data,left,pivot-1);
qSortRecursive(data,pivot+1,right);
}
}
private int partition(int[] data, int left, int right){
int pivot = left ;
left++;
while (left <= right){
while (left <= right && data[left] <= data[pivot]) {
left++;
}
while (left <= right && data[right] >= data[pivot]){
right--;
}
if (left < right){
swap(data,left,right);
left++;
right--;
}
}
if (data[right] <= data[pivot]){
if (data[right] != data[pivot]){
swap(data,right,pivot);
}
pivot = right;
}
return pivot;
}
private void swap(int[] data, int i, int j){
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
private void qSortRecursive(int[] data, int left, int right){
while (left < right){
int pivot = partition(data,left,right);
if (pivot - left < right - pivot){
qSortRecursive(data, left, pivot - 1);
left = pivot + 1;
} else {
qSortRecursive(data, pivot + 1, right);
right = pivot - 1;
}
}
Performing a tail call by reducing number of recursion solved my problem, thanks for help everyone :)
You can try to rewrite the algorithm without recursion. Well, you remove recursion by adding your own stack and in that case you can have available the entire memory, not just size of stack.
Something like: http://alienryderflex.com/quicksort/
I'm running this and I am being told it would not run fast enough. What is a good way to increase the speed of this running class? I am guessing I would need to change my nested while loops. That is the only thing I can think of. The if statements should all be linear...
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
public class QSortLab {
static int findpivot(Comparable[] A, int i, int j) {
return (i + j) / 2;
}
static <E> void swap(E[] A, int p1, int p2) {
E temp = A[p1];
A[p1] = A[p2];
A[p2] = temp;
}
static void quicksort(Comparable[] A, int i, int j) { // Quicksort
int pivotindex = findpivot(A, i, j); // Pick a pivot
swap(A, pivotindex, j); // Stick pivot at end
int k = partition(A, i, j-1, A[j]);
swap(A, k, j); // Put pivot in place
if ((k-i) > 1) quicksort(A, i, k-1); // Sort left partition
if ((j-k) > 1) quicksort(A, k+1, j); // Sort right partition
}
static int partition(Comparable[] A, int left, int right, Comparable pivot) {
while (left <= right) { // Move bounds inward until they meet
while (A[left].compareTo(pivot) < 0) left++;
while ((right >= left) && (A[right].compareTo(pivot) >= 0)) right--;
if (right > left) swap(A, left, right); // Swap out-of-place values
}
return left; // Return first position in right partition
}
}
What do you mean you need to change your nested while loops? Quick Sort is defined by those features. Removing wouldn't function properly.
As for optimization, by default it should be known that primitives vs objects tend to be different. E.g. primitives on stack/heap to keep stack small & heap stores object with refs able to be on stack.
So let's test some stuff
primitive quick sort (from here)
Integer quick sort (same code as above, but with Integer class)
Your original posted code
Your original posted code (w/ several edits)
Here's the entire code I used.
import java.util.Random;
public class App {
public static final int ARR_SIZE = 1000;
public static final int TEST_ITERS = 10000;
public static Random RANDOM = new Random();
public static void main(String[] args) {
int[] a = new int[ARR_SIZE];
Integer[] b = new Integer[ARR_SIZE];
Integer[] c = new Integer[ARR_SIZE];
Integer[] d = new Integer[ARR_SIZE];
long sum = 0, start = 0, end = 0;
for (int i = 0; i < TEST_ITERS; ++i) {
for (int j = 0; j < ARR_SIZE; ++j)
a[j] = RANDOM.nextInt();
start = System.nanoTime();
quickSort(a, 0, a.length - 1);
end = System.nanoTime();
sum += (end - start);
}
System.out.println((sum / TEST_ITERS) + " nano, qs avg - 'int'");
sum = 0;
for (int i = 0; i < TEST_ITERS; ++i) {
for (int j = 0; j < ARR_SIZE; ++j)
b[j] = RANDOM.nextInt();
start = System.nanoTime();
quickSort(b, 0, b.length - 1);
end = System.nanoTime();
sum += (end - start);
}
System.out.println((sum / TEST_ITERS) + " nano, qs avg - 'Integer'");
sum = 0;
for (int i = 0; i < TEST_ITERS; ++i) {
for (int j = 0; j < ARR_SIZE; ++j)
c[j] = RANDOM.nextInt();
start = System.nanoTime();
quicksort(c, 0, c.length - 1);
end = System.nanoTime();
sum += (end - start);
}
System.out.println((sum / TEST_ITERS) + " nano, qs avg - 'Comparable' (SO user code)");
sum = 0;
for (int i = 0; i < TEST_ITERS; ++i) {
for (int j = 0; j < ARR_SIZE; ++j)
d[j] = RANDOM.nextInt();
start = System.nanoTime();
qs_quicksort(d, 0, d.length - 1);
end = System.nanoTime();
sum += (end - start);
}
System.out.println((sum / TEST_ITERS) + " nano, qs avg - 'Comparable' (SO user code - edit)");
for (int i = 0; i < ARR_SIZE; ++i) {
final int n = RANDOM.nextInt();
a[i] = n;
b[i] = n;
c[i] = n;
d[i] = n;
}
quickSort(a, 0, a.length - 1);
Integer[] aConv = new Integer[ARR_SIZE];
for (int i = 0; i < ARR_SIZE; ++i)
aConv[i] = a[i];
quickSort(b, 0, b.length - 1);
quicksort(c, 0, c.length - 1);
qs_quicksort(d, 0, d.length - 1);
isSorted(new Integer[][] { aConv, b, c, d });
System.out.println("All properly sorted");
}
public static void isSorted(Integer[][] arrays) {
if (arrays.length != 4) {
System.out.println("error sorting, input arr len");
return;
}
for (int i = 0; i < ARR_SIZE; ++i) {
int val1 = arrays[0][i].compareTo(arrays[1][i]);
int val2 = arrays[1][i].compareTo(arrays[2][i]);
int val3 = arrays[2][i].compareTo(arrays[3][i]);
if (val1 != 0 || val2 != 0 || val3 != 00) {
System.out.printf("Error [i = %d]: a = %d, b = %d, c = %d", i, arrays[0][i], arrays[1][i], arrays[2][i], arrays[3][i]);
break;
}
}
}
public static int partition(int arr[], 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;
}
public 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 int partition(Integer[] arr, int left, int right) {
int i = left, j = right;
Integer pivot = arr[(left + right) / 2];
while (i <= j) {
while (arr[i].compareTo(pivot) < 0)
i++;
while (arr[j].compareTo(pivot) > 0)
j--;
if (i <= j) {
Integer temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
return i;
}
public static void quickSort(Integer[] 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);
}
static int findpivot(Comparable[] A, int i, int j)
{
return (i+j)/2;
}
static <E> void swap(E[] A, int p1, int p2) {
E temp = A[p1];
A[p1] = A[p2];
A[p2] = temp;
}
static void quicksort(Comparable[] A, int i, int j) { // Quicksort
int pivotindex = findpivot(A, i, j); // Pick a pivot
swap(A, pivotindex, j); // Stick pivot at end
int k = partition(A, i, j-1, A[j]);
swap(A, k, j); // Put pivot in place
if ((k-i) > 1) quicksort(A, i, k-1); // Sort left partition
if ((j-k) > 1) quicksort(A, k+1, j); // Sort right partition
}
static int partition(Comparable[] A, int left, int right, Comparable pivot) {
while (left <= right) { // Move bounds inward until they meet
while (A[left].compareTo(pivot) < 0) left++;
while ((right >= left) && (A[right].compareTo(pivot) >= 0)) right--;
if (right > left) swap(A, left, right); // Swap out-of-place values
}
return left; // Return first position in right partition
}
static <E> void qs_swap(E[] A, int p1, int p2) {
E temp = A[p1];
A[p1] = A[p2];
A[p2] = temp;
}
static void qs_quicksort(Comparable[] A, int i, int j) { // Quicksort
int pivotindex = (i+j)/2;
qs_swap(A, pivotindex, j); // Stick pivot at end
int k = qs_partition(A, i, j-1, A[j]);
qs_swap(A, k, j); // Put pivot in place
if ((k-i) > 1) qs_quicksort(A, i, k-1); // Sort left partition
if ((j-k) > 1) qs_quicksort(A, k+1, j); // Sort right partition
}
static int qs_partition(Comparable[] A, int left, int right, Comparable pivot) {
while (left <= right) { // Move bounds inward until they meet
while (A[left].compareTo(pivot) < 0) left++;
while ((right >= left) && (A[right].compareTo(pivot) >= 0)) right--;
if (right > left) { qs_swap(A, left, right); // Swap out-of-place values
left++; right--;}
}
return left; // Return first position in right partition
}
}
This produces the output:
56910 nano, qs avg - 'int'
69498 nano, qs avg - 'Integer'
76762 nano, qs avg - 'Comparable' (SO user code)
71846 nano, qs avg - 'Comparable' (SO user code - edit)
All properly sorted
Now, breaking down the results
The 'int' vs 'Integer' shows great diff when simply using primitives vs non-primitives (I'm sure at some points in the code there may be boxing but hopefully not in critical spots ;) - please edit this if so). The 'int' vs 'Integer' uses same code with exception of 'int' 'Integer'. See the following four method signatures that are used in this comparison, 'int'
public static int partition(int arr[], int left, int right)
public static void quickSort(int arr[], int left, int right)
and 'Integer'
public static int partition(Integer[] arr, int left, int right)
public static void quickSort(Integer[] arr, int left, int right)
respectively.
Then there are the method signatures related to the original code you posted,
static int findpivot(Comparable[] A, int i, int j)
static <E> void swap(E[] A, int p1, int p2)
static void quicksort(Comparable[] A, int i, int j)
static int partition(Comparable[] A, int left, int right, Comparable pivot)
and the modified ones,
static <E> void qs_swap(E[] A, int p1, int p2)
static void qs_quicksort(Comparable[] A, int i, int j)
static int qs_partition(Comparable[] A, int left, int right, Comparable pivot)
As you can see, in the modified code, findpivot was removed directly and replaced into the calling spot in quicksort. Also, the partition method gained counters for left and right respectively. left++; right--;
And finally, to ensure these 4 variations of quicksort actually did the sole purpose, sort, I added a method, isSorted() to check the validity of the same generated content and that it's sorted accordingly based on each of the 4 different sorts.
In conclusion, I think my edits may have saved a portion of time/nanoseconds, however I wasn't able to achieve the same time as the Integer test. Hopefully I've not missed anything obvious and edits are welcome if need be. Cheers
Well, I couldn't tell from testing whether this makes any difference at all because the timer on my machine is terrible , but I think most of the work in this algo is done with the swap function, so thinking about how to make that in particular more efficient, maybe the function call/return itself consumes cycles, and perhaps the creation of the temp variable each time the function is called also takes cycles, so maybe the code would be more efficient if the swap work was done in line. It was not obvious though when I tested on my machine as the nanotimer returned results +/- 20% each time I ran the program
public class QSort2 {
static int findpivot(Comparable[] A, int i, int j) {
return (i + j) / 2;
}
static Comparable temp;
static void quicksort(Comparable[] A, int i, int j) { // Quicksort
int pivotindex = findpivot(A, i, j); // Pick a pivot
// swap(A, pivotindex, j); // Stick pivot at end
temp = A[pivotindex];
A[pivotindex] = A[j];
A[j] = temp;
int k = partition(A, i, j - 1, A[j]);
//swap(A, k, j); // Put pivot in place
temp = A[k];
A[k] = A[j];
A[j] = temp;
if ((k - i) > 1) quicksort(A, i, k - 1); // Sort left partition
if ((j - k) > 1) quicksort(A, k + 1, j); // Sort right partition
}
static int partition(Comparable[] A, int left, int right, Comparable pivot) {
while (left <= right) { // Move bounds inward until they meet
while (A[left].compareTo(pivot) < 0) left++;
while ((right >= left) && (A[right].compareTo(pivot) >= 0)) right--;
if (right > left) {
//swap(A, left, right);} // Swap out-of-place values
temp = A[left];
A[left] = A[right];
A[right] = temp;
}
}
return left; // Return first position in right partition
}
}
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.