Stackoverflow error while implementing insertion sort using recursion - java

public static void insertionSortRecursion(String a[], int first, int last) {
if (first < last) {
//sort all but last
insertionSortRecursion(a, first, last - 1);
insertInOrder(a[last], a, first, last -1);
}
}
private static void insertInOrder(String element, String[] a, int first, int last) {
// System.out.println(last - 1);
// System.out.println(element);
// System.out.println(a[last]);
if (element.compareTo(a[last]) >= 0) {
a[last + 1] = element;
} else if(first < last) {
a[last + 1] = a[last];
insertInOrder(element, a, first, last - 1);
} else {
a[last + 1] = a[last];
a[last] = element;
}
}
Hey Guys,
I am trying to implement insertion sort using recursion it's working fine on small number of words but I am getting stackoverflow after implementing it because the size of file I am sorting have a lot of words around 10,000. Please suggest what should I do to remove the error.
These are the methods I am using for insertion sort using recursion and I am calling them in my constructor.

Assuming your algorithm is correct, leave this function as it is. Don't try to fix it. In general to get rid of stack overflow (while keeping recursion) there are two solutions :
Use tail call optimization
Increase the stack size
But let sit back and assume this code is going to be anything else than a programming exercise. Any other person who have to read will think :
Why does he use insertion sort ?
Why does he re-implement insertion-sort?
Did it have to be recursion?? my lord!!
Why did he waste his time to find a tail-call insertion algorithm? Or
Did he just increased the stack size for the only sake of running his method?
Good. Now we have 1000,000 items to sort and the program keep crashing.
Conclusion, they will erase your code at once and use Collections.sort().
As I said, if you are doing a programming exercise then good, your recursive insertion
sort work till some point. move on.

Java is not able to handle a recursion depth that deep (10000) by default. Consider the below oversimplified example still throws a StackOverflowError.
static void test(int i)
{
if (i == 0) return;
test(i-1);
}
public static void main(String[] args)
{
test(10000);
}
You must specify command-line parameters to achieve this (-Xss and possibly -Xmx to allocate more memory).
I ran your algorithm successfully for an array of size 100000 using -Xmx1000m -Xss10000000 (though it took a while).
I assume there a reason you're using recursion and not a simple double for loop.

Related

Recursive function that finds the minimum value in an ArrayList of Integers in Java

This is a problem that I have been thinking about as part of self-learning java. The problem consists of writing a recursive function that finds the minimum value in an ArrayList of Integers. Below you will find my attempt. I believe that it is working as intended, but I wonder if there are better ways to get this done. Any comments are appreciated.
public static int findMin(ArrayList<Integer> numbers){
// Base Case
if(numbers.size()==1){
return numbers.get(0).intValue();
}
ArrayList<Integer> numbers_short = new ArrayList<Integer>(numbers);
numbers.remove(numbers.size()-1);
return Math.min(numbers_short.get(numbers_short.size()-1).intValue(), findMin(numbers));
}
Your example is not so good in the way that you should not use recursivity in this case.
But anyway, you can avoid to copy your array each time, by using a method with a start and end parameters to analyze only a part of your initial array.
Something like that:
public static int findMin(ArrayList<Integer> numbers) {
return findMin(numbers, 0, numbers.size() - 1);
}
public static int findMin(ArrayList<Integer> numbers, int start, int end) {
if (end == start)
return numbers.get(start);
int middle = start + (end - start) / 2;
return Math.min(findMin(numbers, start, middle), findMin(numbers, middle + 1, end));
}
And add a check in case the array is empty if needed.
The reason why I'm using the "middle" method is that each time it divides the array by 2, meaning at the end it limits the risk of stack overflow because it will divide by 2 the maximum number of recursivity compare to recurse on every element.
You may want to avoid creating a new ArrayList object every time you call the method. This may seem non consequential for smaller inputs, but for really large inputs it may lead to StackOverflowError.
A cleaner solution with similar time complexity can be:
public static int findMin(ArrayList<Integer> numbers) {
return findMin(numbers, numbers.size());
}
public static int findMin(ArrayList<Integer> numbers, int len) {
// Base Case
if (len == 1) {
return numbers.get(0);
}
return Math.min(numbers.get(len-1), findMin(numbers, len-1));
}
Reference to garbage collector and recursion: Garbage Collection in Java with Recursive Function
Keeping the original method signature and formal parameters - the code can be simplified by eliminating the need to create a new temporary array each time.
public static int findMin(ArrayList<Integer> numbers){
if (numbers.size() == 1) return numbers.get(0);
return Math.min(numbers.remove(0), findMinimum(numbers));
}
numbers.remove(0) will simultaneously remove the first element and return the value of the removed element, eliminating the need to create a temporary array.

