I need help figuring out what exactly is wrong with this partitioning code. I have been struggling with it for a few days now, cant seem to wrap my head around it.
The pIdx is the pivot index, left and right are the bounds integer options for the array, and the array a is just an array or stored long values.
protected static int partition(long[] a, int left, int right, int pIdx) {
//long numbers[] = {4,3,8,9,7,2,1,5};
long pivot = a[pIdx];
swap(a, pIdx, right);
int storeIndex = left;
for(int i=left; i<right; i++) {
if(a[i] <= pivot)
swap(a, i, storeIndex);
}//for
swap(a, right, storeIndex);
return storeIndex;
}//partitio
I tried fixing your code. See if this works for you.
protected static int partition(long[] a, int left, int right, int pIdx) {
//long numbers[] = {4,3,8,9,7,2,1,5};
long pivot = a[pIdx];
swap(a, pIdx, right);
int storeIndex = left;
for(int i=left; i<right; i++) {
if(a[i] < pivot) {
swap(a, i, storeIndex);
storeIndex = storeIndex + 1;
}
}
swap(a, storeIndex, right);
return storeIndex;
}
Related
Can someone please explain to me why this QuickSort algorithm has bad performance?
I followed a tutorial from Derek Banas so I thought it would optimal.
public static void quickSort(int[] arr, int left, int right){
if(left>=right) return;
int pivot = arr[right];
int index = partition(arr, left, right, pivot);
quickSort(arr, left, index-1);
quickSort(arr, index+1, right);
}
private static int partition(int[] arr, int left, int right, int pivot){
int leftPointer = left-1;
int rightPointer = right;
while(true){
while(arr[++leftPointer]<pivot && leftPointer<=rightPointer);
while(arr[--rightPointer]>pivot && rightPointer>leftPointer);
if(leftPointer>=rightPointer) break;
else{
//swap values
int temp = arr[leftPointer];
arr[leftPointer] = arr[rightPointer];
arr[rightPointer] = temp;
}
}
int tempP = arr[leftPointer];
arr[leftPointer] = arr[right];
arr[right] = tempP;
return leftPointer;
}
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;
}
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.
public static void sort(int[] a){
if (a.length>1){
int pivot=a[a.length-1];
int left=0;
int right=a.length-1;
while(left<=right){
while(a[left]<pivot)
left++;
while(a[right]>pivot)
right--;
if(left<=right){
int tmp=a[right];
a[right]=a[left];
a[left]=tmp;
left++;
right--;
}
}
int[] tmp1=new int[right];
for(int i=0;i<tmp1.length;i++)
tmp1[i]=a[i];
int[] tmp2=new int[a.length-right-1];
for(int i=left;i<a.length;i++)
tmp2[i-left]=a[i];
sort(tmp1);
sort(tmp2);
}
}
Im trying to write a quicksort algorithm with one function and it doesn't work. Any help is aprrecitated. Thanks
EDIT: I solved it thanks everyone for your input.
I think the problem is that at the end you are not using the tmp1 and tmp2 to conform the new array a... Here is a way to do it without creating others arrays:
public static void sort(int[] a, int left, int right){
if (left < right){
int pivot = a[right];
int pos = left - 1;
for (int i = left; i < right; i++)
if (a[i] <= pivot)
Swap(a, ++pos, i);
Swap(a, pos + 1, right);
sort(a, left, pos);
sort(a, pos + 1, right);
}
}
public static void Swap(int[] a, int i, int j){
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
The first call of sort must be sort(a, 0, a.length - 1)
I hope this helps you
Your sort method seems extremely compared to most int sort methods. Here is a quick and easy one.
public static void sort(int[] intArray){
int n = intArray.length;
int temp = 0;
for(int i=0; i < n; i++){
for(int j=1; j < (n-i); j++){
if(intArray[j-1] > intArray[j]){
temp = intArray[j-1];
intArray[j-1] = intArray[j];
intArray[j] = temp;
}
}
}
}
This is just a bubble sort. I don't see the point of the recursion. There a bunch of other types of sorts but for a short array length this is the easiest (IMO). Look up some other ones, its kinda cool what they do (Sorting algorithm).
To get to your question....
Like #RobinCurbelo said, you didn't use temp1 and temp2 correctly. Your idea is there but I think you were thinking too much into what you needed to do.
i am trying to implement quicksort but i am not getting correct results. Here is my code:
public static void quickSort(Comparable[] a, int start, int stop) {
if (start < stop) {
int pivot = partition(a, start ,stop);
System.out.print("Pivot: "+a[pivot]+" Array: ");
printArray(a);
quickSort(a,start,pivot-1);
quickSort(a,pivot+1, stop);
}
}
public static int partition(Comparable[] a, int start, int stop) {
Comparable pivot = a[stop];
int i = start;
int j = stop-1;
while (i < j) {
while( (isLess(a[i], pivot)|| isEqual(a[i], pivot)))
i++;
while((isGreater(a[j], pivot)|| isEqual(a[j], pivot)))
j--;
if(i < j)
swap(a, i,j);
}
swap(a,i, stop);
return i;
}
For input: {51,17,82,10,97,6,23,45,6,73}, i am getting result: 6 6 10 17 23 45 51 73 97 82
For input: {12,9,4,99,120,1,3,10}, i am getting an index out of bounds error. Would appreciate some help in where i am going wrong.
Your two problems are unrelated.
The problem with {51,17,82,10,97,6,23,45,6,73} is — what happens when stop == start + 1? Then i == start == stop - 1 == j, so you never enter the while-loop, so you unconditionally swap(a, i, stop) — even if a[i] was already less than a[stop].
The problem with {12,9,4,99,120,1,3,10} is seemingly that you didn't read the stacktrace. ;-) Assuming you have a decent Java compiler and JVM, it should have given you the exact line-number and problematic index, so you would have seen that the problem is in this line:
while((isGreater(a[j], pivot)|| isEqual(a[j], pivot)))
once j gets to -1. (This will happen if pivot is the very least value in the range of interest.) You just need to add a check for that:
while(j > start && (isGreater(a[j], pivot)|| isEqual(a[j], pivot)))
(and, for that matter, for the corresponding case of i:
while(i < stop && (isLess(a[i], pivot)|| isEqual(a[i], pivot)))
)
. . . and you need to learn how to debug your code. :-)
I recommend you Algorithms: Design and Analysis, very good internet course from Stanford. After this course you will write such codes more easily. It is a bit enhanced version, pivot is chosen as a median of three. Note that you don't have to write your own printArray() function. In Java you can do it with System.out.println(Arrays.toString(numbers)). Also you can observe how to call quickSort() in more elegant way, with only one argument, using method overloading.
public class QuickSort
{
public static void main(String[] args)
{
int numbers[] =
{ 51, 17, 82, 10, 97, 6, 23, 45, 6, 73 };
quickSort(numbers);
System.out.println(Arrays.toString(numbers));
}
public static void quickSort(int[] array)
{
quickSort(array, 0, array.length - 1);
}
private static void quickSort(int[] array, int left, int right)
{
if (left >= right)
{
return;
}
int pivot = choosePivot(array, left, right);
pivot = partition(array, pivot, left, right);
quickSort(array, left, pivot - 1);
quickSort(array, pivot + 1, right);
}
private static int partition(int[] array, int pivot, int left, int right)
{
swap(array, pivot, left);
pivot = left;
int i = left + 1;
for (int j = left + 1; j <= right; j++)
{
if (array[j] < array[pivot])
{
swap(array, j, i);
i++;
}
}
swap(array, pivot, i - 1);
return i - 1;
}
private static void swap(int[] array, int j, int i)
{
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
private static int choosePivot(int[] array, int left, int right)
{
return medianOfThree(array, left, (left + right) / 2, right);
// return right;
}
private static int medianOfThree(int[] array, int aIndex, int bIndex, int cIndex)
{
int a = array[aIndex];
int b = array[bIndex];
int c = array[cIndex];
int largeIndex, smallIndex;
if (a > b)
{
largeIndex = aIndex;
smallIndex = bIndex;
}
else
{
largeIndex = bIndex;
smallIndex = aIndex;
}
if (c > array[largeIndex])
{
return largeIndex;
}
else
{
if (c < array[smallIndex])
{
return smallIndex;
}
else
{
return cIndex;
}
}
}
}