I am trying to implement QuickSort on an array of ints.
All my methods function correctly except for the partition. The partition starts with getting the midpoint, then ordering, first, middle, last.
Comes out to {1,6,5,4,3,2,7}
then somewhere after this I get {1, 2, 5, 3, 4, 7, 6} as the final outcome
Can anyone tell me where I can make adjustments?
expected output should be {1,2,3,4,5,6,7}
import java.util.Arrays;
public class Test {
public static void main(String[]args) {
int [] a = {7,6,5,4,3,2,1};
quickSort(a);
System.out.println(Arrays.toString(a));
}
public static void quickSort( int [] a) {
quickSort(a,0,a.length - 1);
}
public static void quickSort(int [] a,int start,int end) {
if(start<end) {
int pivotIndex = partition(a, start, end);
quickSort(a,start,pivotIndex-1); // sort left partition
quickSort(a,pivotIndex+1,end); // sort right partition
}
}
public static int partition(int [] a, int start, int end) {
int mid =midpoint(start,end);
sortFirstMiddleLast(a,start,mid,end);
swap(a,start,end-1);
int pivotIndex = end -1;
int pivotValue = pivotIndex;
int indexFromLeft = start +1;
int indexFromRight = end -2;
boolean done = false;
while (!done) {
while (a[indexFromLeft]<a[pivotValue]) {
indexFromLeft++;
}
while (a[indexFromRight]>a[pivotValue]) {
indexFromRight--;
}
if (indexFromLeft < indexFromRight) {
swap(a,indexFromLeft,indexFromRight);
indexFromLeft++;
indexFromRight--;
}
else {
done=true;
}
}
swap(a,pivotIndex,indexFromLeft);
pivotIndex=indexFromLeft;
return pivotIndex;
}
public static void sortFirstMiddleLast(int [] a, int start, int mid, int end) {
if (a[start]>a[mid]) {
swap(a,start,mid);
}
else if (a[mid]>a[end]) {
swap(a,mid,end);
}
else if (a[start]>a[end]) {
swap(a,start,end);
}
else if(a[start] > a[mid]) {
swap (a,start,mid);
}
}
private static void swap(int[] a, int first, int second) {
int temp = a[first];
a[first] = a[second];
a[second] = temp;
}
private static int midpoint(int first, int last) {
return first + (last - first) / 2;
}
}
check whether if start =< array.size -1 and end >= 0 before execute futher after lines :
int indexFromLeft = start +1;
int indexFromRight = end -2;
terminate recursions on that condition.
If you use the class created below, you won't have any problems.
class QuickSort{
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low-1);
for (int j=low; j<high; j++)
{
if (arr[j] <= pivot)
{
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp;
return i+1;
}
void sort(int arr[], int low, int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
sort(arr, low, pi-1);
sort(arr, pi+1, high);
}
}
Try this one
swap(a,start,end-1);
int pivotIndex = end -1; // removed -1
int pivotValue = pivotIndex;
int indexFromLeft = start +1; // removed +1
int indexFromRight = end -2; // removed -2
public static int partition(int [] a, int start, int end) {
int mid =midpoint(start,end);
sortFirstMiddleLast(a,start,mid,end);
swap(a,start,end-1);
int pivotIndex = end ;
int pivotValue = pivotIndex;
int indexFromLeft = start ;
int indexFromRight = end;
boolean done = false;
while (!done) {
while (a[indexFromLeft]<a[pivotValue]) {
indexFromLeft++;
}
while (a[indexFromRight]>a[pivotValue]) {
indexFromRight--;
}
if (indexFromLeft < indexFromRight) {
swap(a,indexFromLeft,indexFromRight);
indexFromLeft++;
indexFromRight--;
}
else {
done=true;
}
}
swap(a,pivotIndex,indexFromLeft);
pivotIndex=indexFromLeft;
return pivotIndex;
}
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);
}
}
Why is this code not working ?
The following is a recursive approach to quicksort.
Can somebody also suggest a better partitioning algorithm with pivot take as first element ?
import java.util.*;
class QuickSort
{
public static void callQuickSort(int[] array,int left,int right)
{
if(left<right)
{
int s = partition(array,left,right);
callQuickSort(array,left,s-1);
callQuickSort(array,s+1,right);
}
}
public static int partition(int[] array,int left,int right)
{
int pI = left; //pI = partition index
int pivot = array[right];
for(int i=left;i<=right-1;i++)
{
if(array[i] <= pivot)
{
swap(array[i],array[pI]);
pI++;
}
}
swap(array[pI],array[right]);
return pI;
}
static void swap(int a,int b)
{
int temp = a;
a = b;
b = temp;
}
public static void main(String args[])
{
int[] array = {7,2,1,6,8,5,3,4};//array declared
callQuickSort(array,0,7);
System.out.println("Sorted array is - ");
for(int i=0;i<8;i++)
System.out.print(array[i]+"\t");
}
}//end of class
The output is
7 2 1 6 8 5 3 4
The above code returns the array without any change. Why isn't the array changing ?
In java data is passed in method by value, not by reference, so you can't use swap method as you do.
Here is working code:
class QuickSort {
public static void callQuickSort(int[] array, int left, int right) {
if (left < right) {
int s = partition(array, left, right);
callQuickSort(array, left, s - 1);
callQuickSort(array, s + 1, right);
}
}
public static int partition(int[] array, int left, int right) {
int pI = left; //pI = partition index
int pivot = array[right];
for (int i = left; i <= right - 1; i++) {
if (array[i] <= pivot) {
int temp = array[i];
array[i] = array[pI];
array[pI] = temp;
// swap(array[i], array[pI]);
pI++;
}
}
int temp = array[pI];
array[pI] = array[right];
array[right] = temp;
// swap(array[pI], array[right]);
return pI;
}
/*static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}*/
public static void main(String args[]) {
int[] array = {7, 2, 1, 6, 8, 5, 3, 4};//array declared
callQuickSort(array, 0, 7);
System.out.println("Sorted array is - ");
for (int i = 0; i < 8; i++)
System.out.print(array[i] + "\t");
}
}//end of class
I am trying to implement quick sort using Java.The partition function does what it should do.That is,partition the array around the pivot(I've chosen the element as the pivot). But the final output is not in sorted order.I cannot figure the error out.Can someone help?
public class Quick_sort {
public static int arr[] = {11, 2, 7, 1, 5, 4, 12, 65, 23};
public static int temp = 0;
public static void main(String args[]) {
int p=0;
int r=arr.length;
quick_sort(p,r);
for(int i: arr)
System.out.println(i);
}
public static int partition(int p, int r) {
if(p < r) {
int pivot=arr[p];
int i=1;
for(int j=1;j<r;j++) {
if(arr[j]<pivot) {
temp=arr[j];
arr[j]=arr[i];
arr[i]=temp;
i++;
}
}
temp=arr[i-1];
arr[i-1]=arr[p];
arr[p]=temp;
for(int m=0;m<r;m++) {
if(arr[m]==pivot) {
temp=m;
}
}
}
return temp;
}
public static void quick_sort(int p,int r) {
if(p>=r) return;
int index=partition(p,r);
quick_sort(p,index-1);
quick_sort(index+1,r-1);
}
}
In your last line
quick_sort(index+1,r-1);
You skip the last element of the array. But the last element should be sorted as well. Try it with:
quick_sort(index+1,r);
And it is better to adapt the variables i and j in the partition method to the current processed part of the array.
So I tried to fix it. Try it with (main function):
int r=arr.length-1;
and change the partition function to:
public static int partition(int p, int r) {
if(p < r) {
int pivot=arr[p];
int i= p ;
for(int j=(p+1);j<=r;j++) {
if(arr[j]<pivot) {
temp=arr[j];
arr[j]=arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = temp;
i++;
}
}
temp = i;
}
return temp;
}
as well as the in the quick-sort method:
quick_sort(p,index-1);
quick_sort(index+1,r);
Do you see your problem? Your main problem was to not adapt the variables to the smaller parts you are actually looking at at the moment. It did well for the first partition round, but not for the following, as you had the former variables.
This is a complete example of a QuickSort implementation :
public class QuickSort {
public static void main(String[] args) {
int[] x = { 9, 2, 4, 7, 3, 7, 10 };
System.out.println(Arrays.toString(x));
int low = 0;
int high = x.length - 1;
quickSort(x, low, high);
System.out.println(Arrays.toString(x));
}
public static void quickSort(int[] arr, int low, int high) {
if (arr == null || arr.length == 0)
return;
if (low >= high)
return;
// pick the pivot
int middle = low + (high - low) / 2;
int pivot = arr[middle];
// make left < pivot and right > pivot
int i = low, j = high;
while (i <= j) {
while (arr[i] < pivot) {
i++;
}
while (arr[j] > pivot) {
j--;
}
if (i <= j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
// recursively sort two sub parts
if (low < j)
quickSort(arr, low, j);
if (high > i)
quickSort(arr, i, high);
}
}
you can find more here.
I'm trying to implement the randomized selection algorithm that returns the K-th largest element in an array. The algorithm in the code below works when pivot is always set to equal the first element in the array. How do I get the code to work such that it finds the K-th largest using a randomly generated pivot point ?
import java.util.Random;
public class RandomizedKSelection {
private static Random generator = new Random();
public static int partition(int[] A, int start, int end) {
// start = generator.nextInt(end); This Line breaks the code
int pivot = A[start];
int pivotPosition = start++;
while (start <= end) {
// scan for values less than the pivot
while ((start <= end) && (A[start] < pivot)) {
start++;
}
// scan for values greater than the pivot
while ((end >= start) && (A[end] >= pivot)) {
end--;
}
if (start > end) {
// swap the end uncoformed
// element with the pivot
swap(A, pivotPosition, end);
}
else {
// swap unconformed elements:
// start that was not lesser than the pivot
// and end that was not larger than the pivot
swap(A, start, end);
}
}
return end;
}
#SuppressWarnings("unused")
// iterative version
private static int orderStatistic(int[] A, int k, int start, int end) {
int pivotPosition = partition(A, start, end);
while (pivotPosition != k - 1) {
if (k - 1 < pivotPosition) {
end = pivotPosition - 1;
}
else {
start = pivotPosition + 1;
}
pivotPosition = partition(A, start, end);
}
return A[k - 1];
}
public static int kthLargest(int[] A, int k) {
return orderStatistic(A, A.length - k + 1, 0, A.length - 1);
}
public static void swap(int[] A, int i, int j){
int temp = A[i];
A[i]= A[j];
A[j] = temp;
}
}
I've got a `partition implementation from wikibooks. I changed your code to use 0-based indices (you can find examples for 0-based indices more easily), you can wrap them if you like (see kthLargest1Based). Small randomized test arguments the validity of the algorithm.
import java.util.Arrays;
import java.util.Random;
public class RandomizedKSelection {
private static Random generator = new Random();
private static int partition(int[] array, int begin, int end) {
int index = begin + generator.nextInt(end - begin + 1);
int pivot = array[index];
swap(array, index, end);
for (int i = index = begin; i < end; ++ i) {
if (array[i] <= pivot) {
swap(array, index++, i);
}
}
swap(array, index, end);
return (index);
}
// iterative version
private static int orderStatistic(int[] A, int k, int start, int end) {
int pivotPosition = partition(A, start, end);
while (pivotPosition != k) {
if (k < pivotPosition) {
end = pivotPosition - 1;
} else {
start = pivotPosition + 1;
}
pivotPosition = partition(A, start, end);
}
return A[k];
}
public static int kthLargest(int[] A, int k) {
return orderStatistic(A, A.length - k - 1, 0, A.length - 1);
}
public static int kthLargest1Based(int[] A, int k) {
return kthLargest(A, k - 1);
}
public static int kthLargestSafe(int[] A, int k) {
Arrays.sort(A);
return A[A.length - k - 1];
}
public static void swap(int[] A, int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public static void main(String[] args) {
Random random = new Random();
for (int i = 0; i < 1000000; i++) {
int[] A = new int[1 + random.nextInt(1000)];
int max = 1 + random.nextInt(2 * A.length);
for (int j = 0; j < A.length; j++) {
A[j] = random.nextInt(max);
}
int k = random.nextInt(A.length);
if (RandomizedKSelection.kthLargest(A, k) != RandomizedKSelection.kthLargestSafe(A, k)) {
System.out.println("BUG");
}
}
}
}
I'm trying to implement a version of Mergesort using Multi Threading. First off, I know there's a billion threads (give or take...) on here, and I've read a few to no avail! I'm trying to show that using threads in parallel speeds the process up. The issue I'm having however is that my code does not display and speed up whatsoever, in fact, rather the opposite.
With one thread, my times is in the 10's of thousands. With two, my time increases to a few hundred thousand, then with 4 threads my time borders on 7 figures. My initial thoughts were to play around with the join() method and ensure that was in the right place, and have done so, but to no success.
Any help would be greatly appreciated, and an example command line argument is something like;
java working 16 4 (For 4 threads).
Apologies for the lack of comments too throughout!
import java.util.*;
class working
{
private static int sizeVector;
private static int noThreads;
static void sort(int[] input)
{
mergeSort(input, 0, input.length - 1, noThreads);
}
static void mergeSort(int[] array, int low, int high, int noThreadsUp)
{
//private int noThreadsUp;
if (low < high)
{
int mid = (low+high)/2;
if (noThreadsUp > 1)
{
NewThread td = new NewThread(array, low, mid, noThreadsUp/2);
td.start();
/*try{
td.join();
}catch(Exception e){}*/
mergeSort(array, mid+1, high, noThreadsUp/2);
try{
td.join();//UNSURE WHERE THIS SHOULD BE
}catch(Exception e){}
merge(array, low, mid, high);
}
else
{
mergeSort(array, low, mid, noThreadsUp/2);
mergeSort(array, mid+1, high, noThreadsUp/2);
merge(array, low, mid, high);
}
}
}
static void merge(int[] array, int low, int mid, int high)
{
int[] temp = new int[high - low + 1];
int left = low;
int right = mid+1;
int k = 0;
while (left <= mid && right <= high)
{
if(array[left] < array[right])
{
temp[k] = array[left];
left = left+1;
}
else
{
temp[k] = array[right];
right = right + 1;
}
k = k + 1;
}
if (left <= mid)
{
while(left <= mid)
{
temp[k] = array[left];
left = left + 1;
k = k + 1;
}
}
else if (right <= high)
{
while(right <= high)
{
temp[k] = array[right];
right = right + 1;
k = k + 1;
}
}
for (int m = 0; m < temp.length; m++)
{
array[low+m] = temp[m];
}
}
static int[] readInputArray()
{
int[] a = new int[sizeVector];
for (int i = 0; i < sizeVector; i++)
{
Random generator = new Random();
a[i] = generator.nextInt();
}
return a;
}
static void printArray(int[] array)
{
for(int i = 0; i<array.length; i++)
System.out.println(array[i]);
}
public static void main(String[] args)
{
sizeVector = Integer.parseInt(args[0]);
noThreads = Integer.parseInt(args[1]);
int[] inputArray = readInputArray();
System.out.println("INPUT ARRAY: ");
printArray(inputArray);
long startTime = System.nanoTime();
sort(inputArray);
long endTime = System.nanoTime();
long finalTime = endTime - startTime;
System.out.println("SORTED ARRAY: ");
printArray(inputArray);
System.out.println("Time: " + finalTime);
}
static class NewThread extends Thread
{
private int low;
private int mid;
private int[] array;
private int noThreadsDown;
//private int threads;
public NewThread(int[] array, int low, int mid, int noThreadsDown)
{
this.low = low;//Ensure using the right start
this.mid = mid;//Ensure using the right end
this.array = array;
this.noThreadsDown = noThreadsDown;
//this.threads = threads;
}
public void run()
{
mergeSort(array, low, mid, noThreadsDown/2);
System.out.println(noThreadsDown);
}
}//End NewThread
}
It could be best using RecurssionAcition class in java 7, which split up into two parts left and right.
Sum left = new Sum(array, low, mid);
Sum right = new Sum(array, mid, high);
left.fork();
long rightAns = right.compute();
long leftAns = left.join();
return leftAns + rightAns;
Here some code that works.
public class TestMergeSort{
public static void main(String[] args){
// Threaded merge sort (and printing)
int[] toSort = {191,2,3,5,6,7,5,3,21,3,4};
printArr(toSort);
concurrentMergeSort(toSort);
printArr(toSort);
}
public static void concurrentMergeSort(int[] toSort){
int[] tmpArray = new int[toSort.length];
try{
// Start the mergesort
ConcurrentMergeSort sort = new ConcurrentMergeSort(toSort, tmpArray, 0, toSort.length - 1);
sort.start();
sort.join();
} catch(InterruptedException e){
e.printStackTrace();
}
}
public static void printArr(int[] a){
for(int i = 0; i < a.length; i++){
System.out.print(a[i] + " ,");
}
System.out.println();
}
}
public class ConcurrentMerge extends Thread{
private int[] a;
private int[] tmpArray;
private int leftPos;
private int rightPos;
private int rightEnd;
public ConcurrentMerge(int[] a, int[] tmpArray, int leftPos, int rightPos, int rightEnd){
this.a = a;
this.tmpArray = tmpArray;
this.leftPos = leftPos;
this.rightPos = rightPos;
this.rightEnd = rightEnd;
}
public void run(){
int leftEnd = rightPos - 1;
int tmpPos = leftPos;
int numElements = rightEnd - leftPos + 1;
// Main loop
while( leftPos <= leftEnd && rightPos <= rightEnd )
if( a[ leftPos ] <= a[ rightPos ] )
tmpArray[ tmpPos++ ] = a[ leftPos++ ];
else
tmpArray[ tmpPos++ ] = a[ rightPos++ ];
// Copy rest of the left half
while( leftPos <= leftEnd )
tmpArray[ tmpPos++ ] = a[ leftPos++ ];
// Copy rest of the right half
while( rightPos <= rightEnd )
tmpArray[ tmpPos++ ] = a[ rightPos++ ];
// Copy tmpArray back
for( int i = 0; i < numElements; i++){
a[ rightEnd ] = tmpArray[ rightEnd-- ];
}
}
}
import java.util.Arrays;
public class ConcurrentMergeSort extends Thread{
private int[] a;
private int[] tmpArray;
private int left;
private int right;
public ConcurrentMergeSort(int[] a, int[] tmpArray, int left, int right){
this.a = a;
this.tmpArray = tmpArray;
this.left = left;
this.right = right;
}
public void run(){
if(this.left < this.right){
try{
int center = ( this.left + this.right ) / 2;
ConcurrentMergeSort p = new ConcurrentMergeSort(this.a, this.tmpArray, this.left, center);
ConcurrentMergeSort q = new ConcurrentMergeSort(this.a, this.tmpArray, center + 1, this.right);
ConcurrentMerge r = new ConcurrentMerge(this.a, this.tmpArray, this.left, center + 1, this.right);
// Sort
p.start();
q.start();
p.join();
q.join();
// Merge
r.start();
r.join();
}
catch(InterruptedException e){
e.printStackTrace();
}
}
}
public int[] getA(){
return this.a;
}
}