Time-complexity of mergesort with alternative merge-function - java

I currently have this code:
public static void main(String[] args) throws FileNotFoundException {
Scanner sc = new Scanner(new File(args[0]));
int amount = sc.nextInt();
int[] array = new int[amount];
for (int i = 0; i < amount; i++) {
array[i] = sc.nextInt();
}
System.out.println("FINAL ANSWER " + find(array, 0, array.length - 1));
}
static int find(int arr[], int l, int r) {
int answer = 0;
if (l < r) {
int m = (l + r) / 2;
int a = find(arr, l, m);
int b = find(arr, m + 1, r);
answer = a + b + answer(arr, l, m, r);
}
return answer;
}
static int answer(int arr[], int l, int m, int r) {
int ans = 0;
for (int i = m; i < r; i++) {
for (int j = l; j < m + 1; j++) {
if (arr[i + 1] > arr[j]) {
ans++;
}
}
}
return ans;
}
I know mergesort has a time-complexity of O(nlog(n)), however I've replaced the merge-function by a function with two for-loops. So is it now O(n^2) since l, m and r depend on n?

The function answer has a complexity of O( (r-m) * (m+1-l) ). The outer for-loop goes from m to r, thus r-m iterations. The inner for-loop goes from l to m+1, so m+1-l iterations.
Given the worst case l=0,r=n and m=n/2, the function can be approximated to O(n^2).
However you need to add the runtime of the function find. So the overall time complexity will be:
O(n^2 * log(n)).

Related

randomized select not give steady solution

EDIT
try run in the main:
int[] arr = {646 ,94 ,366 ,754 ,948 ,678 ,121 ,320 ,528 ,36};
for(int i=0;i<10;i++){
System.out.println(randomizedSelect(arr,0,arr.length-1,5));
printArr(arr);
}
and see that i got diffrent outpot in each loop..
Got a little problem that I would like some help with, if anyone knows how.
I need to find the kth smallest value in an array by randomized partition.
I've got two problems:
I get array out of bounds with -1 and can't find a way to fix it.
Most of the time it works but sometimes it gives me wrong k place.
For example for array with length of 10, it tells me that 20 is in the 5th place but actually it should be in the 2nd place and it prints the array where not all the values on the left are smaller than 20 and not smaller than the 5th place.
Here is an example array:
{646 ,94 ,366 ,754 ,948 ,678 ,121 ,320 ,528 ,36}
The array input is done by a random number generator.
This is my code:
import java.util.Random;
import java.util.Scanner;
public class Main {
static Scanner scan = new Scanner(System.in);
static Random rand = new Random();
public static void main(String[] args) {
int nSize = askSizeN();
int kSize = askSizeK(nSize);
int[] arr = new int[nSize];
chose(arr);
int[] arrCopy = new int[nSize];
for (int i = 0; i < arrCopy.length; i++) {
arrCopy[i] = arr[i];
}
printArr(arrCopy);
System.out.println(randomizedSelect(arrCopy, 0, arr.length - 1, kSize));
printArr(arrCopy);
}
private static int partition(int[] arr, int p, int r) {
int x = arr[r];
int i = p - 1;
for (int j = p; j < r; j++) {
if (arr[j] <= x) {
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[r];
arr[r] = temp;
return i + 1;
}
private static int randomizedPartition(int[] arr, int p, int r) {
int i = rand.nextInt(r - p);
int temp = arr[r];
arr[r] = arr[i];
arr[i] = temp;
return partition(arr, p, r);
}
private static int randomizedSelect(int[] arr, int p, int r, int i) {
if (p == r) {
return arr[p];
}
int q = randomizedPartition(arr, p, r);
int k = q - p + 1;
if (i == k) {
return arr[q];
}
else if (i < k) {
return randomizedSelect(arr, p, q - 1, i);
}
else {
return randomizedSelect(arr, q + 1, r, i - k);
}
}
private static int askSizeN() {
System.out.println("Please chose the size of the heap: \n" + "(the size of n)");
return scan.nextInt();
}
private static int askSizeK(int nSize) {
System.out.println(
"Please chose how much small values you want to see: \n" + "(the size of k)");
int kSize = scan.nextInt();
if (kSize > nSize) {
System.out.println("cant print more number then the size of the Heap..");
System.out.println("Please enter a number less then " + (nSize + 1));
askSizeK(nSize);
}
return kSize;
}
private static int[] chose(int[] a) {
System.out.println("Chose the option you want: \n" + "\t1. enter your own values."
+ "\n\t2. let me generate random values");
int chose = scan.nextInt();
if (chose == 1) {
for (int i = 0; i < a.length; i++) {
System.out.println("Enter value number " + (i + 1));
a[i] = scan.nextInt();
}
}
else if (chose == 2) {
System.out.println("Generate random numbers.");
for (int i = 0; i < a.length; i++) {
a[i] = rand.nextInt(1000);
}
}
else {
chose(a);
}
return a;
}
private static void printArr(int[] a){
for(int i=0;i<a.length;i++){
System.out.print(a[i] + " ");
}
System.out.println();
}
}
I've solved the problem.
Method randmizedPartition() was generating wrong random pivot for partition.
I solved it by changing the random line to:
int i = rand.nextInt((r - p) + 1) + p;

MergeSort Algorithm from largest to smallest in java

So I want to use the mergesort algorithm to sort an array filled with numbers from largest to smallest. I have working code for this but I can't seem to make it sort from largest to smallest. I tried playing around with the for loop that has all of those if statements in there but I just couldn't figure it out. Could someone please help.
public class MergeSorter
{
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result+ i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] < second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}
import java.util.Arrays;
public class MergeSortTest
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}
Your entire logic is correct except one thing. In the sort_descend function, after you copy the array a into first_replace and second_replace, you start comparing the elements using the if condition if (first_replace[first_i] < second_replace[second_i]).
Here, you essentially assign the smaller of the two elements into your array a and this the step which determines whether your array will be sorted in ascending order or descending order.
To sort in descending order, you need to just reverse this sign and you will get the desired output i.e. change the if condition to if (first_replace[first_i] > second_replace[second_i]).
Please refer to the below code to sort an array of integers in descending order.
It is similar to your solution but only one change of the comparator operator on line number 38.
import java.util.Arrays;
public class C
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}
class MergeSorter {
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result + i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] >= second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}

