Working with quicksort - java

I am working on a quicksort from my data structures and algorithms book. In the book it lists a quicksort method then a hoare partition that it wants you to use with the quick sort. I seem to be having an issue where my hoare partition is using out of bounds numbers on the array. Either it uses 8 or if I try to fix that it goes to -1. Am I converting the books pseudo correctly into java?
Quicksort pseudo code
QuickSort(A, p, r)
if p<r
q = partition(A, p, r);
QuickSort(A, p, q - 1);
QuickSort(A, q, r);
Hoare-Partition Pseudo Code
Hoare-Partition(A,p,r)
x= A[p]
i = p-1
j=r+1
while true
repeat
j=j-1
until A [j] <= x
repeat
i = i +1
until A[i] >= x
if i < l
exchange A[i] with A[j]
else return j
My code
public class RunSort {
/**
* #param args
*/
public static void main(String[] args) {
int[] sortNumbers = {4,5,6,2,3,7,2,1};
int[] sorted = new int[sortNumbers.length];
sorted = QuickSort(sortNumbers, 1, sortNumbers.length);
System.out.print(sorted);
}
public static int[] QuickSort(int[] A, int p, int r){
if(p < r){
int q = partition(A, p, r);
QuickSort(A, p, q - 1);
QuickSort(A, q, r);
}
return A;
}
public static int partition(int[] A, int p, int r){
int x = A[p];
int i = p - 1;
int j = r + 1;
int temp;
while(true){
while(A[j] <= x && j != 0){
j--;
}
while(A[i] >= x && i != A.length){
i++;
}
if(i < j){
temp = A[i];
A[i] = A[j];
A[j] = temp;
}else{
return j;
}
}
}
}

Hint: repeat {...} until (condition) does not do the same thing as while (condition) {...}.

Depending on the text, pseudocode often uses 1..arrayLength as the index bounds on an array, but in Java, et al., it's 0..arrayLength-1. You'll need to adjust the arguments to the main QuickSort call in main.
(As a nitpick, QuickSort should start with a lowercase letter by convention.)

Related

merge sort is duplicatiing array entries

I was trying to implement in Java the merge sort algorithm according to Cormen's Introduction to Algorithms. The problem with my code (below) is that the main array is duplicating some of its entries during the merge step.
Is someone able to catch what I'm doing wrong?
Thank you!
static void merge(int a[], int p, int q, int r)
{
int n1 = q - p;
int n2 = (r - q);
int [] left = new int[n1 + 1];
int [] right = new int[n2 + 1];
int pp = p;
int qq = q;
for(int i = 0; i < n1; i++)
{
left[i] = a[++pp];
}
for(int i = 0; i < n2; i++)
{
right[i] = a[++qq];
}
left[left.length-1] = Integer.MAX_VALUE;
right[right.length-1] = Integer.MAX_VALUE;
int i = 0;
int j = 0;
for(int k = p; k < r; k++)
{
if(left[i] <= right[j])
{
a[k] = left[i];
i++;
}
else
{
a[k] = right[j];
j++;
}
}
}
static int [] mergeSort(int a[], int p, int r)
{
if(p < r)
{
int q = (p + r)/2;
mergeSort(a, 1, q);
mergeSort(a, q + 1, r);
merge(a, p, q, r);
}
return a;
}
Part of the issue here is the example from the book apparently uses index range from 1 to length. It will be simpler if you change the index range from 0 to length-1, which I assume in the rest of my answer.
Use post increment while copying to left[] and right[] as answered by laune (since index range 0 to length-1).
left[i] = a[pp++];
...
right[i] = a[qq++];
The main issue is the merge function is not checking to see if it reached the end of the left or right run during a merge. This can be fixed by changing the inner if to:
if (i < n1 && (j >= n2 || left[i] <= right[j]))
The recursive calls to merge sort should be:
mergeSort(a, p, q);
mergeSort(a, q, r);
Not shown, but the initial call to mergeSort should be:
mergeSort(a, 0, a.length);
There's no need to allocate the extra element in left and right (since index range is 0 to length-1).
int [] left = new int[n1];
int [] right = new int[n2];
I think that this is in error (as well as its sibling in the next loop):
left[i] = a[++pp];
You want to copy starting with pp = p, so don't increment before you access the array element:
left[i] = a[pp++];

Quicksort Counter Example

Firstly (as the question title implies) I'm not looking for why the bellow partitioning method doesn't work, rather a modification to it so that it will work for the following input:
int[] a = {1,2,8,4,5,7};
Here's the partition method along with some other stuff:
static int[] swap (int[] a,int i,int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
return a;
}
static int partition (int[] a,int l,int r){
int i = l;
int j = r;
int v = a[l];
while (true) {
while (a[i] < v) {
if (i == r) break;
i++;
}
while (a[j] > v) {
if (j == l) break;
j--;
}
if (i >= j) break;
a = swap(a,i,j);
}
a = swap(a, l, j);
return j;
}
void sort(int[] a,int l,int r){
int j = partition(a, l, r);
sort(a, l, j-1);
sort(a, j+1, r);
}
public static void main(String[] args) {
int[] a = {1,2,8,4,5,7};
System.out.println(partition(a,0,5));
}
Output:
0
The output is the index of the pivot returned from the partition method. 0, as the index of the pivot, makes sense in terms of the definition, i.e. everything left of the pivot is smaller and everything right of the pivot is larger, but clearly runs into a problem in sort namely:
sort(a, l, j-1);
where you have the right pointer being negative (j-1 = 0-1 = -1). My question again being is there a modification to the above method(s) that will maintain the definition (everything left of the pivot is smaller and everything right of the pivot is larger) and not run into the problem in sort.
The missing part is the line
if ( l >= r ) return;
in the beginning of the sort method. This is actually the recursion stop step so it is necessary to have it anyway to prevent endless recursion. But besides that, it also solves your problem, because if you call sort(0,-1) then -1 is less than 0, so it prevents further processing of that index.

