Why my java program is showing StackOverflowError? - java

I have written a program to sort elements of an array based on the principle of quicksort. So what the program does is that it accepts an array, assumes the first element as the pivot and then compares it with rest of the elements of the array. If the element found greater then it will store at the last of another identical array(say b) and if the element is less than the smaller than it puts that element at the beginning of the array b. in this way the pivot will find its way to the middle of the array where the elements that are on the left-hand side are smaller and at the right-hand side are greater than the pivot. Then the elements of array b are copied to the main array and this whole function is called via recursion. This is the required code.
package sorting;
import java.util.*;
public class AshishSort_Splitting {
private static Scanner dogra;
public static void main(String[] args)
{
dogra=new Scanner(System.in);
System.out.print("Enter the number of elements ");
int n=dogra.nextInt();
int[] a=new int[n];
for(int i=n-1;i>=0;i--)
{
a[i]=i;
}
int start=0;
int end=n-1;
ashishSort(a,start,end);
for(int i=0;i<n;i++)
{
System.out.print(+a[i]+"\n");
}
}
static void ashishSort(int[]a,int start,int end)
{
int p;
if(start<end)
{
p=ashishPartion(a,start,end);
ashishSort(a,start,p-1);
ashishSort(a,p+1,end);
}
}
public static int ashishPartion(int[] a,int start,int end)
{
int n=start+end+1;
int[] b=new int[n];
int j=start;
int k=end;
int equal=a[start];
for(int i=start+1;i<=end;i++)
{
if(a[i]<equal)
{
b[j]=a[i];
j++;
}
else if(a[i]>equal)
{
b[k]=a[i];
k--;
}
}
b[j]=equal;
for(int l=0;l<=end;l++)
{
a[l]=b[l];
}
return j;
}
}
this code works fine when I enter the value of n up to 13930, but after that, it shows
Exception in thread "main" java.lang.StackOverflowError
at sorting.AshishSort_Splitting.ashishSort(AshishSort_Splitting.java:28)
at sorting.AshishSort_Splitting.ashishSort(AshishSort_Splitting.java:29)
I know the fact the error caused due to bad recursion but I tested my code multiple times and didn't find any better alternative. please help. thanks in advance.
EDIT: can someone suggest a way to overcome this.

I see perfrmance issues first. I see in your partition method:
int n = start+end+1
Right there, if the method was called on an int[1000] with start=900 and end=999, you are allocating an int[1900]... Not intended, I think...!
If you are really going to trash memory instead of an in-place partitioning,
assume
int n = end-start+1
instead for a much smaller allocation, and j and k indexes b[], they would be j=0 and k=n, and return start + j.
Second, your
else if(a[i]<equal)
is not necessary and causes a bug. A simple else suffice. If you don't replace the 0's in b[j..k] you'll be in trouble when you refill a[].
Finally, your final copy is bogus, from [0 to end] is beyond the bounds of the invocation [start..end], AND most importantly, there is usually nothing of interest in b[nearby 0] with your b[] as it is. The zone of b[] (in your version) is [start..end] (in my suggested version it would be [0..n-1])
Here is my version, but it still has the O(n) stack problem that was mentioned in the comments.
public static int ashishPartion(int[] a, int start, int end) {
int n = end-start + 1;
int[] b = new int[n];
int bj = 0;
int bk = n-1;
int pivot = a[start];
for (int i = start + 1; i <= end; i++) {
if (a[i] < pivot) {
b[bj++] = a[i];
} else {
b[bk--] = a[i];
}
}
b[bj] = pivot;
System.arraycopy(b, 0, a, start, n);
return start+bj;
}
If you are free to choose a sorting algo, then a mergesort would be more uniform on performance, with logN stack depth. Easy to implement.
Otherwise, you will have to de-recurse your algo, using a manual stack and that is a nice homework that I won't do for you... LOL

Related

How to improve efficiency

