How to optimize quick sort without using Auxiliary array - java

This is a quick sort as you know and I want to optimize it in itself arrayList and don't want to use another array or using linkedList. Suppose that the half numbers of array was sorted in ascending order and others are in among them.I mean optimization is less swap in code that depends on where does choose a pivot or change the partition function.if you know how I should optimize it please help me.total of count variable is a number of swap if I write it true. Thanks!
public class Quick {
public static void main(String[] args) {
int[] a = {4,6,0,7,1,12,2,18,4,9,4,13,5,6};
sort(a,0,a.length - 1);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
static void sort(int[] a, int lo, int hi){
if(lo < hi){
int j = partiton(a ,lo ,hi);
sort(a, lo ,j - 1);
sort(a, j + 1, hi);
}
}
static int partiton(int[] a, int lo, int hi){
int i = lo; int j = hi + 1;
int v = a[lo];
int count = 0;
while(true){
while(a[++i] < v){
if (i == hi)
break;
}
while(v < a[--j]){
if (j == lo)
break;
}
if (i >= j){
break;
}
swap(a, i, j);
count = count + 1;
}
swap(a, lo, j);
count = count + 1;
System.out.println("swap : " + count);
return j;
}
static void swap(int[] a, int i, int j){
int temp = 0;
temp = a[j];
a[j] = a[i];
a[i] = temp;
}
}

Related

MergeSort with CutOFF slower than regular MergeSort - Java

So my goal is to time three different algorithms and show the difference in execution time in ms when they have the same input. The problem I get is that my implementation of Merge Sort with cutoff (to insertion sort) is slower then the regular one. Here are the different methods. I tried debugging and working on smaller input but I could't find the problem. The purpose of the CUTOFF variable - by changing the values I should observe speedup in execution time.
Insertion sort implementation:
public static void insertionSort(int inputArray[]) {
int j, temp;
//start the for loop for iterating the array elements in the array
for (int i = 1; i < inputArray.length; i++) {
//stores the value at index at i int temp
temp = inputArray[i];
//assign i-1 to j
j = i - 1;
//while loop iterates upto j>i-1 and inputArray[j]>temp are true
while ((j > -1) && (inputArray[j] > temp)) {
inputArray[j + 1] = inputArray[j];
j--;
}
//store temp values into particular index j+1
inputArray[j + 1] = temp;
}
}
For the merge sort implementation I use the same merge method for "CutOff" and "Regular". Here is the whole class:
public static class MergeSort {
private static final int CUTOFF = 0;
void merge(int inputArray[], int lo, int mid, int hi) {
// Creating temporary subarrays
int leftArray[] = new int[mid - lo + 1];
int rightArray[] = new int[hi - mid];
// Copying our subarrays into temporaries
for (int i = 0; i < leftArray.length; i++)
leftArray[i] = inputArray[lo + i];
for (int i = 0; i < rightArray.length; i++)
rightArray[i] = inputArray[mid + i + 1];
// Iterators containing current index of temp subarrays
int indexLeft = 0;
int indexRight = 0;
// Copying from leftArray and rightArray back into array
for (int i = lo; i < hi + 1; i++) {
// If there are still uncopied elements in R and L, copy minimum of the two
if (indexLeft < leftArray.length && indexRight < rightArray.length) {
if (leftArray[indexLeft] < rightArray[indexRight]) {
inputArray[i] = leftArray[indexLeft];
indexLeft++;
} else {
inputArray[i] = rightArray[indexRight];
indexRight++;
}
} else if (indexLeft < leftArray.length) {
// If all elements have been copied from rightArray, copy rest of leftArray
inputArray[i] = leftArray[indexLeft];
indexLeft++;
} else if (indexRight < rightArray.length) {
// If all elements have been copied from leftArray, copy rest of rightArray
inputArray[i] = rightArray[indexRight];
indexRight++;
}
}
}
void sortNoCutOff(int inputArray[], int lo, int hi) {
if (lo < hi) {
//Put the cut of here
int mid = lo + (hi - lo) / 2;
sortNoCutOff(inputArray, lo, mid);
sortNoCutOff(inputArray, mid + 1, hi);
merge(inputArray, lo, mid, hi);
}
}
void sortCutOff(int inputArray[], int lo, int hi) {
if (lo <= hi + CUTOFF -1) {
//Put the cut of here
insertionSort(inputArray);
} else{
int mid = (hi + lo) / 2;
sortCutOff(inputArray, lo, mid);
sortCutOff(inputArray, mid + 1, hi);
merge(inputArray, lo, mid, hi);
}
}
}

Implementing Wikipedia in-place quicksort pseudocode in Java

I'm using the pseudocode called Lomuto partition scheme on https://en.wikipedia.org/wiki/Quicksort. But I just don't understand what it is that I am doing wrong here. The array never gets organized (regardless of the input size). This is preparation for my final exam. My professor wants us to use this algorithm, but I can't just learn it unless I have an understanding of how it works by testing it.
private static void quickSort(Integer A[], int l, int r) {
if (l < r) {
int k = partition(A, l, r);
quickSort(A, l, k - 1);
quickSort(A, k + 1, r);
}
}
private static int partition(Integer A[], int l, int r) {
int pivot = A[r];
int i = l;
for (int j = l; j <= r - 1; j++) {
if (A[j] <= pivot) {
i++;
int temp = A[j];
A[j] = pivot;
pivot = temp;
}
}
int temp = A[i + 1];
A[i + 1] = A[r];
A[r] = temp;
return i + 1;
}
I don't know what else to say other than that you just didn't transcribe the pseudocode correctly. At the beginning of partition, i should equal l - 1, but you set it to l.
Also, you're not swapping A[i] with A[j] within the nested loop. Here's the correct implementation:
private static int partition(Integer A[], int l, int r) {
int pivot = A[r];
int i = l - 1;
for (int j = l; j <= r - 1; j++) {
if (A[j] < pivot) {
i++;
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
int temp = A[i + 1];
A[i + 1] = A[r];
A[r] = temp;
return i + 1;
}

Why is this test for my quick sort failing?

I'm trying to implement quicksort using the median of three algo and it fails a unit test I wrote related to a small partition. I changed my earlier partition and now it passes one of the tests it used to fail, but still fails the one at the bottom:
My code is:
public class QuickSort {
static void swap(int[] A, int i, int j) {
int tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
static final int LIMIT = 15;
static int partition(int[] a, int left, int right){
int center = (left + right) / 2;
if(a[center] < (a[left]))
swap(a,left,center);
if(a[right-1] < a[left])
swap(a,left,right);
if(a[right-1] < a[center])
swap(a,center,right);
swap(a,center,right - 1);
return a[right - 1];
}
static void quicksort(int[] a, int left, int right){
if(left + LIMIT <= right){
int pivot = partition(a,left,right);
int i = left;
int j = right - 1;
for(;;){
while(a[++i] < pivot){}
while(a[--j] > pivot){}
if(i < j)
swap(a,i,j);
else
break;
}
swap(a,i,right - 1);
quicksort(a,left,i-1);
quicksort(a,i+1,right);
}
else{
insertionSort(a);
}
}
public static void insertionSort(int[] a){
int j;
for(int p = 1; p < a.length; p++){
int tmp = a[p];
for(j = p; j > 0 && tmp < a[j-1]; j--)
a[j] = a[j-1];
a[j] = tmp;
}
}
}
This test fails:
public void smalltest() throws Exception {
int[] Arr_orig = {3,9,8,2,4,6,7,5};
int[] Arr = Arr_orig.clone();
int pivot = QuickSort.partition(Arr, 0, Arr.length);
for (int i = 0; i != pivot; ++i)
assertTrue(Arr[i] <= Arr[pivot]); //fails!
for (int i = pivot + 1; i != Arr.length; ++i)
assertTrue(Arr[pivot] < Arr[i]);
}
There is a conflict between using right-1 and right in this sequence:
if(a[right-1] < a[left])
swap(a,left,right);
You need to decide if right is going to be the index to the last element, or 1 + index to the last element (an "ending" index).
There may be other problems, but this is the first one I noticed.

How can I fix my code? Quick-sort fill with random numbers

I am writing a code using quicksort but can't seen to make it work.
I have declared my array to size 20 and filled it with random integers. Then I called my sort method to do the quicksorting. The show method just prints the output. Still my code doesn't work at all.
My entire code for quick-sorting:
public class JavaApplication3 {
public static void main(String[] args) {
QuickSort B = new QuickSort();
int[] snum = new int [20];
for(int index = 0; index < snum.length; index++ ){
snum[index]= (int) (Math.random ());
}
B.sort(snum);
B.show(snum);
}
}
class QuickSort{
public static void sort(int [] a ){
quicksort(a, 0, a.length -1);
}
private static void quicksort(int[] a, int lo, int hi){
if(hi <= lo) return;
int j = partition(a, lo, hi);
quicksort(a, lo, j-1);
quicksort(a, j+1, hi);
}
private static void exch(int [] a, int i, int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
private static int partition(int[] a, int lo, int hi){
int i= lo;
int j = hi+1;
int pivot = a[lo];
while(i<=j){
while(a[i] < pivot){
i++;
}
while(a[j] > pivot){
j--;
}
if(i <= j){
exch(a, i, j);
i++;
j--;
}
}
if (lo < j)
quicksort(a, lo, j);
if (i < hi)
exch(a, i, j);
return j;
}
public static void show(int[]a){
for(int i=0; i<a.length;i++)
System.out.print(a[i] + " ");
System.out.println();
}
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
20 at javaapplication3.QuickSort.partition(JavaApplication3.java:61)
at javaapplication3.QuickSort.quicksort(JavaApplication3.java:43) at
javaapplication3.QuickSort.sort(JavaApplication3.java:39) at
javaapplication3.JavaApplication3.main(JavaApplication3.java:29) Java
Result: 1
One problem is that Math.random produces fractional numbers less than one, and when you cast it to int, those numbers result in 0. So multiply math.random by 10.
Hope this helps.
int hoaresPartition(int *arr, int lo, int hi){
int pivot = arr[lo];
int i = lo - 1;
int j = hi + 1;
while (true){
do {
j = j -1;
}while (arr[j] > pivot);
do {
i = i+1;
}while (arr[i] < pivot);
if ( i < j){
int temp;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}else
return j;
}
}

Quicksort (Java) causes StackOverFlow at array.length > 60k

My code works properly (to my knowledge) up until my input array size (a.length) is around 62,000 at which time I consistently get a StackOverFlowError. I previously had used 2 recursive calls to quicksort (less than, and greater than the pivot q) and then I switched to tail recursion. As you can see, I'm selecting the pivot to be the value at the end of the array. I know this isn't the best way to choose a pivot, but I still shouldn't be seeing StackOverFlowErrors with an array size this small, right? What could be causing this? Thanks in advance! Here's my code:
public static void quicksort(int[] a, int p, int r)
{
int q;
while (p < r)
{
q = partition(a, p, r);
quicksort(a, p, q - 1);
p = q + 1;
}
}
public static int partition(int[] a, int p, int r)
{
int j = p - 1;
int x = a[r];
for (int i = p; i < r; i++)
{
if (a[i] <= x)
{
j++;
swap(a, i, j);
}
}
j++;
swap(a, j, r);
return j;
}
private static void swap(int[] a, int i, int j)
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
The worst-case input (sorted order) makes quicksort Θ(n^2). Partition always puts a single element on one side of the partition (Cormen et al.). By randomizing the sort (choosing a random pivot) no particular input elicits its worst-case behavior.
import java.util.Random;
public class Quicksort
{
private static Random rand = new Random();
public static void quicksort(int[] arr, int left, int right)
{
if (left < right)
{
int pivot = randomizedPartition(arr, left, right);
quicksort(arr, left, pivot);
quicksort(arr, pivot + 1, right);
}
}
private static int randomizedPartition(int[] arr, int left, int right)
{
int swapIndex = left + rand.nextInt(right - left) + 1;
swap(arr, left, swapIndex);
return partition(arr, left, right);
}
private static int partition(int[] arr, int left, int right)
{
int pivot = arr[left];
int i = left - 1;
int j = right + 1;
while (true)
{
do
j--;
while (arr[j] > pivot);
do
i++;
while (arr[i] < pivot);
if (i < j)
swap(arr, i, j);
else
return j;
}
}
private static void swap(int[] arr, int i, int j)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// Sort 100k elements that are in reversed sorted order
public static void main(String[] args)
{
int arr[] = new int[100000];
for (int i = 0; i < arr.length; i++)
arr[i] = arr.length - i;
System.out.println("First 20 elements");
System.out.print("Before sort: ");
for (int i = 0; i < 20; i++)
System.out.print(arr[i] + " ");
System.out.println();
quicksort(arr, 0, arr.length - 1);
System.out.print("After sort: ");
for (int i = 0; i < 20; i++)
System.out.print(arr[i] + " ");
System.out.println();
}
}
Given the right input, your implementation will recurse once for every single element of the array. 60,000 recursive calls could easily be enough to overflow the stack in Java in the default configuration.

Categories