Where are comparisons in java sorting methods? - java

Question: Where are comparisons being made in each separate sorting method?
Also if you know please tell me which method count numbers are wrong and where to place my counters instead.trying to understand where and how many times sorting methods make comparisons.
Method A B
Selection 4950 4950
Bubble 99 9900
Insertion 99 5049
Merge 712 1028
Shell 413 649
Quick 543 1041
Okay so to explain some parts, basically Array A is an array from 1-100 in ascending order. So this should be the minimum number of comparisons.
Array B is 100-1 in descending order. So I believe it should be the maximum number of comparisons. Array C is just randomly generated numbers, so it changes every time.
I feel like my selection and bubble sorts were counted correctly. Feel free to let me know where comparisons are being made that I haven't counted, or if I'm counting wrong comparisons.
Side note: Made some global variable to count the methods that were recursive in multiple sections.
class Sorting
{
static int[] X = new int[100];
static int mergecount = 0;
static int quickcount = 0;
public static void selectionSort(int list[])
{
int count = 0;
int position = 0, n = list.length;
for(int j = 0; j < n-1; j++)
{
position = j;
for(int k = j+1; k < n; k++)
{
count++;
if(list[k] < list[position])
position = k;
}
Swap(list, j, position);
}
System.out.println("counter" + count);
}
public static void Swap(int list[], int j, int k)
{
int temp = list[j];
list[j] = list[k];
list[k] = temp;
}
public static void bubbleSort(int list[])
{
int count = 0;
boolean changed = false;
do
{
changed = false;
for(int j = 0; j < list.length - 1; j++)
{
count++;
if(list[j] > list[j + 1])
{
Swap(list, j, j+1);
changed = true;
}
}
} while(changed);
System.out.println("counter" + count);
}
public static void insertionSort(int list[])
{
int count = 0;
for(int p = 1; p < list.length; p++)
{
int temp = list[p];
int j = p;
count++;
for( ; j > 0 && temp < list[j - 1]; j = j-1)
{
list[j] = list[j - 1];
count++;
}
list[j] = temp;
}
System.out.println("counter" + count);
}
public static void mergeSort(int list[])
{
mergeSort(list, 0, list.length - 1);
System.out.println("counter" + mergecount);
}
public static void mergeSort(int list[], int first, int last)
{
if(first < last)
{
int mid = (first + last) / 2;
mergeSort(list, first, mid);
mergeSort(list, mid + 1, last);
Merge(list, first, mid, last);
}
}
public static void Merge(int list[], int first, int mid, int last)
{
int count = 0;
int first1 = first, last1 = mid;
int first2 = mid + 1, last2 = last;
int temp[] = new int[list.length];
int index = first1;
while(first1 <= last1 && first2 <= last2)
{
if(list[first1] < list[first2])
{
temp[index] = list[first1++];
mergecount++;
}
else
temp[index] = list[first2++];
index++;
mergecount++;
}
while(first1 <= last1)
temp[index++] = list[first1++];
while(first2 <= last2)
temp[index++] = list[first2++];
for(index = first; index <= last; index++)
list[index] = temp[index];
}
public static void shellSort(int list[])
{
int count = 0;
int n = list.length;
for(int gap = n / 2; gap > 0; gap = gap == 2 ? 1: (int) (gap/2.2))
for(int i = gap; i < n; i++)
{
int temp = list[i];
int j = i;
count++;
for( ; j >= gap && (temp < (list[j - gap])); j -= gap)
{
list[j] = list[j - gap];
count++;
}
list[j] = temp;
}
System.out.println("counter" + count);
}
public static void quickSort(int start, int finish, int list[])
{
int count = 0;
int left = start, right = finish, pivot, temp;
pivot = list[(start + finish) / 2];
do
{
while(list[left] < pivot)
{
left++;
quickcount++;
}
while(pivot < list[right])
{
right--;
quickcount++;
}
if(left <= right)
{
temp = list[left];
list[left++] = list[right];
list[right--] = temp;
quickcount++;
}
} while(left < right);
if(start < right)
quickSort(start, right, list);
if(left < finish)
quickSort(left, finish, list);
}
public static void copy(int list[])
{
for(int i = 0; i < list.length; i++)
X[i] = list[i];
}
public static void restore(int list[])
{
for(int i = 0; i < list.length; i++)
list[i] = X[i];
}
public static void displayArray(int list[])
{
for(int k = 0; k < list.length; k++)
System.out.print(list[k] + " ");
System.out.println();
}
public static void main(String args[])
{
int[] A = new int[100];
for(int i = 0; i < A.length; i++)
A[i] = i + 1;
int[] B = new int[100];
int q = 100;
for(int i = 0; i < B.length; i++)
B[i] = q--;
int[] C = new int[100];
for(int i = 0; i < C.length; i++)
C[i] = (int)(Math.random() * 100 + 1);
displayArray(A);
copy(A);
selectionSort(A);
displayArray(A);
restore(A);
}

Note that QuickSort performance is greatly influenced by your choice of the pivot. With both of your test arrays sorted (ascending / descending) and because you are picking pivot as array[length/2] you are actually always picking the best pivot. So your test case B won't generate maximum number of comparisons for quicksort. If you were picking array[0] as pivot you'd get maximum number of comparisons for test case A and B.
The easiest way to count comparisons is to use a compare function and do it in there.
static int compareCount = 0;
int compareInt(int a, int b) {
compareCount++;
return a - b; // if 0 they are equal, if negative a is smaller, if positive b is smaller
}
Now just use compareInt in all your algorithms and you'll get an accurate count. You'll have to reset compareCount between each run though.

Related

Find the number of distinct triplets sums to a given integer

You have been given a random integer array/list(ARR) and a number X. Find and return the number of distinct triplet(s) in the array/list which sum to X.
I have written this code:
public class Solution {
public static void merge(int arr[], int lb, int mid, int ub) {
int n1 = mid - lb + 1;
int n2 = ub - mid;
int arr1[] = new int[n1];
int arr2[] = new int[n2];
for (int i = 0; i < n1; i++)
arr1[i] = arr[lb + i];
for (int j = 0; j < n2; j++)
arr2[j] = arr[mid + 1 + j];
int i = 0, j = 0;
int k = lb;
while (i < n1 && j < n2) {
if (arr1[i] <= arr2[j])
arr[k] = arr1[i++];
else
arr[k] = arr2[j++];
k++;
}
while (i < n1)
arr[k++] = arr1[i++];
while (j < n2)
arr[k++] = arr2[j++];
}
public static void mergeSort(int arr[], int lb, int ub) {
if (lb < ub) {
int mid = lb + (ub - lb) / 2;
mergeSort(arr, lb, mid);
mergeSort(arr, mid + 1, ub);
merge(arr, lb, mid, ub);
}
}
public static int tripletSum(int[] arr, int num) {
mergeSort(arr, 0, arr.length - 1);
int n = arr.length;
int count = 0;
for (int i = 0; i < n - 2; i++) {
int sum = num - arr[i];
int j = i + 1;
int k = n - 1;
while (j < k) {
if (arr[j] + arr[k] == sum) {
count++;
k--;
} else if (arr[j] + arr[k] > sum) {
k--;
} else
j++;
}
}
return count;
}
}
Input array was - 1 3 3 3 3 3 3
Input num = 9
Output Generated - 10
Expected output - 20
Help me out with this I'm trying to find the solution for many hours. Also, the time complexity of the program should not exceed O(n²).
The given code works fine for all test cases.
import java.util.Arrays;
public class Solution {
public static int tripletSum(int[] arr, int num) {
Arrays.sort(arr);
int n = arr.length;
int Numtripletsum = 0;
for(int i=0;i<n;i++)
{
int pairSumFor = num - arr[i];
int numPairs = pairSum(arr, (i+1), (n-1), pairSumFor);
Numtripletsum+=numPairs;
}
return Numtripletsum;
}
private static int pairSum(int[] arr, int startIndex, int endIndex, int num ){
int numPair = 0;
while(startIndex < endIndex){
if(arr[startIndex] + arr[endIndex] < num){
startIndex++;
}
else if(arr[startIndex] + arr[endIndex] > num){
endIndex--;
}
else
{
int elementAtStart = arr[startIndex];
int elementAtEnd = arr[endIndex];
if(elementAtStart == elementAtEnd){
int totalElementsFromStartToEnd = (endIndex - startIndex) + 1;
numPair += (totalElementsFromStartToEnd * (totalElementsFromStartToEnd -1) /2);
return numPair;
}
int tempStartIndex = startIndex + 1;
int tempEndIndex = endIndex - 1;
while(tempStartIndex <= tempEndIndex && arr[tempStartIndex] == elementAtStart){
tempStartIndex+=1;
}
while(tempEndIndex >= tempStartIndex && arr[tempEndIndex] == elementAtEnd){
tempEndIndex-=1;
}
int totalElementsFromStart = (tempStartIndex - startIndex);
int totalElementsFromEnd = (endIndex - tempEndIndex);
numPair += (totalElementsFromStart * totalElementsFromEnd);
startIndex = tempStartIndex;
endIndex = tempEndIndex;
}
}
return numPair;
}
}
I did it in this way, hope I understood it well.
public static int tripletSum(int[] arr, int num) {
int loops = 0; // just to check the quality of the code
int counter = 0;
for (int i1 = 0; i1 < arr.length - 2; i1++) {
for (int i2 = i1 + 1; i2 < arr.length - 1; i2++) {
for (int i3 = i2 + 1; i3 < arr.length; i3++) {
loops++;
if (arr[i1] + arr[i2] + arr[i3] == num) {
counter++;
}
}
}
}
// Check for not exceeding O(n^2)
if (loops <= arr.length * arr.length) {
System.io.println("Well done");
} else {
System.io.println("Too many cycles");
}
return counter;
}
I iterate from "left" to "right" over the array and walking more and more to the "right".
1st, 2nd, 3rd
1st, 2nd, 4th
...
1st, 2nd, nth
2nd, 3rd, 4th
2nd, 3rd, 5th
...
2nd, 3rd, nth
.
.
.
nth - 2, nth - 1, nth
I iterated 35 times, but could iterate 7^2 = 49 times --> "Well done"
You missed one loop. The fixed code:
public static int tripletSum(int[] arr, int num) {
//Your code goes here
mergeSort(arr, 0, arr.length - 1);
int n = arr.length;
int count = 0;
for (int i = 0; i < n - 2; i++) {
int sum = num - arr[i];
for (int j = i+1; j < n-1; j++) {
int k = n-1;
while (j < k) {
if (arr[j] + arr[k] == sum) {
count++;
k--;
} else if (arr[j] + arr[k] > sum) {
k--;
} else {
j++;
}
}
}
}
return count;
}
OK, then optimized version:
public static int tripletSum(int[] arr, int num) {
//Your code goes here
mergeSort(arr, 0, arr.length - 1);
int n = arr.length;
int count = 0;
for (int i = 0; i < n - 2; i++) {
int sum = num - arr[i];
int maxK = n - 1;
for (int j = i + 1; j < n - 1; j++) {
int k = maxK;
while (j < k) {
if (arr[j] + arr[k] == sum) {
count++;
k--;
} else if (arr[j] + arr[k] > sum) {
k--;
maxK--;
} else {
j++;
}
}
}
}
return count;
}

Difficulty trying to sort 10 numbers inputted by a user. Must use arrays and a separate method for sorting

My program isn't sorting the numbers at all. It displays them in the order they were initially entered. It must sort them from smallest to largest number. The code below should find the largest number in the array and swap it with the last .the code is below:
import java.util.Scanner;
public class maxSorttt {
public static void main(String[] args) {
double[] ten = new double[10];
Scanner input = new Scanner(System.in);
System.out.print("Enter 10 numbers: ");
for (int i = 0; i < ten.length; i++)
ten[i] = input.nextDouble();
sort(ten);
}
public static void sort(double[] array) {
for (int i = array.length - 1; i < 0; i--) {
double currentMax = array[i];
int currentMaxIndex = i;
for (int x = i - 1; x < -1; x--) {
if (currentMax < array[x]) {
currentMax = array[x];
currentMaxIndex = x;
}
}
if (currentMaxIndex != i) {
array[currentMaxIndex] = array[i];
array[i] = currentMax;
}
}
for (int i = 0; i < array.length; i++)
System.out.print(array[i] + " ");
}
}
I believe your problem is here:
for(int i=array.length-1; i<0; i--)
array.length is not less than 0 so the for loop never runs. You probably wanted
for(int i=array.length-1; i>=0; i--)
Be Simple!
public static void selectionSort(double[] arr) {
for (int i = 0; i + 1 < arr.length; i++) {
int minIndex = findMinIndex(arr, i + 1);
if (Double.compare(arr[i], arr[minIndex]) > 0)
swap(arr, i, minIndex);
}
}
private static int findMinIndex(double[] arr, int i) {
int minIndex = i;
for (; i < arr.length; i++)
if (Double.compare(arr[i], arr[minIndex]) < 0)
minIndex = i;
return minIndex;
}
private static void swap(double[] arr, int i, int j) {
double tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}

Merge sort algorithm not working

Here is my code for a mergesort in java:
public class MergeSort {
public static void mergesort(int[] input) {
int inputSize = input.length;
if(inputSize < 2) {
return;
}
int[] left = new int[inputSize/2];
int[] right = new int[inputSize/2];
int count = 0;
for(int i=0; i < inputSize/2; i++) {
left[i] = input[i];
}
for(int i=inputSize/2; i<inputSize; i++) {
right[count] = input[i];
count++;
}
mergesort(left);
mergesort(right);
merge(left, right, input);
}
public static int[] merge(int[] returnArr, int[] left, int[] right) {
int leftSize = left.length;
int rightSize = right.length;
int i = 0;
int j =0;
int k = 0;
int count = 0;
while(i < leftSize && j < rightSize) {
if(left[i] <= right[j]) {
returnArr[k] = left[i];
i++;
}
else {
returnArr[k] = right[j];
j++;
}
k++;
}
while(i<leftSize) {
returnArr[k] = left[i];
i++;
k++;
}
while(j < rightSize) {
returnArr[k] = right[j];
j++;
k++;
}
for(int x=0; x<returnArr.length; x++) {
System.out.print(returnArr[x]);
}
return returnArr;
}
public static void main(String[] args) {
int[] array = {3,4,6,2,7,1,8,6};
mergesort(array);
}
}
My issue is that I'm getting an out of bounds exception.
I'm using the debugger and have found that after mergesort(left) and mergesort(right) have finished recursively running.
The arrays left and right, which go into the merge function, have the values [3] and [4] respectively, which is correct.
But when the debugger jumps into the merge function, left has value [3] and right, for some reason is length 2 and has the value [3,4].
This is the source of my out of bounds exception, though I'm not sure why when the merge function runs for its first time, it changes the value of "right".
One problem that is readily visible is that the you shouldn't make 2 arrays of size inputSize/2. Make two arrays of inputSize/2 and inputsize-inputSize/2. Otherwise the algorithm would fail for odd length array.
Also call the function with proper order of the arguments. merge( input, left, right);
I fixed your code and merged them to 1 method, left.length and right.length are limited by input.length so you only need to loop by input.length:
public static void mergeSort(int[] input)
{
if (input.length < 2)
{
return;
}
int[] left = new int[input.length / 2];
int[] right = new int[input.length - input.length / 2];
for (int i = 0; i < input.length; i++)
{
if (i < input.length / 2)
left[i] = input[i];
else
right[i - input.length / 2] = input[i];
}
mergeSort(left);
mergeSort(right);
for (int i = 0, l = 0, r = 0; i < input.length; i++)
{
if (l >= left.length)
{
input[i] = right[r];
r++;
}
else if (r >= right.length)
{
input[i] = left[l];
l++;
}
else
{
if (left[l] >= right[r])
{
input[i] = right[r];
r++;
}
else
{
input[i] = left[l];
l++;
}
}
}
}
you had two problems with your code:
1- as #coderredoc said: your left and right array sizes are wrong:
exemple: if you had an array of 7 elements, your left and right arrays would have a size of 7/2 = 3 so you would have a total of 6 elements in left and right arrays and not 7.
2- you are calling merge function in the mergeSort function with wrong parameters order:
it should be returnArr, left, right and not left,right, returnArr.
Explanation:
if you pass the left array as the first parameter, it would merge the right and the returnArr in the left array. But your left array has a size of 3 and the sum of the sizes of the others is 7 + 3 = 10 that's why you got an OutOfBoundsException.
you need to call merge(input,left,right);
here is the final version:
public class MergeSort {
public static void mergesort(int[] input) {
int inputSize = input.length;
if(inputSize < 2) {
return;
}
int[] left = new int[inputSize/2];
int[] right = new int[inputSize-inputSize/2];
int count = 0;
for(int i=0; i < inputSize/2; i++) {
left[i] = input[i];
}
for(int i=inputSize/2; i<inputSize; i++) {
right[count] = input[i];
count++;
}
mergesort(left);
mergesort(right);
merge(input,left, right);
}
public static int[] merge(int[] returnArr, int[] left, int[] right) {
int leftSize = left.length;
int rightSize = right.length;
int i = 0;
int j =0;
int k = 0;
int count = 0;
while(i < leftSize && j < rightSize) {
if(left[i] <= right[j]) {
returnArr[k] = left[i];
i++;
}
else {
returnArr[k] = right[j];
j++;
}
k++;
}
while(i<leftSize) {
returnArr[k] = left[i];
i++;
k++;
}
while(j < rightSize) {
returnArr[k] = right[j];
j++;
k++;
}
for(int x=0; x<returnArr.length; x++) {
System.out.print(returnArr[x]);
}
return returnArr;
}
public static void main(String[] args) {
int[] array = {3,4,6,2,7,1,8,6};
mergesort(array);
}
}

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.

Iterative Java merge sort

I am trying make an iterative version of Merge Sort for an Assignment. I got the Merge sort method from a website, and I worked on the method that is supposed to merge the arrays. However I keep getting an IndexOutOfBounds Exception.
I have been working on this for multiple hours and I cannot find the error. Can someone help me find a way to solve this?
So far I have this:
public static void MergeSort(int[] array) {
int current;
int leftStart;
int arraySize = array.length - 1;
for (current = 1; current <= arraySize; current = 2 * current) {
for (leftStart = 0; leftStart <= arraySize; leftStart += 2 * current) {
int mid = leftStart + current - 1;
int right = getMin(leftStart + 2 * current - 1, arraySize);
mergeArray(array, leftStart, mid, right);
}
}
}
public static void mergeArray(int[] array, int left, int mid, int right) {
int leftArraySize = mid - left + 1;
int rightArraySize = right - mid;
int[] leftArray = new int[leftArraySize];
int[] rightArray = new int[rightArraySize];
for (int i = 0; i < leftArraySize; i++)
leftArray[i] = array[left + i];
for (int i = 0; i < rightArraySize; i++)
rightArray[i] = array[mid + 1 + i];
int leftPtr = 0;
int rightPtr = 0;
int tempPtr = leftPtr;
while (leftPtr < leftArraySize && rightPtr < rightArraySize) {
if (leftArray[leftPtr] <= rightArray[rightPtr])
array[tempPtr++] = leftArray[leftPtr++];
else
array[tempPtr++] = rightArray[rightPtr++];
}
while (leftPtr <= left)
array[tempPtr++] = leftArray[leftPtr++];
while (rightPtr < right)
array[tempPtr++] = rightArray[rightPtr++];
}
public static int getMin(int left, int right) {
if (left <= right) {
return left;
} else {
return right;
}
}
Any sort of help will be highly appreciated!
Thanks!
Merge sort algorithm is a classical Divide and Conquer algorithm.
Divide the problem into smaller sub problems
Conquer via recursive calls.
Combine solutions of sub problems into one for the original problem
The Pseudocode for Merge:
C = output[length = n]
A = 1st sorted array[n/2]
B = 2st sorted array[n/2]
i = 1
j = 1
for k = 1 to n
if A[i] < B[j]
C[k] = A[i]
i++
else B[j]<A[i]
C[k] = B[j]
j++
end (ignores end cases)
So your source code problem is this line:
array[tempPtr++] = leftArray[leftPtr++];
please change to the logic of pseudocode:
if (leftArray [leftPtr ] <= rightArray[rightPtr ])
{
array[tempPtr] = leftArray [leftPtr];
leftPtr++;
}
else
{
array[tempPtr] = rightArray[rightPtr];
rightPtr++;
}
Try this code Successfully executed:
Only Small mistake in mergeArray() method:
array[tempPtr++] = leftArray[leftPtr++];
DOn't increment in array... Replace
array[tempPtr] = leftArray [leftPtr];
leftPtr++;
Final code: Compare my code you will get it.
public static void MergeSort(int[] array) {
int current;
int leftStart;
int arraySize = array.length;
for (current = 1; current <= arraySize-1; current = 2 * current) {
for (leftStart = 0; leftStart < arraySize-1; leftStart += 2 * current) {
int mid = leftStart + current - 1;
int right = getMin(leftStart + 2 * current - 1, arraySize-1);
mergeArray(array, leftStart, mid, right);
}}}
static void printArray(int A[])
{
int i;
for (i=0; i < A.length; i++)
System.out.println(A[i]);
}
static void mergeArray(int array[], int left, int mid, int right)
{
int leftArraySize = mid - left + 1;
int rightArraySize = right - mid;
int[] leftArray = new int[leftArraySize];
int[] rightArray = new int[rightArraySize];
for (int i = 0; i < leftArraySize ; i++)
leftArray [i] = array[left + i];
for (int j = 0; j < rightArraySize; j++)
rightArray[j] = array[mid + 1+ j];
int leftPtr = 0;
int rightPtr = 0;
int tempPtr = left;
while (leftPtr < leftArraySize && rightPtr < rightArraySize)
{
if (leftArray [leftPtr ] <= rightArray[rightPtr ])
{
array[tempPtr] = leftArray [leftPtr];
leftPtr++;
}
else
{
array[tempPtr] = rightArray[rightPtr];
rightPtr++;
}
tempPtr++;
}
while (leftPtr < leftArraySize )
{
array[tempPtr++] = leftArray [leftPtr++];
leftPtr++;
tempPtr++;
}
while (rightPtr < rightArraySize)
{
array[tempPtr++] = rightArray[rightPtr++];
rightPtr++;
tempPtr++;
} }
public static int getMin(int left, int right) {
if (left <= right) {
return left;
} else {
return right;
}}

Categories