ArrayLinkedList Insertion Sort

I have to do an Array List for an insertion sort and my teacher sent this back to me and gave me an F, but says I can make it up before Friday.
I do not understand why this isn't an A.L insertion sort.
Can someone help me fix this so it hits his criteria?
Thanks.
HE SAID:
After checking your first insertion sort you all did it incorrectly. I specifically said to shift the numbers and move the number into its proper place and NOT SWAP THE NUMBER INTO PLACE. In the assignment in MySA I said if you do this you will get a 0 for the assignment.
import java.util.ArrayList;
public class AListINSSORT {
private static void insertionSort(ArrayList<Integer> arr) {
insertionSort();
}
private static void insertionSort() {
ArrayList<Integer> swap = new ArrayList<Integer>();
swap.add(1);
swap.add(2);
swap.add(3);
swap.add(4);
swap.add(5);
int prior = 0;
int latter = 0;
for (int i = 2; i <= latter; i++)
{
for (int k = i; k > prior && (swap.get(k - 1) < swap.get(k - 2)); k--)
{
Integer temp = swap.get(k - 2);
swap.set(k - 2, swap.get(k - 1));
swap.set(k - 1, temp);
}
}
System.out.println(swap);
}
}
First of all, it seems your teacher asked you to use a LinkedList instead of an ArrayList. There is quite a difference between them.
Secondly, and maybe more to the point. In your inner loop you are saving a temp variable and swapping the elements at position k - 2 and k - 1 with each other. From the commentary this is not what your teacher intended. Since he wants you to solve the problem with element insertion, I recommend you look at the following method definition of LinkedList.add(int i, E e): https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#add(int,%20E).
This should point you in the right direction.
As far as I see, your code does nothing at all.
The condition of the outer for loop
for (int i = 2; i <= latter; i++)
is not fulfilled.
As you start with i = 2 and as latter = 0, it never holds i <= latter.
Thus, you never run through the outer for loop and finally just give back the input values.
If you add the input values to swap in a different order (not already ordered), you will see that your code does not re-order them.
There's a lot of stuff wrong here.
Firstly, your method:
private static void insertionSort(ArrayList<Integer> arr) {
insertionSort();
}
takes an ArrayList and completely ignores it. This should presumably be the List which requires sorting.
Then in insertionSort() you create a new ArrayList, insert some numbers already in order, and then attempt something which looks nothing like insertion sort, but slightly more like bubble sort.
So, when you call insertionSort(List) it won't actually do anything to the list at all, all the work in insertionSort() happens to a completely different List!
Since on SO we don't generally do people's homework for them, I suggest looking at the nice little animated diagram on this page
What you should have then is something like:
public void insertionSort(LinkedList<Integer> numbers) {
//do stuff with numbers, using get() and add()
}

Why is my Parallel Code Running Slow?

I have been asked to use ForkJoin to write the following method:
public static boolean hasOver(int val, int[] arr, int sequentialCutoff)
and my code must have a work of O(n), a span of O(lgn) and use the sequentialCutoff argument. I figured this problem would be fairly straight forward and one in which sequentialCutoff would set the threshold, and the recursion would occur over half the array, repeating until hitting the threshold, before hitting the base case which would just traverse the array over the specified indices, checking to see if any elements greater than val exist. Here is the parallel code portion of what I wrote:
protected Boolean compute() {
if(high - lo <= sequentialCutoff) {
return sequentialCheckHasOver(check, array);
} else {
int mid = lo + (high - lo) / 2;
CheckHasOver left = new CheckHasOver(check, array, lo, mid, cutoff);
left.fork();
CheckHasOver right = new CheckHasOver(check, array, mid, high, cutoff);
return right.compute() || left.join();
}
}
The problem is that when I now run timing tests on the code that I wrote, no matter what threshold I choose, the sequential code is running faster than my parallel code and I cannot, for the life of me, figure out where my reasoning has failed. Can anyone see a mistake in what I've done? Some help would be much appreciated.

Recursive Quicksort for a LinkedList

