I have implemented a merge sort and would like to run it concurrently.
Merge sort works as follows:
i. Divide the unsorted list into n sublists, each containing 1 element (a list of 1 element
is considered sorted).
ii. Repeatedly merge sublists to produce new sorted sublists until there is only 1 sublist remaining. This will be the sorted list.
The split function is provided below,
public void mergeSort(int[] arr) {
if (arr.length <= 1) {
return;
}
int mid = arr.length / 2;
int[] leftSubArray = Arrays.copyOfRange(arr, 0, mid);
int[] rightSubArray = Arrays.copyOfRange(arr, mid, arr.length);
mergeSort(leftSubArray);
mergeSort(rightSubArray);
merge(arr, leftSubArray, rightSubArray);
}
The method for the merge is provided,
private void merge(int[] arr, int[] left_subArray, int[] right_subArray) {
int i = 0, j = 0;
int index = 0;
while ((i < left_subArray.length) && (j < right_subArray.length)) {
if (left_subArray[i] <= right_subArray[j]) {
arr[index++] = left_subArray[i++];
} else {
arr[index++] = right_subArray[j++];
}
}
while (i < left_subArray.length) {
arr[index++] = left_subArray[i++];
}
while (j < right_subArray.length) {
arr[index++] = right_subArray[j++];
}
}
The program is working fine and I thought it might work more efficiently is run concurrently. The code is here,
public void concurrMergeSort(int[] arr, int numOfThreads) {
if (numOfThreads <= 1) {
mergeSort(nums);
return;
}
/*
split the array in left and right parts
*/
int middleIndex = arr.length / 2;
int[] leftArray = Arrays.copyOfRange(arr, 0, middleIndex);
int[] rightArray = Arrays.copyOfRange(arr, middleIndex, arr.length);
Thread left = mergeSortThread(leftArray, numOfThreads);
Thread right = mergeSortThread(rightArray, numOfThreads);
left.start();
right.start();
try {
left.join();
right.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
merge(arr, leftArray, rightArray);
}
private Thread mergeSortThread(int[] arr, int numOfThreads) {
return new Thread() {
#Override
public void run() {
// split the thread by half
concurrMergeSort(arr, numOfThreads / 2);
}
};
}
Is the implementation is correct?
Related
So I want to use the mergesort algorithm to sort an array filled with numbers from largest to smallest. I have working code for this but I can't seem to make it sort from largest to smallest. I tried playing around with the for loop that has all of those if statements in there but I just couldn't figure it out. Could someone please help.
public class MergeSorter
{
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result+ i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] < second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}
import java.util.Arrays;
public class MergeSortTest
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}
Your entire logic is correct except one thing. In the sort_descend function, after you copy the array a into first_replace and second_replace, you start comparing the elements using the if condition if (first_replace[first_i] < second_replace[second_i]).
Here, you essentially assign the smaller of the two elements into your array a and this the step which determines whether your array will be sorted in ascending order or descending order.
To sort in descending order, you need to just reverse this sign and you will get the desired output i.e. change the if condition to if (first_replace[first_i] > second_replace[second_i]).
Please refer to the below code to sort an array of integers in descending order.
It is similar to your solution but only one change of the comparator operator on line number 38.
import java.util.Arrays;
public class C
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}
class MergeSorter {
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result + i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] >= second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}
I've tried to write a Mergesort Algorithm in Java:
static void merge(int[] sort, int l, int m, int r) {
int[] cache_array = new int[r - l + 1];
int l_cache = l;
int _mid = m + 1;
for (int i = 0; i < r - l + 1; i++) {
if (l > m) {
cache_array[i] = sort[_mid];
_mid++;
} else { if (_mid > r) {
cache_array[i] = sort[l];
l++;
} else { if (sort[l] >= sort[_mid]) {
cache_array[i] = sort[l];
l++;
} else { if (sort[_mid] > sort[l]) {
cache_array[i] = sort[_mid];
_mid++;
}}}}
}
for (int i = 0; i < cache_array.length; i++) {
sort[i + l_cache] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (l < r) {
int mid = (int)Math.floor((l + r - 1) / 2);
mergeSort(sort, l, mid);
mergeSort(sort, mid + 1, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length - 1);
for (int i : a) {
System.out.println(i);
}
}
But it just sorts a part of the Array and replaces the rest of it with zeros. I tried to change the cache_array to a LinkedList but nothing changed and after I tried debugging I couldn't find out anything, too.
I'd appreciate it if you'd help me and/or show me another Mergesort Algorithm that works for Java.
(I used this Algorithm because it worked for Python and so I wanted to use similar code in Java)
The bug in your code is difficult to spot:
the loop in your merge function iterates for i from 0 to r - l + 1 excluded, which would be correct if r and l remained constant during the loop, but you increment l each time you copy from the left part, reducing the number of iterations. As a consequence, the loop exits early, leaving the remaining elements in cache_array with their default value 0.
There are multiple sources of confusion in the code:
the convention to include r in the slice is confusing: it requires +1/-1 adjustments to compute the slice lengths and the middle index.
using Math.floor() is useless: integer arithmetic uses integer division in java.
incrementing the l and m arguments is confusing as these lose their meaning if the value is changed. Use other index variables to iterate through the arrays.
adding a { between the else and if keywords introduces unnecessary indentation levels.
the last condition is the opposite of the previous one: you should just omit it. Note that if the array elements were floating point values, both conditions could be false for NaN values and some elements of cache_array would be left untouched. This last condition would cause errors in this case.
Here is a modified version:
// merge adjacent slices of the `sort` array.
// left slice has elements from `l` included to `m` excluded
// right slice has elements from `m` included to `r` excluded
static void merge(int[] sort, int l, int m, int r) {
int len = r - l;
int[] cache_array = new int[len];
for (int i = 0, ll = l, mm = m; i < len; i++) {
if (ll >= m) {
cache_array[i] = sort[mm];
mm++;
} else
if (mm >= r) {
cache_array[i] = sort[ll];
ll++;
} else
if (sort[ll] >= sort[mm]) {
cache_array[i] = sort[ll];
ll++;
} else {
cache_array[i] = sort[mm];
mm++;
}
}
for (int i = 0; i < len; i++) {
sort[l + i] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (r - l > 1) {
int mid = l + (r - l) / 2;
mergeSort(sort, l, mid);
mergeSort(sort, mid, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length);
for (int i : a) {
System.out.println(i);
}
}
This is how I write the mergesort algorithm.
public static int[] mergeSort(int[] sort) {
if(sort.length > 1) {
int mid = sort.length / 2;
int[] left = Arrays.copyOf(sort, mid);
int[] right = Arrays.copyOfRange(sort, mid, sort.length);
// sort the left and right arrays
mergeSort(left);
mergeSort(right);
// Merge the arrays
merge(sort, left, right);
}
}
private static void merge(int[] sort, int[] leftArray, int[] rightArray) {
// These values are just to keep track of our position in each of the 3
// arrays
int l = 0; // left array
int r = 0; // right array
int o = 0; // the actual array being sorted
while(l < leftArray.length && r < rightArray.length) {
if(leftArray[l] < righArray[r]) {
sort[o++] = leftArray[l++];
}
else {
sort[o++] = leftArray[r++];
}
}
// Now that we are out of the while loop we know that either the
// left or right array has all of its values in sort, so we just
// need to put the rest of the values in the array that doesn't have
// all of its elements in sort with the following code.
while(l < leftArray.length) {
sort[o++] = leftArray[l++];
}
while(r < rightArray.length) {
sort[o++] = rightArray[r++];
}
}
I usually implement it like this:
/// <summary>
/// Mergesort
/// best-case: O(n* log(n))
/// average-case: O(n* log(n))
/// worst-case: O(n* log(n))
/// </summary>
/// <returns>The sorted array.</returns>
/// <param name="array">array.</param>
public static int[] MergeSort(int[] array) {
// Exit condition for recursion
if (array.length <= 1) return array;
// Middle index of list to sort
int m = array.length / 2;
// Define left and right sub-listså
int[] left_array = new int[m];
int[] right_array = new int[array.length - m];
// Initialize left list
for (int i = 0; i < m; i++) left_array[i] = array[i];
// Initialize right list
for (int i = m, x = 0; i < array.length; i++, x++) right_array[x] = array[i];
// Recursively sort left half of the list
left_array = MergeSort(left_array);
// Recursively sort right half of the list
right_array = MergeSort(right_array);
// Merge sorted sub-lists
return Merge(left_array, right_array);
}
/// <summary>
/// Merge the specified left_array and right_array.
/// </summary>
/// <returns>The merge.</returns>
/// <param name="left_array">Left array.</param>
/// <param name="right_array">Right array.</param>
public static int[] Merge(int[] left_array, int[] right_array) {
int[] m = new int[left_array.length + right_array.length];
int index_l = 0;
int nl, nr;
nl = left_array.length - 1;
nr = right_array.length - 1;
for (int i = 0; i <= nl + nr + 1; i++) {
if (index_l > nl) {
m[i] = (right_array[i - index_l]);
continue;
}
if (index_l < i - nr) {
m[i] = (left_array[index_l]);
index_l++;
continue;
}
if (left_array[index_l] <= (right_array[i - index_l])) {
m[i] = (left_array[index_l]);
index_l++;
} else {
m[i] = (right_array[i - index_l]);
}
}
return m;
}
A few months ago I wrote all of the common sorting algorithms and this is what I got. A bit inaccurate but just to See how this implementation performs.
The other algorithms are here.
To achieve a descending order I think you just have to swap the comparison operators.
I want to implement Merge Sort using one a mergeSort method that splits the sequences of an int array up until it's a single element and using a method merge to put them together.
With my code as it is I get a Stackoverflow Error.
Anyone has an idea why?
public static int[] mergeSort(int[] seq) {
return mergeSort(seq, 0, seq.length - 1);
}
private static int[] mergeSort(int[] seq, int l, int r) {
if (seq.length < 2) {
return seq;
}
int s = (l + r) / 2;
int[] a = new int[s];
int[] b = new int[seq.length - s];
for (int i : a) {
a[i] = seq[i];
}
for (int j : b) {
b[j] = seq[s + j];
}
mergeSort(a);
mergeSort(b);
return merge(a, b);
}
public static int[] merge(int[] ls, int[] rs) {
// Store the result in this array
int[] result = new int[ls.length + rs.length];
int i, l, r;
i = l = r = 0;
while (i < result.length) {
if (l < ls.length && r < rs.length) {
if (ls[l] < rs[r]) {
result[i] = ls[l];
++i;
++l;
} else {
result[i] = rs[r];
++i;
++r;
}
} else if (l >= ls.length) {
while (r < rs.length) {
result[i] = rs[r];
++i;
++r;
}
} else if (r >= rs.length) {
while (l < ls.length) {
result[i] = ls[l];
++i;
++l;
}
}
}
return result;
}
The stack overflow is caused by calling the method recursively too many times, possibly infinitely.
private static int[] mergeSort(int[] seq, int l, int r) this will always be called with l=0 and r=seq.length-1, so it's not really necessary to overload.
Here: int s = (l + r) / 2; if the array has 2 elements, this will return 0 (l=0, r=1), so the array will be split to a length 0, and a length 2 (and here is what causes the infinite recursive calls). Add one to the result, and the splitting of the array will work correctly.
To copy the parts of the original array, it's easier to use Arrays.copyOfRange() than writing your own for loop. And you're trying to use the existing elements of arrays a and b, which will all be 0, for indexing.
There are two small issues with your code.
First one is here:
public static int[] mergeSort(int[] seq) {
return mergeSort(seq, 0, seq.length - 1);
}
You need to call it as return mergeSort(seq, 0, seq.length);
The reason behind that is that for example when you have 2 elements and you call it like that with -1 you pass an array with 2 elements but s=1+0/2 =0 and you don't actually split it. Each subsequent recursion call is done with one empty array and one array with the same 2 elements causing an infinite loop and a stackoverflow exception
The second problem is this one:
for (int i : a) { and for (int i : b) {
You can't do the for loop like because you want to iterate on indexes not values of the array. You need to change it to:
for (int i=0;i<a.length;i++) {
a[i] = seq[i];
}
for (int i=0;i<b.length;i++) {
b[i] = seq[s + i];
}
And the last problem with your code is that you don't assign the values of the resulting sorted array and when you do the recursive calls it returns the sorted sub part but you don't get the result. It should become:
a=mergeSort(a);
b=mergeSort(b);
And here is the final code:
public static void main(String... args) {
int[] array={3,9,4,5,1} ;
array=mergeSort(array);
for(int i:array) {
System.out.print(i+",");
}
}
private static int[] mergeSort(int[] seq) {
if (seq.length < 2) {
return seq;
}
int s = seq.length / 2; //You always use that value. no need for 2 methods
int[] a = new int[s];
int[] b = new int[seq.length - s];
for (int i=0;i<a.length;i++) {
a[i] = seq[i];
}
for (int i=0;i<b.length;i++) {
b[i] = seq[s + i];
}
a=mergeSort(a);
b=mergeSort(b);
return merge(a, b);
}
public static int[] merge(int[] ls, int[] rs) {
// Store the result in this array
int[] result = new int[ls.length + rs.length];
int i, l, r;
i = l = r = 0;
while (i < result.length) {
if (l < ls.length && r < rs.length) {
if (ls[l] < rs[r]) {
result[i] = ls[l];
++i;
++l;
} else {
result[i] = rs[r];
++i;
++r;
}
} else if (l >= ls.length) {
while (r < rs.length) {
result[i] = rs[r];
++i;
++r;
}
} else if (r >= rs.length) {
while (l < ls.length) {
result[i] = ls[l];
++i;
++l;
}
}
}
return result;
}
I want to modify the 2 threaded merge sort to 4 threaded merge sort. First I want to divide the array into 4 equal subarrays(the last subarray might be larger) and assign them into separate threads to sort. Finally, merge 1 and 2 subarrays and 3 and 4 subarrays, then merge already sorted-merged 1 and 2 subarrays with sorted-merged 3 and 4 subarrays.
here is what i have as now:
How can I implement that? Thanks ver much!!!
package four_threaded;
import java.util.Random;
public class four_threaded_merge_sort {
public static void finalMerge(int[] a, int[] b) {
int[] result = new int[a.length + b.length];
int i=0;
int j=0;
int r=0;
while (i < a.length && j < b.length) {
if (a[i] <= b[j]) {
result[r]=a[i];
i++;
r++;
}
else {
result[r]=b[j];
j++;
r++;
}
if (i==a.length) {
while (j<b.length) {
result[r]=b[j];
r++;
j++;
}
}
if (j==b.length) {
while (i<a.length) {
result[r]=a[i];
r++;
i++;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Random rand = new Random();
int[] original = new int[10];
for (int i=0; i<original.length; i++) {
original[i] = rand.nextInt(100);
}
long startTime = System.currentTimeMillis();
int s = original.length / 4 ;
int r = original.length % 4;
//first subarray
int[] subArr1 = new int[s];
System.arraycopy(original, 0, subArr1, 0, s);
//second subarray
int[] subArr2 = new int[s];
System.arraycopy(original, s, subArr2, 0, s);
//third subarray
int[] subArr3 = new int[s];
System.arraycopy(original, 2*s, subArr3, 0, s);
//fourth subarray
int[] subArr4 = new int[s+r];
System.arraycopy(original, 3*s, subArr4, 0, s+r);
Worker runner1 = new Worker(subArr1);
Worker runner2 = new Worker(subArr2);
Worker runner3 = new Worker(subArr3);
Worker runner4 = new Worker(subArr4);
runner1.start();
runner2.start();
runner3.start();
runner4.start();
runner1.join();
runner2.join();
runner3.join();
runner4.join();
finalMerge(runner1.getInternal(), runner2.getInternal());
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println("4-thread MergeSort takes: " + (float)elapsedTime/1000 + " seconds");
}
}
class Worker extends Thread {
private int[] internal;
public int[] getInternal() {
return internal;
}
public void mergeSort(int[] array) {
if (array.length > 1) {
int[] left = leftHalf(array);
int[] right = rightHalf(array);
mergeSort(left);
mergeSort(right);
merge(array, left, right);
}
}
public int[] leftHalf(int[] array) {
int size1 = array.length / 2;
int[] left = new int[size1];
for (int i = 0; i < size1; i++) {
left[i] = array[i];
}
return left;
}
public int[] rightHalf(int[] array) {
int size1 = array.length / 2;
int size2 = array.length - size1;
int[] right = new int[size2];
for (int i = 0; i < size2; i++) {
right[i] = array[i + size1];
}
return right;
}
public void merge(int[] result, int[] left, int[] right) {
int i1 = 0;
int i2 = 0;
for (int i = 0; i < result.length; i++) {
if (i2 >= right.length || (i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1];
i1++;
} else {
result[i] = right[i2];
i2++;
}
}
}
Worker(int[] arr) {
internal = arr;
}
public void run() {
mergeSort(internal);
}
}
After the 4 threads complete, you could use 2 threads to merge the 4 sub-arrays into 2 sub-arrays, although that probably won't help much since the merging of large arrays will be memory bandwidth limited. You could also use the main thread to do a 4 way merge. On processor with 16 registers, like a PC in 64 bit mode, there are enough registers to deal with 4 sub-arrays via pointers or indices.
If speed is the goal here, allocating a working array one time and using a bottom up merge sort would be faster than top down. To avoid copying, each merge sort alternates merging data between the original and the working array. Each merge sort can determine the number of passes needed, and if it's an odd number, then swap in place for the first pass instead of merging to the other buffer.
If the final pass will be a 4 way merge, then each merge sort thread should end up with the sorted data in the working array. In this case, if it's an even number of passes, then swap in place for the first pass. You may want to do an in place swap for more than 2 elements at a time. Using something like a sorting network, 4 elements can be swapped with 6 if / swap statements. I'm not sure about using other in place sort methods for small sets of elements helps.
I have implemented the select/median of medians algorithm using the following as a reference http://www.ics.uci.edu/~eppstein/161/960130.html (this has previously been linked here Median of Medians in Java).
My code seems to work for small arrays (~100) and even works for arrays of size 100001 http://pastebin.com/mwRc4Hig (answer 5008), but then fails on an input array of size 10001 http://pastebin.com/YwVBmgDk (answer 4960, my code outputs 4958).
Note that the correct answers for the texts above are equivalent to sorting the array and returning the element at array[array.length / 2], regardless of whether the array size is even or odd.
I'm not sure how to debug this issue. The functionality seems arbitrary and I'm just lost. Here below is my code:
public class MedianOfMedians {
public static void main(String[] args) {
MedianOfMedians mds = new MedianOfMedians();
mds.run();
}
private void run() {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] numArray = new int[n];
for (int i = 0; i < n; i++) {
numArray[i] = in.nextInt();
}
int median = select(numArray, numArray.length / 2);
System.out.print(median);
}
private int select(int[] numArray, int k) {
if (numArray.length <= 10) {
int[] sorted = insertionSort(numArray);
return sorted[k];
}
int divCount = (numArray.length % 5 == 0) ? numArray.length / 5 - 1 : numArray.length / 5;
int[] medOfMed = new int[divCount + 1];
int counter = 0;
int[] subArray;
while (counter <= divCount) {
subArray = splitByFive(counter, divCount, numArray);
medOfMed[counter] = select(subArray, subArray.length / 2);
counter++;
}
int M = select(medOfMed, numArray.length / 10);
List<Integer> lt = new ArrayList<>();
List<Integer> eq = new ArrayList<>();
List<Integer> gt = new ArrayList<>();
for (int i : numArray) {
if (i < M) {
lt.add(i);
} else if (i == M) {
eq.add(i);
} else {
gt.add(i);
}
}
if (k < lt.size()) {
return select(createArray(lt), k);
} else if (k > lt.size() + eq.size()) {
return select(createArray(gt), k - lt.size() - eq.size());
} else {
return M;
}
}
private int[] splitByFive(int splitIter, int divisions, int[] toSplit) {
int numToCopy;
if (splitIter == divisions) {
numToCopy = toSplit.length - (5 * splitIter);
} else {
numToCopy = 5;
}
int[] subArray = new int[numToCopy];
System.arraycopy(toSplit, splitIter * 5, subArray, 0, numToCopy);
return subArray;
}
private int[] createArray(List<Integer> list) {
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
private int[] insertionSort(int[] numArray) {
for (int i = 1; i < numArray.length; i++) {
int j = i;
while (j - 1 >= 0 && numArray[j] < numArray[j - 1]) {
int temp = numArray[j];
numArray[j] = numArray[j - 1];
numArray[j - 1] = temp;
j--;
}
}
return numArray;
}
}
I don't have time to debug your code, but maybe I can offer a debugging technique for you to try yourself that's useful for recursive algorithms like this.
If there is an input that the algorithm fails on (and there is, as you found) then there is a smallest such input -- and the smaller this input, the easier it is to figure out what's going wrong. Because the algorithm is recursive, you have a nice way to isolate the first place that things go wrong: you can test that the result you are about to return from select() is correct (using a slow, trusted method like copying the data to a temporary buffer, sorting it and then grabbing the half-way element) just before returning the value. Doing this will be much easier if you rearrange the function to use just a single return statement, e.g.:
private int select(int[] numArray, int k) {
int knownCorrectAnswer = selectSlowlyButDefinitelyCorrectly(numArray, k);
int willReturn;
if (numArray.length <= 10) {
int[] sorted = insertionSort(numArray);
willReturn = sorted[k]; // Just remember what we will return
} else { // Need to add else branch here now
...
if (k < lt.size()) {
willReturn = select(createArray(lt), k);
} else if (k > lt.size() + eq.size()) {
willReturn = select(createArray(gt), k - lt.size() - eq.size());
} else {
willReturn = M;
}
} // End of inserted else branch
if (willReturn == knownCorrectAnswer) {
return willReturn;
} else {
yell("First problem occurs with numArray=<...> and k=<...>!");
}
}
yell() should print out the entire problem instance and halt the program (e.g. by throwing an exception). The nice thing about this setup is that you know that when yell() gets called, every call to select() that has already completed was correct -- since if it wasn't, yell() would have already been called and the program would have halted before now. So the output produced by yell() is guaranteed to be the first (not necessarily the smallest, but often that also) subproblem in which things went wrong.