Counting Comparisons When The Pivot Is Not The First Element

I have tried to implement the Quicksort algorithm, but different pivots don't seem to work.
When the pivot element is not the first element, it always ends in a recursive loop resulting in a crash where the variable i falls off of the array and it calls itself again with the full array and nothing changes. I think the error is the comparison comparing toSort[j] with the pivot value, or the first element after being swapped with the other element.
public static void quickSort(int[] toSort, int l, int r){
if(r - l <= 1)return;
counter += r - l - 1;
int p = choosePivot(l, r);
int pivot = toSort[p];
int oldP = toSort[p];
toSort[p] = toSort[l];
toSort[l] = oldP;
int i = l + 1;
for(int j = l + 1; j < r; j++){
if(toSort[j] < pivot){
int swap = toSort[j];
toSort[j] = toSort[i];
toSort[i] = swap;
i++;
}
}
oldP = toSort[i - 1];
toSort[i - 1] = toSort[l];
toSort[l] = oldP;
quickSort(toSort, l, i);
quickSort(toSort, i, r);
}
public static int choosePivot(int m, int n){
return n - 1;
//return m;
}
The problem is that the recursive call to quickSort() is not converging. A slight change in the last two lines will work like magic.
public static void quickSort(int[] toSort, int l, int r){
if(r - l <= 1)return;
counter += r - l - 1;
int p = choosePivot(l, r);
int pivot = toSort[p];
int oldP = toSort[p];
toSort[p] = toSort[l];
toSort[l] = oldP;
int i = l + 1;
for(int j = l + 1; j < r; j++){
if(toSort[j] < pivot){
int swap = toSort[j];
toSort[j] = toSort[i];
toSort[i] = swap;
i++;
}
}
oldP = toSort[i - 1];
toSort[i - 1] = toSort[l];
toSort[l] = oldP;
quickSort(toSort, l, i-1);
quickSort(toSort, i, r);
}
public static int choosePivot(int m, int n){
return n - 1;
//return m;
}
You can check the Ideone link for updated code.

Why do I get a stack overflow error?

Here is the code .. I have to sort an already sorted array and to calculate it's execution time ...for quicksort it is n^2 cause it is the worst case. but for large input data let's say 7500 it gives me an overflow error :S what can i do in order to calculate the running time?
public class Provo {
public static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static int HoarePartition(int m, int d, int[] a) {
int pivot = a[m];
int i = m + 1;
int j = d;
while (i < j) {
while (a[i] < pivot) {
i = i + 1;
}
while (a[j] > pivot) {
j = j - 1;
}
if (i < j)
swap(a, i, j);
}
swap(a, m, j);
return j;
}
public static void quicksort(int m, int d, int[] a) {
if (m < d) {
int s = HoarePartition(m, d, a);
quicksort(m, s - 1, a);
quicksort(s + 1, d, a);
}
}
}
and here is the main class
import javax.swing.*;
public class ascending {
public static void main(String[] args){
String input=JOptionPane.showInputDialog("Shkruani nr e te dhenave");
int size=new Integer(input).intValue();
int[] r= new int[size];
int[] p = new int[size];
int majtas=0;
int djathtas=size;
for(int i=majtas;i<djathtas;i++)
{r[i]=i;}
for(int i=majtas;i<djathtas;i++)
{p[i]=r[i];}
long average;
int n=100;
long result=0;
for(int j=1;j<=n;j++)
{
long startTime = System.nanoTime();
Provo.quicksort(majtas,djathtas-1,p);
long endTime = System.nanoTime();
result = result+(endTime-startTime);
long a = endTime-startTime;
System.out.println(j+": " +a);
for(int i=majtas;i<djathtas;i++)
{p[i]=r[i];}
}
average=result/n;
System.out.println("Koha e ekzekutimit te insertion sort eshte " + average + " nanosekonda ");
}
}
Well if you are stuck, you can maybe look for iterative quicksort on the web to get some help.
I have found this article. It is dedicated to C# but translating it into Java shouldn't be a big issue.
Change int djathtas = size - 1; to int djathtas = size; and change quicksort(majtas, djathtas, p); to quicksort(majtas, djathtas - 1, p);
Otherwise it's not allocating 10 digits, only 9.
It seems like you're just using too large of a number. Your program can be functioning correctly and generate a stack overflow error. You could try implementing another version of quicksort that does not rely on the stack or something.
Other than that, I'm not sure why you need such a large input anyway.