Converting Merge Sort pseudocode to running Java code

I tried to convert this Merge Sort pseudocode into Java but don't get the right output. Here is the pseudocode:
Merge-Sort(A, p, r )
if p < r
then q←(p+r)/2
Merge-Sort(A, p, q)
Merge-Sort(A, q + 1, r )
Merge(A, p, q, r )
Merge(A, p, q, r )
for k←1 to r−p+1 do
if j>r or (i ≤ q and A[i] ≤ A[j])
then B[k]←A[i]; i←i+1 else B[k]←A[j];j←j+1
for k←1 to r−p+1 do A[k+p−1]←B[k]
And this is my Java code for it:
public class MergeSort {
public static void main(String[] args) {
int[] a = {2, 6, 3, 5, 1};
mergeSort(a, 0, a.length - 1);
for (int i = 0; i < a.length; i++) {
System.out.print(" " + a[i]);
}
}
public static void mergeSort(int[] a, int from, int to) {
final int begin = from, end = to;
if (begin < end) {
final int mid = (begin + end) / 2;
MergeSort.mergeSort(a, begin, mid);
MergeSort.mergeSort(a, mid+1, end);
MergeSort.merge(a, begin, mid, end);
}
}
private static void merge(int[] a, int from, int mid, int to) {
final int begin = from, mitte = mid, end = to;
int[] B = new int[a.length];
int i = begin, j = mitte;
for (int k = 0; k <= end-begin; k++) {
if (j > end || (i <= mitte && a[i] <= a[j])) {
B[k] = a[i];
i++;
} else {
B[k] = a[j];
j++;
}
}
for (int k = 0; k < end-begin; k++) {
a[k + begin] = B[k];
}
}
Sadly it is not working like that. I think i do something wrong with some indexes but I can't figure out where exactly the error is.
I need to stick as close as possible to this pseudocode.
It would be great if someone could show me what I am doing wrong.
The pseudocode given for the Merge algorithm is somewhat incorrect because it does not say anything about the situation when only one pointer moves while other remains stationary.
In the above mentioned case you would have to separately fill out temporary array for by moving that stationary pointer.
Also the required length of B is to - from + 1 and it should be j = mitte + 1 instead of j = mitte The correct code for the merge is :
private static void merge(int[] a, int from, int mid, int to) {
final int begin = from, mitte = mid, end = to;
int[] B = new int[end-begin+1];
int k=0;
int i = begin, j = mitte+1;
while(i<=mid&&j<=end)
if(a[i]<=a[j]){
B[k++] = a[i];
i++;
} else {
B[k++] = a[j];
j++;
}
//in case i remained stationary
while(i<=mid)
B[k++] = a[i++];
//in case j remained stationary
while(j<=end)
B[k++] = a[j++];
//Now copy the array
i=0;
for(k=begin;k<=end;++k)
a[k]=B[i++];
}

Quick sort explanation on an assignment

I am writing a specific variant of quicksort class. However; the directions on this variant of quick sort is confusing me. I have written the code for quick sort, but I do not understand the description. Can anyone help me understand this description means for the variant so I can finalize it?
Description: implement a variant of quicksort with pivots chosen according to pivot_pos. That is, whenever the quicksort makes a recursive call to quicksort a subarray (A, p, r), it chooses as the pivot min(p+pivot,r).
To my interpretation, this is saying to include within the if statement of quicksort a int value of min(p + pivot, r). It would partition the array with the pivot representing this value, and quicksorting the array with this value as well.
public static int partition(int[] a, int p, int r)
{
int x = a[r];
int i = p - 1;
for( int j = p; j <= r - 1; j++)
{
if(a[j] <= x)
{
i++;
swap(a, i, j);
}
}
swap(a, i + 1, r);
return i + 1;
}
public static void quick_sort(int[] a, int p, int r)
{
if(p < r)
{
int q = partition(a, p, r);
quick_sort(a, p, q - 1);
quick_sort(a, q + 1, r);
}
}

stackoverflow error in quicksort

So I've been trying to implement a quicksort myself, but it generates a stackoverflowerror, but I can't seem to find what the cause is.
Can someone help me?
public static int partition(int[] a, int p, int q){
int i = 0;
for (int j = p; j < q; ++j){
if(a[j] <= a[q]){
int tmp = a[j];
a[j] = a[i];
a[i] = tmp;
i++;
}
}
int tmp = a[i];
a[i] = a[q];
a[q] = tmp;
return i;
}
public static void qsort(int[] a, int p, int q){
if(p < q){
int x = partition(a, p, q);
qsort(a, p, x - 1);
qsort(a, x + 1, q);
}
}
public static void main(String args[]){
int[] a = {4, 6, 2, 9, 8, 23, 0, 7};
qsort(a, 0, a.length - 1);
for(int i : a){
System.out.print(i + " ");
}
}
There are several bugs, but the immediate one you're hitting is that in partition(), i is not constrained to be between p and q. You pretty quickly end up in a situation where p=2, q=3 yet the final value of i is 1. This results in infinite recursion as qsort() keeps calling itself with identical arguments.
A stack overflow error means the stop condition for the recursion is never reached, in this case p < q is never true. Use a debugger, set a breakpoint for that line, and look for when qsort() is repeatedly recursively called with the same parameters.

Categories

Resources