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);
}
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'm having a bit of a problem writing a recursive function that sorts an array in java recursively . Right now it appears as though I have an infinite loop, and I can't seem to figure out where.
The primary function "rec_piv" searches from index1 to the pivot point and sorts the first half, then switches from the pivot point to the length of the array and sorts the second half. All of the comparisons are recorded by an int. [The array is of random size from 2 to 2014]
Thanks very much in advance!
public class Recursive_pivot {
private Random random_size = new Random();
private int size = random_size.nextInt(1024) + 2;
public int[] a = new int[size];
private Random elements = new Random();
/* variable for rec_piv */
public int temp=0;
public int temp2=0;
private Random rand_pivot = new Random();
private int pivot = rand_pivot.nextInt(size) + 2;
private int first_half =a[0+1];
private int second_half=a[pivot+1];
private int first_index=0; //first half of the array
private int second_index=pivot; //second half of the array
//The pivot is randomly chosen.
public int comparisons =0; //count the number of comparisons.
public void fill(){
for (int q=0; q<a.length; q++) {
/* filling the array */
a[q] = elements.nextInt(100 ) + 1;
}
}
public void rec_piv(int first_index, int second_index) {
if(first_index < pivot) {
if(first_half > a[first_index]) {
comparisons++;
temp = a[first_index];
a[first_index] = a[first_half];
a[first_half] = temp;
}
rec_piv(first_index+1, second_index);
}
if(second_index < a.length) {
if(second_half > a[second_index]) {
comparisons++;
temp2 = a[second_index];
a[second_index] = a[second_half];
a[second_half] = temp2;
}
rec_piv(first_index, second_index+1);
}
} //end of rec_piv
}//end of class.
You are trying to do a QSort here is a simple version of it.
public void quickSort(int array[], int start, int end)
{
int i = start; // index of left-to-right scan
int k = end; // index of right-to-left scan
if (end - start >= 1) // check that there are at least two elements to sort
{
int pivot = array[start];
while (k > i)
{
while (array[i] <= pivot && i <= end && k > i)
i++;
while (array[k] > pivot && k >= start && k >= i)
k--;
if (k > i)
swap(array, i, k);
}
swap(array, start, k);
quickSort(array, start, k - 1); // quicksort the left partition
quickSort(array, k + 1, end); // quicksort the right partition
}
else // if there is only one element in the partition, do not do any sorting
{
return; // the array is sorted, so exit
}
}
public void swap(int array[], int index1, int index2)
// pre: array is full and index1, index2 < array.length
// post: the values at indices 1 and 2 have been swapped
{
int temp = array[index1]; // store the first value in a temp
array[index1] = array[index2]; // copy the value of the second into the first
array[index2] = temp; // copy the value of the temp into the second
}
from this site.
http://www.mycstutorials.com/articles/sorting/quicksort
Here's the code. The output is a very nearly correctly sorted array, but there are several elements out of order. Anyone able to spot the error?
I'm pretty sure the swap and quicksort methods are correct, but I'm posting all the methods here just in case.
package quicksort;
import java.util.Random;
import java.util.Arrays;
public class QuickSort {
/**
* #param args the command line arguments
*/
private static int[] u;
public static void main(String[] args) {
u = makeArray(100);
System.out.println(Arrays.toString(u));
quicksort(0, u.length - 1);
System.out.println(Arrays.toString(u));
}
public static int[] makeArray(int n) {
int[] a = new int[n];
int j;
Random r = new Random();
for (int i = 0; i < n; i++) {
j = (r.nextInt(100) + 1);
a[i] = j;
}
return a;
}
public static int partition(int left, int right, int pivot) {
int p = pivot; // pivot
int lPt = left - 1;
int rPt = right + 1;
while (true) {
while ((lPt < right) && (u[++lPt] < p));
while ((rPt > left) && (u[--rPt] > p));
if (lPt >= rPt) {
break;
} else {
swap(lPt, rPt);
System.out.println("Swapping " + lPt + " " + rPt);
}
}
return lPt;
}
public static void swap (int a, int b) {
int temp = u[a];
u[a] = u[b];
u[b] = temp;
}
public static void quicksort(int l, int r) {
if (r - l <= 0) {
return;
} else {
int part = partition(l, r, u[l]);
quicksort (l, part - 1);
quicksort (part + 1, r);
}
}
}
The problem is in the partition method. The pivot element is not being placed in its correct position at the end of your swaps. I've changed the method signature so that you pass in the position of the pivot element, rather than the value of the pivot, so in quicksort() you would now write:
int part = partition(l, r, l);
In the body of the pivot method, I swapped the pivot element to the end of the section (by swapping with right). So that we then ignore this element with our swaps, I took away the "+ 1" on the initialisation of rPT. I then added a statement after your while loop to move the pivot element into place. With those three changes, the method now looks like this:
public static int partition(int left, int right, int pivotPosition) {
int p = u[pivotPosition]; // pivot
// Move pivot to the end
swap(pivotPosition, right);
int lPt = left - 1;
int rPt = right;
while (true) {
while ((lPt < right) && (u[++lPt] < p));
while ((rPt > left) && (u[--rPt] > p));
if (lPt >= rPt) {
break;
} else {
swap(lPt, rPt);
System.out.println("Swapping " + lPt + " " + rPt);
}
}
// Put pivot in its place
swap(lPt, right);
return lPt;
}
With these changes, the code works for me.
You have to find a values in the left list which is larger than the pivot element and find a value in the right list which is smaller then the pivot element then we exchange the values.
package quicksort;
import java.util.Random;
import java.util.Arrays;
public class QuickSort {
/**
* #param args the command line arguments
*/
private static int[] u;
public static void main(String[] args) {
u = makeArray(10);
System.out.println(Arrays.toString(u));
quicksort(0, u.length - 1);
System.out.println(Arrays.toString(u));
}
public static int[] makeArray(int n) {
int[] a = new int[n];
int j;
Random r = new Random();
for (int i = 0; i < n; i++) {
j = (r.nextInt(100) + 1);
a[i] = j;
}
return a;
}
private static void quicksort(int low, int high) {
int i = low, j = high;
int pivot = u[low];
while (i <= j) {
while (u[i] < pivot) {
i++;
}
while (u[j] > pivot) {
j--;
}
if (i <= j) {
exchange(i, j);
i++;
j--;
}
}
if (low < j) {
quicksort(low, j); // note here
}
if (i < high) {
quicksort(i, high); // note here
}
}
private static void exchange(int i, int j) {
int temp = u[i];
u[i] = u[j];
u[j] = temp;
}
}
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;
}
}
}
}
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).