I've been trying to implement a Recursive Quicksort into my algorithm which makes use of LinkedList. However when I run the method, it seems to go on forever even for a small list (of 10 elements), I've been waiting for the method to stop for about 10 minutes.
This is the code in question
public static void QuickSort(LinkedList<Contacto> Lista, int ini, int fin){
Contacto pivote, aux;
int i, j, comp;
if (ini<fin){
pivote = Lista.get(ini);
i=ini+1;
j=fin;
while (i<j){
while(i<fin && (comp=Lista.get(i).get_name().compareTo(pivote.get_name()))<=0 )
i++;
while((comp=Lista.get(i).get_name().compareTo(pivote.get_name()))>0 )
j--;
if(i<j){
aux = Lista.get(i);
Lista.set(i, Lista.get(j));
Lista.set(j, aux);
}
}
aux=Lista.get(j);
Lista.set(j,pivote);
Lista.set(ini,aux);
QuickSort(Lista,ini,j-1);
QuickSort(Lista,j+1,fin);
}
}
Thanks for your help!
As is noted in the comments, the fact that it's taking ten minutes to sort a list of ten items is due to a bug somewhere, and I recommend you insert some breakpoints/println() statements to get a sense for how your method is proceeding (one at the top of each of your conditionals should be sufficient to show you where it's getting hung up).
That said, inefficiency with very short lists is a known problem with the quicksort algorithm - and, if you think about how the algorithm works, you can see why it's an inherent one. (I can expound on this, but you'll be better off if you figure out why yourself).
A common solution to this issue is having a cutoff: When the size of the list becomes smaller than the cutoff size, switch to a simple insertion sort to finish the job. There is a good discussion about this here, and a very good example implementation here.
Note the first few lines of the quicksort() method in that example:
private static void quicksort(Comparable [] a, int left, int right) {
final int CUTOFF = 3;
if (right-left+1 < CUTOFF) { // if less than three elements remain:
insertionSort(a,left,right);
else { //quicksort...
(note: that first link comes from the booksite for Algorithms, 4th edition, written by some folks at Princeton. I can't recommend that site highly enough as you're reasoning through the fundamental algorithms)

Compare elements in an array of string in Java

I have to write a method that will compare elements in an array of strings and return the index of the largest element. It's going to be done recursively using a divide and conquer approach. I have an idea, and I was just looking to see if my idea was right or if it should be done in a different way.
I was planning on looking at the array from the left side to mid -1, then look at mid, and then look at mid +1 to right. I have a variable that will keep track of the largest index, and then after that make the recursive call for the left side and the right side.
Does that sound like a good way to approach this problem?
This is what I have so far:
public int longest()
{
longest(0, a.length-1);
return longestIndex;
}
private int longest( int left, int right)
{
int longestIndex;
int mid;
if(left > right)
{
longestIndex = -1;
}
else if(left == right)
{
longestIndex = 0;
}
else
{
longestIndex = 0;
mid = (left + right) / 2;
longest(left, mid - 1);
if (a[mid].compareTo(a[longestIndex]) > 0)
{
longestIndex = mid;
}
longest(mid + 1, right);
}
return longestIndex;
}
Also, since the methods are supposed to return an int, how would I pass the longestIndex n the private method up to the public method so that it would show up in my test program when longest is called?
Does it have to be recursive? Using recursion for this sounds like a case of:
And your recursion looks totally wrong anyways, because not only you are not keeping track of the actual index but also your base cases and recursive calls don't make any sense.
If I were compelled to use recursion, I would do something like:
int longest(array):
return longest_helper(0, 0, array)
int longest_helper(max_index, curr_idx, array):
# base case: reached the end of array
if curr_idx == array.length:
return max_index
if array[curr_idx].length > array[max_index].length:
max_index = curr_idx
# recursive call
return longest_helper(max_index, curr_idx + 1, array)
And then I would proceed to drop the class and tell the professor to give students problems where recursion is actually helpful next time around.
Since it doesn't look like the array is sorted, the easiest (and fastest) way to do this would just be go through the whole thing (pseudocode):
max_index = 0
max_length = array[0].length
for index in 1 .. array.length:
if array[index].length > max_length:
max_length = array[index].length
max_index = index
return max_index
This is your fourth question in two days on recursion. It is good that you are putting homework tag but your time would be better spent understanding how recursion works.
My recommendation is to take a few colored discs (poker chips or playing cards of a single suite work well), work out manually the recursive solution to Towers of Hanoi and then come back and look at the individual questions you have been asking.
In all likelihood you will be able to answer all the questions yourself. You would also be able to accept the answers, increasing you chances in future of getting responses when you face tougher questions.

Categories