I am implementing a quicksort algorithm and have succesfully partitioned the input array around a pivot. The problem is, I am confused in how to recursively sort the 1st part and 2nd part of the array (i.e specifying the range) using the same input array.
Below is my implementation
class QuickSort {
int i;
int l = 0;
public void quicksort(int A[], int n) {
if (n == 1) {
return;
} else {
partition(A, 0, n);
//----Confused as from this point
quicksort(A, A[i]);
//Recursively sort both parts of the array
}
}
public int partition(int A[], int l, int r) {
int p = A[l];//Choose pivot
i = l + 1;
//Partition around A through P
for (int j = i; j < r; j++) {
if (A[j] < p) {
swap(A, i, j);
++i;
}
}
swap(A, l, i - 1 );
return i;
}
public void swap(int A[], int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public void display(int A[]){
for (int i = 0; i < A.length; i ++){
System.out.print(A[i] + " ");
}
}
}
class QuickSortApp{
public static void main(String args[]){
QuickSort quick = new QuickSort();
int A[] = {6,2,7,8,4,3,5};
quick.quicksort(A, A.length);
quick.display(A);
}
}
Please, I would also appreciate being corrected on any other inefficencies in my algorithm. Thanks
Change your quicksort() signature to quicksort(int[] A, int begin, int end)
Since, you actually did the sorting inside partition(). What I would do is this:
if (end-begin <= 1) {
return;
} else {
int pivot = partition(A, begin, end);
quicksort(A, begin, pivot);
quicksort(A, pivot, end);
}
Create a wrapper for the quicksort call with the signature you have which calls another one like quicksort(A, i, j) and your call from the wrapper will be quicksort(A, 0, n).
Related
I tried and wrote a code for Quicksort with middle element as pivot.
I was successful in writing one.
But Pivot has the property that:
Elements on its left are lesser than pivot and greater on its right.
I was not able to achieve this in my following code.
private static void QuickSortAlgorithm(int[] a, int i, int n)
{
if(i<n)
{
int part = partition(a,i,n);
QuickSortAlgorithm(a, i, part-1);
QuickSortAlgorithm(a, part, n);
}
}
private static int partition(int[] a, int i, int n)
{
int pivot = (i+n)/2;
int left = i;
int right = n;
while(left<=right)
{
while(a[left]<a[pivot]){
left++;
}
while(a[right]>a[pivot])
{
right--;
}
if(left<=right)
{
swap(a,left,right);
left++;
right--;
}
}
return left;
}
Main Method:
int a[]={5,7,3,9,1};
int n = a.length;
QuickSortAlgorithm(a,0,n-1);
System.out.println(Arrays.toString(a));
My doubt is:
I am sending left as my partitioned index.
But, when I am recursively calling QuickSortAlgorithm()
I am sending i to part-1 and part to n;
What should I send as partition index so that
I could call something like this: So that pivot property is satisfied?
QuickSortAlgorithm(a, i, part-1);
QuickSortAlgorithm(a, part+1, n);
Thank you:)
you have to send pivot value in first stack call inclusive and pivot+1 as lower index for second stack call.
You also have to put value of left as i+1 then your code will give an correct output
You have to change the return value to left+1 in partition method.
Try this program:
import java.io.*;
public class QuickSort {
public int partion(int[] a, int l, int h) {
int middle = (h+l)/2;
//System.out.println(middle);
int pivot = a[middle];
int i = l;
int j = h;
while (i <= j) {
while (a[i] < pivot) i++;
while (a[j] > pivot) j--;
if (i <= j) {
swap(a, i, j);
i++;
j--;
}
}
// swap(a,i,j);
System.out.println((i+j)/2);
return i-1;
}
public void quick(int[] a, int l, int h) {
if (l<h) {
int pi = partion(a, l, h);
System.out.println(pi);
if (l < pi - 1)
quick(a, l, pi+1);
if (pi < h)
quick(a, pi+1, h);
}
}
public void swap(int[] a, int l, int h){
int temp=a[l];
a[l]=a[h];
a[h]=temp;
}
public static void main(String[] args) {
int[] a = {10,80,30,90,40,50,70};
int l=0;
int h=a.length-1;
QuickSort q =new QuickSort();
q.quick(a,0,h);
System.out.println(" Sorted Array : ");
for(int e :a){
System.out.print(e+" , ");
}
}
}
You can choose the leftmost element in the array or you can choose any random element to be your pivot.
Check out the wikipedia page on quicksort for more details about choosing pivot
I've been banging my head on the table on this one.
I need to create an n sized array that is optimized for QuickSort Partition. It will be used to demonstrate the growth of QuickSort's best case. I know that for best case, QuickSort must select a pivot that divides the array in half for every recursive call.
I cannot think of a way to create an n-sized optimized array to test. Any help would be greatly appreciated.
Here is the algorithm in Java.
public class QuickSort {
private int length;
private void quickSort(int[] a, int p, int r) {
if (p < r) {
int q = partition(a, p, r);
quickSort(a, p, q - 1);
quickSort(a, q + 1, r);
}
}
private int partition(int[] a, int p, int r) {
int x = a[r];
int i = p - 1;
for (int j = p; j < r; j++) {
if (a[j] <= x) {
i++;
exchange(a, i, j);
}
}
exchange(a, i + 1, r);
return i + 1;
}
public void exchange(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
QuickSort(int[] a) {
if (a == null || a.length == 0) {
return;
}
length = a.length;
quickSort(a, 0, length - 1);
}
}
I know this is an old question, but I had the same question and finally developed a solution. I'm not a Java programmer, so don't blame me for Java code issues, please. I assumed that the quicksort algorithm always takes the first item as a pivot when partitioning.
public class QuickSortBestCase
{
public static void generate(int[] arr, int begin, int end)
{
int count = end - begin;
if(count < 3)
return;
//Find a middle element index
//This will be the pivot element for the part of the array [begin; end)
int middle = begin + (count - 1) / 2;
//Make the left part best-case first: [begin; middle)
generate(arr, begin, middle);
//Swap the pivot and the start element
swap(arr, begin, middle);
//Make the right part best-case, too: (middle; end)
generate(arr, ++middle, end);
}
private static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
private static void fillArray(int[] arr)
{
for(int i = 0; i != arr.length; ++i)
arr[i] = i + 1;
}
private static void printArray(int[] arr)
{
for(int item : arr)
System.out.print(item + " ");
}
public static void main(String[] args)
{
if(args.length == 0)
return;
int intCount = Integer.parseInt(args[0]);
int[] arr = new int[intCount];
//We basically do what quicksort does in reverse
//1. Fill the array with sorted values from 1 to arr.length
fillArray(arr);
//2. Recursively generate the best-case array for quicksort
generate(arr, 0, arr.length);
printArray(arr);
}
}
This program produces the same output for the array of 15 items, as described here: An example of Best Case Scenario for Quick Sort. And in case someone needs a solution in C++:
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case_sorted(RandomIterator begin, RandomIterator end)
{
auto count = std::distance(begin, end);
if (count < 3)
return;
auto middle_index = (count - 1) / 2;
auto middle = begin + middle_index;
//Make the left part best-case first
generate_quicksort_best_case_sorted(begin, middle);
//Swap the pivot and the start element
std::iter_swap(begin, middle);
//Make the right part best-case, too
generate_quicksort_best_case_sorted(++middle, end);
}
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case(RandomIterator begin, RandomIterator end)
{
{
auto current = begin;
RandomIterator::value_type value = 1;
while (current != end)
*current++ = value++;
}
generate_quicksort_best_case_sorted(begin, end);
}
I have my lovely little quick sort method ready to go, but I am unsure how to incorporate into a GUI (this will be my first GUI) and GUI do not like public statics and what-not...
So any ideas/know-how one to do a quick sort in a GUI without the publics etc would be amazing!
private void sortNumbersButtonActionPerformed(java.awt.event.ActionEvent evt) {
public static void main(String[] args) {
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) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
One simple option is to present your items in a JList. Here's a tutorial.
Nothing prevents you from using a static method in a GUI application.
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;
}
}
}
}