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