Quicksort. Exception in thread "main" java.lang.StackOverflowError

Good day! I have here a Java program that does the quicksort. It reads a file then sorts the first 10,000 words in it. I followed the pseudocode of Thomas Cormen in his Introduction to Algorithms, Second Ed.
import java.io.*;
import java.util.*;
public class SortingAnalysis {
public static int partition(String[] A, int p, int r) {
String x = A[r];
int i = p-1;
for (int j=p; j < r-1; j++) {
int comparison = A[j].compareTo(x);
if (comparison<=0) {
i=i+1;
A[i] = A[j];
}
}
A[i+1] = A[r];
return i+1;
}
public static void quickSort(String[] a, int p, int r) {
if (p < r) {
int q = partition(a, p, r);
quickSort(a, p, q-1);
quickSort(a, q+1, r);
}
}
public static void main(String[] args) {
final int NO_OF_WORDS = 10000;
try {
Scanner file = new Scanner(new File(args[0]));
String[] words = new String[NO_OF_WORDS];
int i = 0;
while(file.hasNext() && i < NO_OF_WORDS) {
words[i] = file.next();
i++;
}
long start = System.currentTimeMillis();
quickSort(words, 0, words.length-1);
long end = System.currentTimeMillis();
System.out.println("Sorted Words: ");
for(int j = 0; j < words.length; j++) {
System.out.println(words[j]);
}
System.out.print("Running time: " + (end - start) + "ms");
}
catch(SecurityException securityException) {
System.err.println("Error");
System.exit(1);
}
catch(FileNotFoundException fileNotFoundException) {
System.err.println("Error");
System.exit(1);
}
}
}
However, when I run the code, the console says
Exception in thread "main" java.lang.StackOverflowError
at SortingAnalysis.partition and quickSort
I thought that the error was just because of the large size (ie, 10000) so I decreased it to 100 instead. However, it still doesn't sort the first 100 words from a file, rather, it displays the 100th word 100 times.
Please help me fix the code. I'm new in Java and I need help from you guys. Thank you very much!
EDIT: I now edited my code. It doesn't have an error now even when the NO_OF_WORDS reaches 10000. The problem is it halts the wrong sequence.
You have two problems:
the loop in partition() should run to j <= r - 1, you are jumping out early.
You are not swapping elements. Try the following code:
public static int partition(String[] A, int p, int r) {
String x = A[r];
int i = p - 1;
for (int j = p; j <= r - 1; j++) {
int comparison = A[j].compareTo(x);
if (comparison <= 0) {
i = i + 1;
swap(A, i, j);
}
}
swap(A, i + 1, r);
return i + 1;
}
public static void swap(String[] a, int i, int j) {
String temp = a[i];
a[i] = a[j];
a[j] = temp;
}
Looking at the Quicksort algo of wikipedia, the partition algo is the following :
// left is the index of the leftmost element of the array
// right is the index of the rightmost element of the array (inclusive)
// number of elements in subarray = right-left+1
function partition(array, 'left', 'right', 'pivotIndex')
'pivotValue' := array['pivotIndex']
swap array['pivotIndex'] and array['right'] // Move pivot to end
'storeIndex' := 'left'
for 'i' from 'left' to 'right' - 1 // left ≤ i < right
if array['i'] < 'pivotValue'
swap array['i'] and array['storeIndex']
'storeIndex' := 'storeIndex' + 1
swap array['storeIndex'] and array['right'] // Move pivot to its final place
return 'storeIndex'
In your method you don't use the pivotIndex value, you base your pivotValue on the right index. You need to add this parameter to your method.
Following the wiki algo it should be like this :
public static int partition(String[] A, int p, int r, int pivotIdx) {
String x = A[pivotIdx];
String tmp = A[pivotIdx];
A[pivotIdx] = A[r];
A[r]=tmp;
int i = p;
for (int j=p; j < r; j++) {
int comparison = A[j].compareTo(x);
if (comparison<=0) {
tmp=A[i];
A[i] = A[j];
A[j]=tmp;
i++;
}
}
tmp=A[i];
A[i] = A[r];
A[r]=tmp;
return i;
}

Categories