MergeSort with CutOFF slower than regular MergeSort - Java - 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);
}
}
}

Related

How to avoid my index going out of bounds in quicksort?

I'm trying implementing a pseudocode of quicksort that chooses the different elements as pivot, such as first element as pivot, last element as pivot, random element as pivot, and median element as pivot. First i'm working on the first element as pivot, but if the pivot is the greatest number in the array the index will grow to be greater than the length of the array causing an index out of bounds for length. The quicksort implementation works for when the pivot is the first element of the array and the first element of the array is the smallest. The error happens at line 27 when the pivot (in this case) is 8, it will stay at the while([i] < pivot) adding 1 to i.
How can i avoid this?
This is the pseudocode i'm using:
Partition(A, p, r):
pivot ← A[p]`
i ← p + 1
j ← r
while i ≤ j
while A[i] < pivot
i ← i + 1
while A[j] > pivot
j ← j - 1
if i < j
swap A[i] with A[j]
swap A[p] with A[j]
return j
And this is my code:
public class QuickSort {
//this global variable counts the comparisons
static long countComp = 0;
static void quickSort(int []array, int ft, int lt) {
if(ft < lt) {
int q = partitionFtE(array, ft, lt);
quickSort(array, ft, q - 1);
quickSort(array, q + 1, lt);
}
}
//this method does quicksort with first element as pivot, ft = first element, lt = last element
static int partitionFtE(int []array, int ft, int lt) {
int pivot = array[ft];
int i = ft + 1;
int j = lt;
while(i <= j){
while(array[i] < pivot) {
i = i + 1;
}
while(array[j] > pivot) {
j = j - 1;
}
//here we swap elements if i is lower than j
countComp++;
if(i < j) {
int temp = 0;
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
//here we change the pivot where it suppose to be in the array
int temp2 = array[i];
temp2 = array[ft];
array[ft] = array[j];
array[j] = temp2;
return j;
}
static void printArray(int []array) {
for(int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println("\n" + countComp);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// int choice = menuData();
int[] intArray = {8, 7, 6, 5, 4, 3, 2, 1};
int n = intArray.length;
quickSort(intArray, 0, n - 1);
System.out.println("Sorted array: ");
printArray(intArray);
}
}
I used another pseudocode from class to fix this.
This is the pseudocode:
//ft is first element, lt is last element
pivot := array[ft]
i := ft + 1;
for j:= ft + 1 to array length do
if array[j] < pivot
swap array[j] and array[i]
swap array[ft] and array[i - 1]
return i -1
And this is the partition method:
static int partition(int []array, int ft, int lt) {
int pivot = array[ft];
int i = ft + 1;
for(int j = ft + 1; j < array.length; j ++) {
if(array[j] < pivot) {
int temp = 0;
temp = array[j];
array[j] = array[i];
array[i] = temp;
i = i + 1;
}
}
int temp2 = array[ft];
array[ft] = array[i-1];
array[i-1] = temp2;
return i - 1;
}
Example of a post decrementing | incrementing Hoare partition scheme:
void QuickSort(int *a, int lo, int hi)
{
int i, j;
int p, t;
if(lo >= hi)
return;
p = a[lo + (hi-lo)/2];
i = lo;
j = hi;
while (i <= j){
while (a[i] < p)i++;
while (a[j] > p)j--;
if (i > j)
break;
t = a[i];
a[i] = a[j];
a[j] = t;
i++;
j--;
}
QuickSort(a, lo, j);
QuickSort(a, i, 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;
}

Merge sort implementation questions in Java

I'm in an algorithms course and am learning about merge sort. Our professor recommended we try to implement the pseudo code provided in the book.
Am I correct in using Integer.MAX_VALUE as a sentinel value when
sorting an array of integers (used in lines 8 & 9 in the Merge
method pseudo code below)?
For line 2 of the Merge-Sort pseudo code method, is it correct to code that in Java using Math.ceil() like I did? (Edit: It's actually floor and I updated my code to reflect this.)
If you see any other mistakes please let me know!
Here is the pseudo code the book gives for merge sort.
And, here is how I coded it in Java:
public void mergeSort(int[] arrNums, int p, int r) {
if (p < r) {
int q = (p + r) / 2;
mergeSort(arrNums, p, q);
mergeSort(arrNums, q + 1, r);
merge(arrNums, p, q, r);
}
}
public void merge(int[] arrNums, int p, int q, int r) {
int nOne = q - p + 1;
int nTwo = r - q;
int[] arrLeft = new int[nOne + 1];
int[] arrRight = new int[nTwo + 1];
for (int i = 0; i < nOne; i++) {
arrLeft[i] = arrNums[p + i - 1];
}
for (int j = 0; j < nTwo; j++) {
arrRight[j] = arrNums[q + j];
}
arrLeft[nOne] = Integer.MAX_VALUE;
arrRight[nTwo] = Integer.MAX_VALUE;
// Tracks arrLeft index
int i = 0;
// Tracks arrRight index
int j = 0;
for (int k = p; k < r; k++) {
if (arrLeft[i] <= arrRight[j]) {
arrNums[k] = arrLeft[i];
i++;
} else {
arrNums[k] = arrRight[j];
j++;
}
}
}
The last for loop in your merge method, variable k should start from p - 1:
for (int k = p - 1; k < r; k++) {
if (arrLeft[i] <= arrRight[j]) {
arrNums[k] = arrLeft[i];
i++;
} else {
arrNums[k] = arrRight[j];
j++;
}
}
Pseudo code in many text books likes to start array index from 1, so here you need to subtract it by 1.
I implemented it a few days ago, if someone will be interested.
private static void mergeSort(double[] arr, int start, int end){
if(start < end){
int mid = ( start + end ) / 2;
mergeSort(arr, start, mid);
mergeSort(arr, mid + 1, end);
Merge(arr, start, mid, end);
}
}
private static void Merge(double[] arr, int start, int mid, int end){
double[] leftArray = new double[mid - start + 2];
double[] rightArray = new double[end - mid + 1];
for(int i = start; i <= mid; i++ )
leftArray[i - start] = arr[i];
for (int i = mid + 1; i <= end; i++ )
rightArray[i - mid - 1] = arr[i];
leftArray[mid - start + 1] = Double.POSITIVE_INFINITY;
rightArray[end - mid] = Double.POSITIVE_INFINITY;
int leftIndex = 0, rightIndex = 0;
for (int k = start; k <= end; k++){
if(leftArray[leftIndex] <= rightArray[rightIndex])
arr[k] = leftArray[leftIndex++];
else
arr[k] = rightArray[rightIndex++];
}
}

How to optimize quick sort without using Auxiliary array

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;
}
}

Explanation on how inversions work with merge sort

my code currently works just fine, but my trouble is understand why it works. Why are certain parameters the way they need to be and why do certain have to to happen. I tried two other solutions and this seems to be the only working one.
public static int invCounter(int[] ranking)
{
int[] b = new int[ranking.length];
int[] aux = new int[ranking.length];
for (int i = 0; i < ranking.length; i++)
b[i] = ranking[i];
int inversions = mergeSortInv(ranking, b, aux, 0, ranking.length - 1);
return inversions;
}
private static int mergeInv(int[] a, int[] aux, int lo, int mid, int hi) {
int inversions = 0;
// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = a[k];
}
// merge back to a[]
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (aux[j] < aux[i]) { a[k] = aux[j++]; inversions += (mid - i + 1); }
else a[k] = aux[i++];
}
return inversions;
}
private static int mergeSortInv(int[] a, int[] b, int[] aux, int lo, int hi) {
int inversions = 0;
if (hi <= lo) return 0;
int mid = lo + (hi - lo) / 2;
inversions += mergeSortInv(a, b, aux, lo, mid);
inversions += mergeSortInv(a, b, aux, mid+1, hi);
inversions += mergeInv(b, aux, lo, mid, hi);
return inversions;
}
If someone could explain why this works and how it works that would be great.

Categories