Why do I get a stack overflow error? - java

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.

Related

Time-complexity of mergesort with alternative merge-function

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)).

Java QuickSort Best Case Array Generation

I've been banging my head on the table on this one.
I need to create an n sized array that is optimized for QuickSort Partition. It will be used to demonstrate the growth of QuickSort's best case. I know that for best case, QuickSort must select a pivot that divides the array in half for every recursive call.
I cannot think of a way to create an n-sized optimized array to test. Any help would be greatly appreciated.
Here is the algorithm in Java.
public class QuickSort {
private int length;
private void quickSort(int[] a, int p, int r) {
if (p < r) {
int q = partition(a, p, r);
quickSort(a, p, q - 1);
quickSort(a, q + 1, r);
}
}
private int partition(int[] a, int p, int r) {
int x = a[r];
int i = p - 1;
for (int j = p; j < r; j++) {
if (a[j] <= x) {
i++;
exchange(a, i, j);
}
}
exchange(a, i + 1, r);
return i + 1;
}
public void exchange(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
QuickSort(int[] a) {
if (a == null || a.length == 0) {
return;
}
length = a.length;
quickSort(a, 0, length - 1);
}
}
I know this is an old question, but I had the same question and finally developed a solution. I'm not a Java programmer, so don't blame me for Java code issues, please. I assumed that the quicksort algorithm always takes the first item as a pivot when partitioning.
public class QuickSortBestCase
{
public static void generate(int[] arr, int begin, int end)
{
int count = end - begin;
if(count < 3)
return;
//Find a middle element index
//This will be the pivot element for the part of the array [begin; end)
int middle = begin + (count - 1) / 2;
//Make the left part best-case first: [begin; middle)
generate(arr, begin, middle);
//Swap the pivot and the start element
swap(arr, begin, middle);
//Make the right part best-case, too: (middle; end)
generate(arr, ++middle, end);
}
private static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
private static void fillArray(int[] arr)
{
for(int i = 0; i != arr.length; ++i)
arr[i] = i + 1;
}
private static void printArray(int[] arr)
{
for(int item : arr)
System.out.print(item + " ");
}
public static void main(String[] args)
{
if(args.length == 0)
return;
int intCount = Integer.parseInt(args[0]);
int[] arr = new int[intCount];
//We basically do what quicksort does in reverse
//1. Fill the array with sorted values from 1 to arr.length
fillArray(arr);
//2. Recursively generate the best-case array for quicksort
generate(arr, 0, arr.length);
printArray(arr);
}
}
This program produces the same output for the array of 15 items, as described here: An example of Best Case Scenario for Quick Sort. And in case someone needs a solution in C++:
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case_sorted(RandomIterator begin, RandomIterator end)
{
auto count = std::distance(begin, end);
if (count < 3)
return;
auto middle_index = (count - 1) / 2;
auto middle = begin + middle_index;
//Make the left part best-case first
generate_quicksort_best_case_sorted(begin, middle);
//Swap the pivot and the start element
std::iter_swap(begin, middle);
//Make the right part best-case, too
generate_quicksort_best_case_sorted(++middle, end);
}
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case(RandomIterator begin, RandomIterator end)
{
{
auto current = begin;
RandomIterator::value_type value = 1;
while (current != end)
*current++ = value++;
}
generate_quicksort_best_case_sorted(begin, end);
}

Sorting a time intervals

I am giving a time interval in the form of two arrays.
A[0]= 2 B[0]=3
A[1]= 9 B[1]=11
A[2] = 5 B[2]=6
A[3] = 3 B[3]=10
I want to sort the interval on the basics of starting time i.e.
(2,3) , (3,10) ,(5,6) ,(9,11)
Does i have to make a structure of this. or it can be done straight.
Try:
private static class StartEnd implements Comparable<StartEnd> {
private final int start;
private final int end;
// + constructor + getters
#Override
public int compareTo(StartEnd other) {
return start - other.getStart();
}
}
public void sort(int[] starts, int[] ends) {
StartEnd[] ses = new StartEnd[starts.length];
for(int i = 0 ; i < starts.length ; ++i) {
ses[i] = new StartEnd(starts[i], ends[i]);
}
Arrays.sort(sis);
// re-insert
for(int i = 0 ; i < ses.length ; ++i) {
starts[i] = ses[i].getStart;
ends[i] = ses[i].getEnd();
}
}
It can be done straight, since you dont show what have you tried so far I just give you the algorithm:
for j = 1 to n
for i = i+1 to n
if(A[i]>A[j]){
swap(A[i],A[j])
swap(B[i],B[j])
}
you can easily convert it to java code.
this algorithm is buble sort if you want better algorithm use this wiki link to improve your time.
As DwB want here is merge sort full java code that do what you want. I got merge sort algorithm from here and modify to satisfy your need. also you could see the working version on Ideone
Merge Sort:
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
private int[] A;
private int[] B;
private int[] helperA;
private int[] helperB;
private int length;
public static void main (String[] args){
int[] As = {2,9,5,3};
int[] Bs = {3,11,6,10};
new Ideone().sort(As,Bs);
}
public void sort(int[] As , int[] Bs) {
A = As;
B = Bs;
length = A.length;
this.helperA = new int[length];
this.helperB = new int[length];
mergesort(0, length - 1);
for(int i = 0 ; i<length ; i++)
System.out.println("(" + A[i] + "," + B[i]+ ")");
}
private void mergesort(int low, int high) {
// check if low issmaller then high, if not then the array is sorted
if (low < high) {
// Get the index of the element which is in the middle
int middle = low + (high - low) / 2;
// Sort the left side of the array
mergesort(low, middle);
// Sort the right side of the array
mergesort(middle + 1, high);
// Combine them both
merge(low, middle, high);
}
}
private void merge(int low, int middle, int high) {
// Copy both parts into the helper array
for (int i = low; i <= high; i++) {
helperA[i] = A[i];
helperB[i] = B[i];
}
int i = low;
int j = middle + 1;
int k = low;
// Copy the smallest values from either the left or the right side back
// to the original array
while (i <= middle && j <= high) {
if (helperA[i] <= helperA[j]) {
A[k] = helperA[i];
B[k] = helperB[i];
i++;
} else {
A[k] = helperA[j];
B[k] = helperB[j];
j++;
}
k++;
}
// Copy the rest of the left side of the array into the target array
while (i <= middle) {
A[k] = helperA[i];
B[k] = helperB[i];
k++;
i++;
}
}
}
Step 1: Java is an object oriented language; learn to use objects.
Possible class for the time interval
public class TimeInterval implements Comparable<TimeInterval>
{
private int end;
private int start;
public TimeInterval(
final int end,
final int start)
{
this.end = end;
this.start = start;
}
public int getEnd()
{
return end;
}
public int getStart()
{
return start;
}
public int comareTo(final TimeInterval other)
{
if (other == null)
{
return -1; // this will put the null value objects at the end.
}
return start - other.start;
}
}
The classical Javanese "object oriented" approach for this is to use a dedicated class storing a pair of values (int values, in this case), and sort them, as already pointed out in most of the other answers. However, I'd recommend to not make this class Comparable. Instead, a Comparator could be used, which would make it much easier to introduce new sorting orders. Particularly, there could be Comparator implementations for sorting in ascending/descending order, based on the first/second value, respectively. Only then, object orientation plays out its advantages, compensating the "disadvantage" of having to create such a pair of int values as a "dummy data structure" in the first place...
However, I wanted to try to find a solution for the original question as well, namely, sorting two arrays "in sync". Despite the task of sorting seemingly being trivial, one can dedicate a lot of work to doing it right (see Chapter 3 of TAOCP). A bubble sort is simple but inefficient even for medium-sized arrays. Implementing a quick- or merge sort can be fiddly when trying to get the indices right. However, one solution can be obtained by simply taking the existing sort method from java.lang.Arrays, and factoring out the most elementary building block: The swap function:
public class ArraySort
{
public static void main(String[] args)
{
final int A[] = new int[4];
final int B[] = new int[4];
A[0] = 2; B[0] = 3;
A[1] = 9; B[1] = 11;
A[2] = 5; B[2] = 6;
A[3] = 3; B[3] = 10;
Swapper swapper = new Swapper()
{
#Override
public void swap(int array[], int i0, int i1)
{
ArraySort.swap(A, i0, i1);
ArraySort.swap(B, i0, i1);
}
};
sort(A, 0, A.length, swapper);
for (int i=0; i<A.length; i++)
{
System.out.println("("+A[i]+","+B[i]+")");
}
}
interface Swapper
{
void swap(int array[], int i0, int i1);
}
public static void swap(int array[], int i0, int i1)
{
int t = array[i0];
array[i0] = array[i1];
array[i1] = t;
}
// The following methods are copied from java.util.Arrays:
public static void sort(int x[], int off, int len, Swapper swapper)
{
if (len < 7)
{
for (int i = off; i < len + off; i++)
{
for (int j = i; j > off && x[j - 1] > x[j]; j--)
{
swapper.swap(x, j, j - 1);
}
}
return;
}
int m = off + (len >> 1);
if (len > 7)
{
int l = off;
int n = off + len - 1;
if (len > 40)
{
int s = len / 8;
l = med3(x, l, l + s, l + 2 * s);
m = med3(x, m - s, m, m + s);
n = med3(x, n - 2 * s, n - s, n);
}
m = med3(x, l, m, n);
}
int v = x[m];
int a = off, b = a, c = off + len - 1, d = c;
while (true)
{
while (b <= c && x[b] <= v)
{
if (x[b] == v)
{
swapper.swap(x, a++, b);
}
b++;
}
while (c >= b && x[c] >= v)
{
if (x[c] == v)
{
swapper.swap(x, c, d--);
}
c--;
}
if (b > c)
{
break;
}
swapper.swap(x, b++, c--);
}
int s, n = off + len;
s = Math.min(a - off, b - a);
vecswap(x, off, b - s, s, swapper);
s = Math.min(d - c, n - d - 1);
vecswap(x, b, n - s, s, swapper);
if ((s = b - a) > 1)
{
sort(x, off, s, swapper);
}
if ((s = d - c) > 1)
{
sort(x, n - s, s, swapper);
}
}
private static void vecswap(int x[], int a, int b, int n, Swapper swapper)
{
for (int i = 0; i < n; i++, a++, b++)
{
swapper.swap(x, a, b);
}
}
private static int med3(int x[], int a, int b, int c)
{
return (x[a] < x[b] ? (x[b] < x[c] ? b : x[a] < x[c] ? c : a)
: (x[b] > x[c] ? b : x[a] > x[c] ? c : a));
}
}
Notes
This is not a solution that I would recommend. It's just an attempt to answer the question
or it can be done straight. [sic!]
And the answer is: Yes, it is possible, although the solutions that are introducing some sort of an IntPair are more idiomatic.
Apart from that, it would probably be more efficient to "inline" the Swapper#swap calls to directly swap elements of two arrays that are stored in instance variables, or passed as method parameters. However, I liked the genericity of such a Swapper interface. Additionally, it would be nice to generalize this even further, by passing in something like a
interface IntArrayEntryComparator {
int compare(int array[], int i0, int i1);
}
But the latter would go beyond what I wanted to test/demonstrate with this class.
instead having two arrays, create object which holds your intervals
class Interval implements Comparable<Interval> {
private Long start,completed
public Interval(Long start, Long completed) {
this.start = start;
this.completed = completed;
}
#Override
public int compareTo(Interval o) {
return start.compareTo(o.start);
}
//getters and setters ommited
}
then, all what you need to do is implement compareTo method and put all your data in some collection ie List<Interval> intervals
and used Collections.sort(intervals) to sort them
EDIT
Example:
originally you have:
A[0]= 2 B[0]=3,
A[1]= 9 B[1]=11
A[2] = 5 B[2]=6
A[3] = 3 B[3]=10`
lets replace this by:
List<Interval> intervals = new ArrayList<>();
intervals.add(new Interval(2L,3L));
intervals.add(new Interval(9L,11L));
intervals.add(new Interval(5L,6L));
intervals.add(new Interval(3L,10L));
//NOTE L is added at the end variable as interval uses Long, if you change it to integer you dont need to add it;
And now all what you need to do is sort
Collection.sort(intervals);

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

Confused with Quicksort algorithm

I am implementing a quicksort algorithm and have succesfully partitioned the input array around a pivot. The problem is, I am confused in how to recursively sort the 1st part and 2nd part of the array (i.e specifying the range) using the same input array.
Below is my implementation
class QuickSort {
int i;
int l = 0;
public void quicksort(int A[], int n) {
if (n == 1) {
return;
} else {
partition(A, 0, n);
//----Confused as from this point
quicksort(A, A[i]);
//Recursively sort both parts of the array
}
}
public int partition(int A[], int l, int r) {
int p = A[l];//Choose pivot
i = l + 1;
//Partition around A through P
for (int j = i; j < r; j++) {
if (A[j] < p) {
swap(A, i, j);
++i;
}
}
swap(A, l, i - 1 );
return i;
}
public void swap(int A[], int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public void display(int A[]){
for (int i = 0; i < A.length; i ++){
System.out.print(A[i] + " ");
}
}
}
class QuickSortApp{
public static void main(String args[]){
QuickSort quick = new QuickSort();
int A[] = {6,2,7,8,4,3,5};
quick.quicksort(A, A.length);
quick.display(A);
}
}
Please, I would also appreciate being corrected on any other inefficencies in my algorithm. Thanks
Change your quicksort() signature to quicksort(int[] A, int begin, int end)
Since, you actually did the sorting inside partition(). What I would do is this:
if (end-begin <= 1) {
return;
} else {
int pivot = partition(A, begin, end);
quicksort(A, begin, pivot);
quicksort(A, pivot, end);
}
Create a wrapper for the quicksort call with the signature you have which calls another one like quicksort(A, i, j) and your call from the wrapper will be quicksort(A, 0, n).

Categories