StackOverflowError while implementing QuickSort - java

I am trying to implement an QuickSort algorithm on an ArrayList. However, I am getting a
Exception in thread "main" java.lang.StackOverflowError
at sorting.QuickSort.quickSort(QuickSort.java:25)
at sorting.QuickSort.quickSort(QuickSort.java:36)
at sorting.QuickSort.quickSort(QuickSort.java:36)
at sorting.QuickSort.quickSort(QuickSort.java:36)
at sorting.QuickSort.quickSort(QuickSort.java:36)
...
I am not sure as to why is there an overflow. Below is my implementation:
public static void quickSort(ArrayList<Integer> al, int fromIdx, int toIdx) {
int pivot, pivotIdx;
if (fromIdx < toIdx) {
pivot = al.get(fromIdx);
pivotIdx = fromIdx;
for (int i = 0; i != (fromIdx + 1); i++) {
if (al.get(i) <= pivot) {
pivotIdx += 1;
swap(al, pivotIdx, i);
}
}
swap(al, fromIdx, pivotIdx);
quickSort(al, fromIdx, pivotIdx - 1);
quickSort(al, pivotIdx + 1, toIdx);
}
}
public static void swap(ArrayList<Integer> al, int xIdx, int yIdx) {
Integer temp = al.get(xIdx);
al.set(xIdx, al.get(yIdx));
al.set(yIdx, temp);
}

If you're trying to sort the chunk of the array from fromIdx to toIdx, you should never look at element 0 unless it is in that chunk. But your implementation does.
Your indexing trick in the middle is also kind of..odd. I highly recommend that you do the exercise of cutting out little pieces of paper for the array, and writing tracking information on a sheet of paper so that you can trace through the algorithm. If when you physically do it, you see it not make sense, then it doesn't make sense in the computer either. And the act of holding physical pieces of paper may seem silly, but is of great help in visualizing exactly what you are doing. (The more precisely you can visualize what your code actually does, the more likely you are to be able to figure out if it is doing something wrong.)

Related

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.

QuickSort stack overflow on big input

My QuickSort implementation causes StackOverflow error if I give reverse-sorted array. It is working fine for about 1000 items, but for 10000+ I get StackOverflow error. If I get the error the recursion depth is about 9000. I know my algorithm always choose the latest element of the subarray as pivot, which is not optimal, but I would not change that, because I want to make it work like this.
Here is the code:
private int partition(int[] numbers, int begin, int end) {
int pivot = numbers[end];
int partitionIndex = begin;
for (int i = begin; i < end; ++i) {
comparisonCounter++;
if (numbers[i] <= pivot) {
if (i != partitionIndex) {
swapCounter++;
int temp = numbers[i];
numbers[i] = numbers[partitionIndex];
numbers[partitionIndex] = temp;
}
partitionIndex++;
}
}
if (partitionIndex != end) {
swapCounter++;
int temp = numbers[partitionIndex];
numbers[partitionIndex] = numbers[end];
numbers[end] = temp;
}
return partitionIndex;
}
private void quickSort(int[] numbers, int begin, int end) {
if (begin < end) {
int partitionIndex = partition(numbers, begin, end);
quickSort(numbers, begin, partitionIndex - 1);
quickSort(numbers, partitionIndex + 1, end);
}
}
Is there something wrong with my implementation? How could I fix it?
Thank you!
Nothing seems wrong with your code but bear in mind that this is a recursive function and most languages have a limited-depth stack which you are bound to get to if you have an input large enough. For Java, see:
What is the maximum depth of the java call stack?
How to predict the maximum call depth of a recursive method?
What you could do is turn your method, from a recursive to an iterative approach. There are several ways you can do it. I just found a couple examples online:
http://www.geeksforgeeks.org/iterative-quick-sort/
http://kosbie.net/cmu/summer-08/15-100/handouts/IterativeQuickSort.java
There are some ways to reduce the stack size in Quicksort.
You could put the larger partition on the stack each time, leaving it there while the smaller partition is sorted first. That keeps too many small partitions from clogging up the stack at once.
You could use another method, such as insertion sort, to sort small partitions rather than Quicksort. Again, that keeps a lot of small partitions off the stack. You can experiment, but something in the region of 15 - 20 elements usually counts as a "small" partition.
As you say, using a better method to pick your pivot would also help.

Stackoverflow error while implementing insertion sort using recursion

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.

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