Write a function:
class Solution{
public int solution(int[] A);
}
that, given an array A of N integers, returns the smallest positive integer(greater than 0)
that does not occur in A.
For example, given A = [1,3,6,4,1,2], the function should return 5.
Given A = [1,2,3], the function should return 4.
Given A = [-1, -3], the function should return 1.
Write an efficient algorithm for the following assumptions.
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [-1,000,000..1,000,000].
I wrote the following algorithm in Java:
public class TestCodility {
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
//int a[] = {1,2,3};
//int b[] = {-1,-3};
int element = 0;
//checks if the array "a" was traversed until the last position
int countArrayLenght = 0;
loopExtern:
for(int i = 0; i < 1_000_000; i++){
element = i + 1;
countArrayLenght = 0;
loopIntern:
for(int j = 0; j < a.length; j++){
if(element == a[j]){
break loopIntern;
}
countArrayLenght++;
}
if(countArrayLenght == a.length && element > 0){
System.out.println("Smallest possible " + element);
break loopExtern;
}
}
}
}
It does the job but I am pretty sure that it is not efficient. So my question is, how to improve this algorithm so that it becomes efficient?
You should get a grasp on Big O, and runtime complexities.
Its a universal construct for better understanding the implementation of efficiency in code.
Check this website out, it shows the graph for runtime complexities in terms of Big O which can aid you in your search for more efficient programming.
http://bigocheatsheet.com/
However, long story short...
The least amount of operations and memory consumed by an arbitrary program is the most efficient way to achieve something you set out to do with your code.
You can make something more efficient by reducing redundancy in your algorithms and getting rid of any operation that does not need to occur to achieve what you are trying to do
Point is to sort your array and then iterate over it. With sorted array you can simply skip all negative numbers and then find minimal posible element that you need.
Here more general solution for your task:
import java.util.Arrays;
public class Main {
public static int solution(int[] A) {
int result = 1;
Arrays.sort(A);
for(int a: A) {
if(a > 0) {
if(result == a) {
result++;
} else if (result < a){
return result;
}
}
}
return result;
}
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
int b[] = {1,2,3};
int c[] = {-1,-3};
System.out.println("a) Smallest possible " + solution(a)); //prints 5
System.out.println("b) Smallest possible " + solution(b)); //prints 4
System.out.println("c) Smallest possible " + solution(c)); //prints 1
}
}
Complexity of that algorithm should be O(n*log(n))
The main idea is the same as Denis.
First sort, then process but using java8 feature.
There are few methods that may increase timings.(not very sure how efficient java 8 process them:filter,distinct and even take-while ... in the worst case you have here something similar with 3 full loops. One additional loop is for transforming array into stream). Overall you should get the same run-time complexity.
One advantage could be on verbosity, but also need some additional knowledge compared with Denis solution.
import java.util.function.Supplier;
import java.util.stream.IntStream;
public class AMin
{
public static void main(String args[])
{
int a[] = {-2,-3,1,2,3,-7,5,6};
int[] i = {1} ;
// get next integer starting from 1
Supplier<Integer> supplier = () -> i[0]++;
//1. transform array into specialized int-stream
//2. keep only positive numbers : filter
//3. keep no duplicates : distinct
//4. sort by natural order (ascending)
//5. get the maximum stream based on criteria(predicate) : longest consecutive numbers starting from 1
//6. get the number of elements from the longest "sub-stream" : count
long count = IntStream.of(a).filter(t->t>0).distinct().sorted().takeWhile(t->t== supplier.get()).count();
count = (count==0) ? 1 : ++count;
//print 4
System.out.println(count);
}
}
There are many solutions with O(n) space complexity and O(n) type complexity. You can convert array to;
set: array to set and for loop (1...N) check contains number or not. If not return number.
hashmap: array to map and for loop (1...N) check contains number or not. If not return number.
count array: convert given array to positive array count array like if arr[i] == 5, countArr[5]++, if arr[i] == 1, countArr[1]++ then check each item in countArr with for loop (1...N) whether greate than 1 or not. If not return it.
For now, looking more effective algoritm like #Ricola mentioned. Java solution with O(n) time complexity and O(1) space complexity:
static void swap(final int arr[], final int i,final int j){
final int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static boolean isIndexInSafeArea(final int arr[], final int i){
return arr[i] > 0 && arr[i] - 1 < arr.length && arr[i] != i + 1 ;
}
static int solution(final int arr[]){
for (int i = 0; i < arr.length; i++) {
while (isIndexInSafeArea(arr,i) && arr[i] != arr[arr[i] - 1]) {
swap(arr, i, arr[i] - 1);
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != i + 1) {
return i+1;
}
}
return arr.length + 1;
}

understanding recursion for dot product in java

Could anyone give me some clue about how could I Transform this code to recursion:
public class arrayExample {
public static void main (String[] args) {
int[] a = {2,2,2,2};
int[] b = {2,2,2,2};
int n = a.length;
int sum = 0;
for (int i = 0; i < n; i++) {
sum += a[i] * b[i];
}
System.out.println(sum);
}
}
So to do this do product with recursion.
You asked for a hint, so I'm not giving you the complete solution. When you want to process a list (or an array) recursively, the concept is nearly always:
public int recursiveFunction(List l, int carry) {
if (l.isEmpty()) {
return carry;
}
return recursiveFunction(l.subList(1, l.size()), operation(carry, l.get(0));
}
Where operation is whatever you want to do with your list. carry is used to provide an initial value (in the first call) and save the interim results.
You just have to change the code so it uses two arrays instead of one list and choose the correct operation.
Ok so hoping you have tried it before this is one possible way to code it.
public class ArrayExample {
public static void main (String[] args) {
int[] a = {2,2,2,2};
int[] b = {2,2,2,2};
int n = a.length;
int result = recurseSum(a, b, n-1);
System.out.println(result);
}
public static int recurseSum(int[] a, int[] b, int n){
if(n == 0)
return a[0]*b[0];
else{
return (a[n] * b[n]) + recurseSum(a,b,n-1);
}
}
}
This code is basically doing the same thing in the iteration.
The recursive call happens 4 times. When n hits 0, a[0]*b[0] is returned to the higher call. so basically from right to left it happens as follows:
a[3]*b[3] + a[2]*b[2] + a[1]*b[1] + a[0]*b[0]
One simple way to make a loop into a recursion is to answer these two questions:
What happens when the loop executes zero times?
If the loop has already executed n-1 times, how do I compute the result after the n-th iteration?
The answer to the first case produces your base case; the answer to the second question explains how to do the recursive invocation.
In your case, the answers are as follows:
When the loop executes zero times, the sum is zero.
When the loop executed n-1 times, add a[n] * b[n] to the previous result.
This can be translated into a recursive implementation
static int dotProduct(int[] a, int[] b, int n) {
... // your implementation here
}

tukey's ninther for different shufflings of same data

While implementing improvements to quicksort partitioning,I tried to use Tukey's ninther to find the pivot (borrowing almost everything from sedgewick's implementation in QuickX.java)
My code below gives different results each time the array of integers is shuffled.
import java.util.Random;
public class TukeysNintherDemo{
public static int tukeysNinther(Comparable[] a,int lo,int hi){
int N = hi - lo + 1;
int mid = lo + N/2;
int delta = N/8;
int m1 = median3a(a,lo,lo+delta,lo+2*delta);
int m2 = median3a(a,mid-delta,mid,mid+delta);
int m3 = median3a(a,hi-2*delta,hi-delta,hi);
int tn = median3a(a,m1,m2,m3);
return tn;
}
// return the index of the median element among a[i], a[j], and a[k]
private static int median3a(Comparable[] a, int i, int j, int k) {
return (less(a[i], a[j]) ?
(less(a[j], a[k]) ? j : less(a[i], a[k]) ? k : i) :
(less(a[k], a[j]) ? j : less(a[k], a[i]) ? k : i));
}
private static boolean less(Comparable x,Comparable y){
return x.compareTo(y) < 0;
}
public static void shuffle(Object[] a) {
Random random = new Random(System.currentTimeMillis());
int N = a.length;
for (int i = 0; i < N; i++) {
int r = i + random.nextInt(N-i); // between i and N-1
Object temp = a[i];
a[i] = a[r];
a[r] = temp;
}
}
public static void show(Comparable[] a){
int N = a.length;
if(N > 20){
System.out.format("a[0]= %d\n", a[0]);
System.out.format("a[%d]= %d\n",N-1, a[N-1]);
}else{
for(int i=0;i<N;i++){
System.out.print(a[i]+",");
}
}
System.out.println();
}
public static void main(String[] args) {
Integer[] a = new Integer[]{17,15,14,13,19,12,11,16,18};
System.out.print("data= ");
show(a);
int tn = tukeysNinther(a,0,a.length-1);
System.out.println("ninther="+a[tn]);
}
}
Running this a cuople of times gives
data= 11,14,12,16,18,19,17,15,13,
ninther=15
data= 14,13,17,16,18,19,11,15,12,
ninther=14
data= 16,17,12,19,18,13,14,11,15,
ninther=16
Will tuckey's ninther give different values for different shufflings of the same dataset? when I tried to find the median of medians by hand ,I found that the above calculations in the code are correct.. which means that the same dataset yield different results unlike a median of the dataset.Is this the proper behaviour? Can someone with more knowledge in statistics comment?
Tukey's ninther examines 9 items and calculates the median using only those.
For different random shuffles, you may very well get a different Tukey's ninther, because different items may be examined. After all, you always examine the same array slots, but a different shuffle may have put different items in those slots.
The key here is that Tukey's ninther is not the median of the given array. It is an attempted appromixation of the median, made with very little effort: we only have to read 9 items and make 12 comparisons to get it. This is much faster than getting the actual median, and has a smaller chance of resulting in an undesirable pivot compared to the 'median of three'. Note that the chance still exists.
Does this answer you question?
On a side note, does anybody know if quicksort using Tukey's ninther still requires shuffling? I'm assuming yes, but I'm not certain.

java mergesort count homework

I am working on getting the counts of comparisons and movers when merge sorting. I think I have the recursion I need thanks to this Sort Comparisons Counter but I can not get it to print out. I am obviously very new at programming so I'd be appreciative if you could explain what it is that I am missing.
import java.util.Arrays;
public class MergeSort {
int count = 0;
/**
* #param args
*/
// Rearranges the elements of a into sorted order using
// the merge sort algorithm (recursive).
public int mergeSort(int[] a, int howMany) {
if (a.length >= 2) {
// split array into two halves
int[] left = Arrays.copyOfRange(a, 0, a.length/2);
int[] right = Arrays.copyOfRange(a, a.length/2, a.length);
// sort the two halves
howMany = mergeSort(left,howMany);
howMany = mergeSort(right, howMany);
// merge the sorted halves into a sorted whole
howMany = merge ( left, right, a, howMany);
}
return howMany;
}
// Merges the left/right elements into a sorted result.
// Precondition: left/right are sorted
public static int merge(int[] result, int[] left,
int[] right, int howMany) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
for (int i = 0; i < result.length; i++) {
if (i2 >= right.length ||
(i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1]; // take from left
i1++;
} else {
result[i] = right[i2]; // take from right
i2++;
}
}
return howMany;
}
System.out.println(howMany); // ???
}
you need to call the method through its object wherever you wanna print. something like this (may be in your main method):
MergeSort mObj - new MergeSort();
int[] array = {1,2,3};
int count = mObj.mergeSort(array, 2);
System.out.println(count);
Basically, you need a driver method. When a java class is run, it will look for a public static void main(String[] args) method; if this method doesn't exist, nothing will happen. With what you have now, you should actually get a compile error from System.out.println(howMany); since the variable howMany only exists within the scope (brackets) of the merge method. To understand this better I'd review your notes on variable and method scope and class members. For a quick fix, remove the line at the bottom that I mentioned above, and place this method somewhere in your class:
public static void main(String[] args) {
int[] array = {2,5,8,1,3};
int howMany = mergeSort(array, 5);
System.out.println(howMany);
}
You also need to make your mergeSort method static, so change its definition to
public **static** int mergeSort(int[] a, int howMany)
I tested your code and I'm pretty sure that it doesn't give the answer you want, so be sure to check that. Best of luck learning object oriented programming!

