The code is working fine for test cases like {3,3,3,3}, {1,2,3,4}, {2,4,1,3,5} etc. But it isn't working for {1,20,6,4,5,2,7,3,5}, which should return 18 inversions. My code is getting me 16 inversions.
class Test{
static int count =0;
public static void main(String[] agrs) {
int[] arr = new int[] {1,20,6,4,5,2,7,3,5};
sort(arr);
System.out.println("\n"+count);
}
private static void sort(int[] arr) {
int length = arr.length;
int tempArr[] = new int[length];
divideAndConquer(arr,tempArr,0,length-1);
}
private static void divideAndConquer(int[] arr, int[] tempArr, int low, int high) {
if(low < high){
int middle = low + (high - low) / 2;
divideAndConquer(arr, tempArr, low, middle);
divideAndConquer(arr, tempArr, middle + 1, high);
merge(arr, tempArr, low, middle, high);
}
}
private static void merge(int[] arr, int[] tempArr, int low, int middle,int high) {
for (int i = low; i <= high; i++)
tempArr[i] = arr[i];
int i = low, j = middle + 1, k = low;
while (i <= middle && j <= high) {
if(tempArr[i] < tempArr[j]) {
arr[k] = tempArr[i];
i++;
}
else {
arr[k] = tempArr[j];
if(tempArr[i] != tempArr[j])
count += middle+1 - i;
System.out.println(count);
j++;
}
k++;
}
while (i <= middle) {
arr[k] = tempArr[i];
k++;
i++;
}
}
}
Just change the line
if(tempArr[i] < tempArr[j]) {
to
if(tempArr[i] <= tempArr[j]) {
and the problem will be solved.
Related
When I use mergeSort to sort a portion of an array it gives ArrayIndexOutOfBoundsException but if I merge a portion starting from the index 0 to any other index it works why?
public static void mergeSort(int[] arr, int[] temp, int low, int high) {
if (low < high) {
int mid = low + (high - low) / 2;
mergeSort(arr, temp, low, mid);
mergeSort(arr, temp, mid + 1, high);
merge(arr, temp, low, mid, high);
}
}
public static void merge(int[] arr, int[] temp, int low, int mid, int high) {
for (int i = low; i <= high; i++) {
temp[i] = arr[i];
}
int i = low;
int j = mid + 1;
int k = low;
while (i <= mid && j <= high) {
if (temp[i] <= temp[j]) {
arr[k] = temp[i];
i++;
} else {
arr[k] = temp[j];
j++;
}
k++;
}
while (i <= mid) {
arr[k] = temp[i];
i++;
k++;
}
}
I get an error ArrayIndexOutOfBoundsException.
The argument high in your code is the index of the last element in the slice to be sorted or merged. Are you sure you pass array.length - 1 as the second argument to the topmost call to mergeSort()?
Also make sure you allocate the temp array with the same length as the array to be sorted.
This convention is confusing and does not allow sorting empty arrays. You might instead use a more consistent convention where high is the index of the element after the last one and you pass array.length to the topmost call.
Here is a modified version:
public static void mergeSort(int[] arr, int[] temp, int low, int high) {
if (high - low > 1) {
int mid = low + (high - low) / 2;
mergeSort(arr, temp, low, mid);
mergeSort(arr, temp, mid, high);
merge(arr, temp, low, mid, high);
}
}
public static void merge(int[] arr, int[] temp, int low, int mid, int high) {
for (int i = low; i < high; i++) {
temp[i] = arr[i];
}
int i = low;
int j = mid;
int k = low;
while (i < mid && j < high) {
if (temp[i] <= temp[j]) {
arr[k++] = temp[i++];
} else {
arr[k++] = temp[j++];
}
}
while (i < mid) {
arr[k++] = temp[i++];
}
}
My merge sort program is not sorting the array, but giving me the output as 0,0,0,3,5. The input array is 2,7,9,5,3. Can someone tell me what's wrong in this program?
In the merge function, I have created temporary array brr[],and recursion is used in mergesort function.
public class merge_sort {
public static void merge(int arr[],int low,int mid,int high){
int i=low,k=low;
int j=mid+1;
int brr[]=new int[5];
while(i<=mid&&j<=high){
if(arr[i]<arr[j]){
brr[k]=arr[i];
i++;
k++;
}
else{
brr[k]=arr[j];
k++;
j++;
}
}
while(i<=mid){
brr[k]=arr[i];
i++;
k++;
}
while(j<=high){
brr[k]=arr[j];
j++;
k++;
}
for (int z = 0; z <=high; z++)
{
arr[z]=brr[z];
}
}
public static void mergesort(int arr[], int low, int high) {
if(low<high){
int mid=(low+high)/2;
mergesort(arr,low,mid);
mergesort(arr,mid+1,high);
merge(arr,low,mid,high);
}
}
public static void main(String args[]) {
int arr[]={2,7,9,5,3};
int arr_size=5;
mergesort(arr,0,4);
for (int i = 0; i < arr_size; i++)
{
System.out.println(arr[i]);
}
}
}
Change required in merge method: You have done mistakes in assignment of indexes among low mid and high of subarrays for the final result array
public static void merge(int arr[],int low,int mid,int high){
int n1 = mid - low + 1;
int n2 = high - mid;
/* Create temp arrays */
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; ++i)
L[i] = arr[low + i];
for (int j = 0; j < n2; ++j)
R[j] = arr[mid + 1 + j];
/* Merge the temp arrays */
// Initial indexes of first, second and merged subarrays
int i = 0, j = 0;
int k = low;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
/* Copy remaining elements if any */
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
For a class project I am supposed to test Quicksort with different pivots (Low, High, Midpoint, Random, Median, and Mean), but I am having trouble getting it to work with wall of them. So far I have used two different Quicksort methods and I have been able to sort a random array with everything up to random, but not with mean or median. "Partition" work with Low, Midpoint and Random, while "Partition1" works with High.
Any help is greatly appreciated and If there is any more I should add just let me know.
Here is the code that I've used so far. "Partition1" is from GFG and "Partition" is from my textbook.
`
import java.util.Arrays;
import java.util.Random;
public class QSort {
public static int comparisonCount;
public static int swapCount;
public static void main(String[] args){
Random r = new Random();
int N= 10;
int[] test = new int[N]; //random integer array
for (int i =0; i < test.length; i++){
test[i] = r.nextInt(N*2);
}
System.out.println(Arrays.toString(test));
long startTime = System.nanoTime();
Quicksort(test, 0, test.length-1);
long endTime = System.nanoTime();
long duration = (endTime - startTime);
System.out.println(Arrays.toString(test));
System.out.println("Number of Comparisons "+ comparisonCount);
System.out.println("Number of swaps "+ swapCount);//1000000
System.out.println("QuickSort Duration in millisecond is "+(duration/1000000));
System.out.println("length is "+(test.length-1));
}
public static double median(int[] arr){
double median;
if (arr.length % 2 == 0) {
median = ((double) arr[arr.length / 2] + (double) arr[arr.length / 2 - 1]) / 2;
}
else {
median = (double) arr[arr.length / 2];
}
return median;
}
static void swap(int[] arr, int i, int j)
{
swapCount++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static int Partition1(int[] arr, int low, int high)
{
int pivot =arr[high];
int i = (low - 1);
for(int j = low; j <= high - 1; j++)
{
if(largerThan(arr[j],pivot))
{
i++;
swap(arr, i, j);
}
}
swap(arr, i+1, high);
return (i+1);
}
public static int mean(int[] arr){
double total = 0;
for(int i=0; i<arr.length; i++){
total = total + arr[i];
}
double average = total / arr.length;
return (int)average;
}
public static int Partition(int[] numbers, int low, int high) {
int midpoint = low + (high - low)/2; // Calculate Midpoint
//Random rand= new Random(); // for random pivot
//int pivot = numbers[rand.nextInt(high-low)+low];
int pivot = numbers[high];
boolean done = false;
while (!done) {
while (largerThan(numbers[low], pivot)) {
low+=1;
}
while (largerThan(pivot, numbers[high])) {
high-=1;
}
if (low >= high) {
done = true;
}
else {
swap(numbers, low, high);
low+=1;
high-=1;
}
}
return high;
}
public static boolean largerThan( int i, int m){
comparisonCount++;
return i < m;
}
public static void Quicksort(int[] numbers, int low, int high) {
if (high <= low || low >= high) {
return;
}
var Index = Partition1(numbers, low, high);
Quicksort(numbers, low, Index-1); //Index-1 for Partion1 and just Index for Partition
Quicksort(numbers, Index + 1, high);
}
}
`
Example C code for Lomuto Partition. It swaps middle element to last, but that can be removed. Recurse on smaller, loop on larger limits stack space complexity to O(log2(n)), but worst case time complexity remains O(n^2). You don't need uint64_t either (just use int instead).
void QuickSort(uint64_t a[], int lo, int hi)
{
while (lo < hi){
uint64_t t;
uint64_t p = a[(lo+hi)/2]; /* use mid point for pivot */
a[(lo+hi)/2]= a[hi]; /* swap with a[hi] */
a[hi] = p;
int i = lo;
for (int j = lo; j < hi; ++j){ /* Lomuto partition */
if (a[j] < p){
t = a[i];
a[i] = a[j];
a[j] = t;
++i;
}
}
t = a[i];
a[i] = a[hi];
a[hi] = t;
if(i - lo <= hi - i){ /* recurse on smaller partiton, loop on larger */
QuickSort(a, lo, i-1);
lo = i+1;
} else {
QuickSort(a, i+1, hi);
hi = i-1;
}
}
}
I'm running a quick sort on 2000 integers read from a file and count the comparisons and swaps but I'm not sure if my counters are in the right place as my numbers seem off, or is something wrong with the sort?
public int partition(int array[], int low, int high)
{
int pivot = array[low];
while(low < high)
{
while(pivot < array[high] && low < high)
{
high = high - 1;
compCounter++;
}
if(high != low)
{
array[low] = array[high];
SwapCounter++;
low++;
}
while(array[low] < pivot && low < high)
{
low = low +1;
compCounter++;
}
if(high != low)
{
array[high] = array[low];
SwapCounter++;
high--;
}
}
SwapCounter++;
int temp = array[high];
array[high] = pivot;
return high;
}
public void quickSort(int array[], int low, int high)
{
if (low < high)
{
int pivotPoint = partition(array, low, high);
quickSort(array, low, pivotPoint-1);
quickSort(array, pivotPoint+1, high);
}
}
I check your code but I think you do some more works (and maybe produce invalid result in some special case). I change your code in some how which is true and you can find it with some search and place counter in correct place.
private static int CompCounter, SwapCounter;
public static void main(String[] args) {
int[] a = {3, 2, 1, 5, 6, 7 , 4, -1};
quickSort(a, 0, a.length - 1);
System.out.println(Arrays.toString(a));
}
public static int partition(int array[], int low, int high) {
int pivot = array[high];
int lowBound = low;
for (int i = low; i < high; i++)
{
CompCounter++;
if (array[i] < pivot) {
int temp = array[lowBound];
array[lowBound] = array[i];
array[i] = temp;
lowBound++;
SwapCounter++;
}
}
SwapCounter++;
array[high] = array[lowBound];
array[lowBound] = pivot;
return lowBound;
}
public static void quickSort(int array[], int low, int high) {
if (low < high)
{
int pivotPoint = partition(array, low, high);
quickSort(array, low, pivotPoint - 1);
quickSort(array, pivotPoint + 1, high);
}
}
If you want, you can use another way to partition for sort (another algorithm):
public static int partitionSecondWay(int array[], int low, int high) {
int pivot = array[low];
int i = low - 1;
int j = high + 1;
while (true)
{
do
{
i++;
CompCounter++;
} while (array[i] < pivot);
do
{
j--;
CompCounter++;
} while (array[j] > pivot);
if (i >= j)
{
CompCounter++;
return j; // notice if you use this way, then in quicksort you
// must use quicksort(array, low, partition) and
// quicksort(array, partition + 1, high)
}
int temp = array[i];
array[i] = array[j];
array[j] = temp;
SwapCounter++;
}
}
I hope these helps you. If something is wrong, comment it.
For some reason the middle element of my array remains unsorted...
public class QuickSort {
public int a[];
public QuickSort(int[] a) {
this.a = a;
}
private void swap(int pos1, int pos2) {
int t = a[pos1];
a[pos1] = a[pos2];
a[pos2] = t;
}
private int partition(int low, int high) {
int i = low, j = low + 1, pivot = low;
while (j < high) {
if (a[j] <= a[pivot]) {
swap(++i, j);
}
j++;
}
swap(i, pivot);
return i;
}
private void sort(int low, int high) {
int i;
if (low >= high)
return;
else {
i = partition(low, high);
sort(i + 1, high);
sort(low, i - 1);
}
}
public String toString() {
StringBuilder sb = new StringBuilder("");
for (int i : a) {
sb.append(i);
sb.append("\n");
}
return sb.toString();
}
private static int[] generateRandomNumbers(int s) {
int a[] = new int[s];
for (int i = 0; i < s; i++) {
a[i] = new Random().nextInt(50);
}
return a;
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the size of elements");
int s = sc.nextInt();
QuickSort obj = new QuickSort(generateRandomNumbers(s));
System.out.println(obj.toString());
obj.sort(0, s - 1);
System.out.println("\n");
System.out.println(obj.toString());
}
}
The array is filled with randomly generated numbers, this is a standard quicksort algorithm
any help would be appreciated , i'm a novice programmer and have tried to debug this code for far too long...
Modify
swap(i+1, pivot);
return i+1;
and
int i = low-1, j = low, pivot = high;
also
if (low < high)
{
i = partition(low, high);
sort(i + 1, high);
sort(low, i - 1);
}
works flawlessly after these changes.
Or just change the '<' to '<=' as its not checking the high element...
while (j <= high) {
I found my mistake....
it should have been
while (j <= high)
instead of
(j < high)