Select i th smallest element from an array

I have a divide and conquer method to find the i th smallest element from an array. Here is the code:
public class rand_select{
public static int Rand_partition(int a[], int p, int q, int i) {
//smallest in a[p..q]
if ( p==q) return a[p];
int r=partition (a,p,q);
int k=r-p+1;
if (i==k) return a[r];
if (i<k){
return Rand_partition(a,p,r-1,i);
}
return Rand_partition(a,r-1,q,i-k);
}
public static void main(String[] args) {
int a[]=new int []{6,10,13,15,8,3,2,12};
System.out.println(Rand_partition(a,0,a.length-1,7));
}
public static int partition(int a[],int p,int q) {
int m=a[0];
while (p < q) {
while (p < q && a[p++] < m) {
p++;
}
while (q > p && a[q--] > m) {
q--;
}
int t = a[p];
a[p] = a[q];
a[q] = t;
}
int k=0;
for (int i=0; i < a.length; i++) {
if ( a[i]==m){
k=i;
}
}
return k;
}
}
However, I get an exception when run: java.lang.ArrayIndexOutOfBoundsException.
I was able to fix a few bugs. A minor one is this line:
return Rand_partition(a,r-1,q,i-k);
^
Instead, you want this:
return Rand_partition(a,r+1,q,i-k);
^
That's because you have partitioned a[p..q] into three parts as follows:
a[p..r-1], a[r], a[r+1..q]
Your original code handles the a[r] and a[p..r-1] case fine, but messes up on the a[r+1..q] by using r-1 instead.
I was also able to correct and simplify partition:
public static int partition(int a[],int p,int q){
int m=a[p]; // not m[0], you want to partition m[p..q]!!!
while ( p<q){
while (p<q && a[p] <m){ // don't do p++ here!
p++;
}
while (q>p && a[q]>m){ // don't do q-- here!
q--;
}
int t=a[p];
a[p]=a[q];
a[q]=t;
}
return p; // no need to search!!!
}
Your original code had extraneous p++ and q--. Also, the search for where the pivot is is unnecessary. It's where p and q meet.
On naming conventions
Please follow Java naming conventions:
Class names should be nouns, in mixed case with the first letter of each internal word capitalized. Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.
Related questions
How is this statement making sense? (Sun’s naming convention for Java variables)
Unfortunately the naming convention document above has one glaring error
On array declarations
Also, do not make a habit of declaring arrays like this:
int x[];
You should instead put the brackets with the type, rather than with the identifier:
int[] x;
Related questions
Is there any difference between Object[] x and Object x[] ?
Difference between int[] myArray and int myArray[] in Java
in array declaration int[] k,i and int k[],i
These declarations result in different types for i!
Assuming this isn't homework where you need do it this way, and it's not in the critical path (which is a likely guess), just sort the array and grab the value at index i.
public static getIthSmallest(final int[] myArray, final int i) {
if (i < 0) {
System.err.println("You're going to get an ArrayIndexOutOfBoundsException.");
}
if (i >= myArray.length) {
System.err.println("You're going to get an ArrayIndexOutOfBoundsException.");
}
Arrays.sort(myArray);
return myArray[i];
}
No clue what your bug is (I dislike Java :)
The simple solution (O(n) average, O(n^2) worst case) to this problem is copy the source to a nice simple implementation of qsort and make it only recurse on the side that contains the position you care about. It should be about 5 lines of code different so it should be easy to do.
If i is small there is a O(n + log(n)*i*log(i)) solution):
int FindI(int[] array, int i)
{
int[] tmp = array[0..i].dup; // copy first i elements;
sort(tmp); // sort, low to high
foreach(j in array[i..$]) // loop over the rest
if(j < tmp[0])
{
tmp[0] = j;
sort(tmp);
}
return tmp[0];
}
The algorithm you're attempting to implement is called Quickselect. Here is a link to working code using a median-of-three partitioning strategy.
You can use public static T min(Collection coll, Comparator comp) in Collections.

Categories