I've a problem.
I have to edit the standard mergesort algorithm, changing the ratio between the two halves of the array. Standard mergesort splits array in 2. BUT I've to split it with a coefficient.
Example:
I've a 10elements array, and i've to split it with a coeff of 0.2. This means that the first time the array is divided in 2 parts: one with 2 elements, the second with 8 elements. Being recursive, this ratio is applied every time I split the array.
The problem:
If the coeff >=0.5 no probs. If the ratio in <=0.5 every attempt leads to a stackoverflow.
Any help will be kindly appreciated!
Here the class:
public class Sort {
public static double coeff = 0.2;
public static void mergeSort(int[] a) {
int vectorTemp[];
vectorTemp = new int[a.length];
mergeSort(a, vectorTemp, 0, a.length - 1);
}
private static void mergeSort(int[] a, int[] vectorTemp, int left, int right) {
if (left < right) {
int center = calculateMid(left, right);
mergeSort(a, vectorTemp, left, center);
mergeSort(a, vectorTemp, center + 1, right);
merge(a, vectorTemp, left, center + 1, right);
}
}
private static void merge(int[] a, int[] vectorAux, int posLeft, int posRight, int posEnd) {
int endLeft = posRight - 1;
int posAux = posLeft;
int numElemen = posEnd - posLeft + 1;
while (posLeft <= endLeft && posRight <= posEnd) {
if ((a[ posLeft]) < (a[posRight])) {
vectorAux[posAux++] = a[posLeft++];
} else {
vectorAux[posAux++] = a[posRight++];
}
}
while (posLeft <= endLeft) {
vectorAux[posAux++] = a[posLeft++];
}
while (posRight <= posEnd) {
vectorAux[posAux++] = a[posRight++];
}
for (int i = 0; i < numElemen; i++, posEnd--) {
a[posEnd] = vectorAux[posEnd];
}
}
//this is the method i've added to calculate the size
private static int calculateMid(int left, int right){
int mid = 0;
int tot = right-left+1;
int firstHalf = (int) (tot * coeff);
mid = left + firstHalf;
System.out.println(left+", "+mid +", "+firstHalf+", "+right + ", "+tot);
return mid-1;
}
public static void main(String[] args) {
int vector2[] = {10, 3, 15, 2, 1, 4, 9, 0};
System.out.println("Array not ordered: " + Arrays.toString(vector2) + "\n");
mergeSort(vector2);
System.out.println("Array ordered: " + Arrays.toString(vector2));
}}
Here is a hint:
Think about what calculateMid() returns for a two-element array, and what happens in mergeSort() after that.
Once you figure out what happens there, it will also become clear why the code works for coeff >= 0.5.
Related
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 have a homework problem that gives me this array:
[3, 22, 1, 5, 6, 10, 4]
And I need to move all numbers that are larger than the last value, 4, to the right of the value and all of the values that are smaller to the left.
The numbers do not necessarily need to be in order. So, the output of the program would be:
[3, 1, 4, 22, 5, 6, 10]
For some reason I am really struggling to think of an algorithm that would allow for this to happen. I have tried creating a loop that swaps the last value with larger numbers, but if a smallest value is mixed in the array somewhere odd it will be to the right of the value which is not correct.
Can anyone help me with this?
I won't help you complete the home-work. But I will guide you to think where this example of yours is headed. It is the first step of quick sort - Partitioning the array.
public class QuickSortImpl {
private static void swap(int[] array, int l, int h) {
int temp = array[h];
array[h] = array[l];
array[l] = temp;
}
public static int partition(int[] array, int low, int high) {
int pivot = high;
int firsthigh = low;
int x,y;
for (int i = low; i < high; i++) {
x = array[i];
y = array[pivot];
if (array[i] < array[pivot]) {
swap(array, i, firsthigh);
firsthigh++;
}
}
swap(array, pivot, firsthigh);
return firsthigh;
}
private static void printArray(int[] arr ) {
for ( int i =0; i < arr.length; i++ ) {
System.out.print(" " + arr[i]);
}
System.out.println();
}
public static void quickSort(int[] array, int low, int high) {
if ( low < high ) {
int pivot = partition(array, low, high);
quickSort(array, low, pivot - 1);
quickSort(array, pivot + 1, high);
}
}
public static void main(String[] args) {
int[] arr = { 3, 22, 1, 5, 6, 10, 4};
quickSort(arr, 0, arr.length -1 );
printArray(arr);
}
}
#brent_mb, take a look at this simple example for your cause:
public static void main(String[] args) {
Integer[] listOfNumbers = {1,4,5,6,74,2,7,8,5,2,6,989,3};
//sort by number 6
FirstCustomComparator comparator = new FirstCustomComparator(6);
Arrays.sort(listOfNumbers, 0, listOfNumbers.length, comparator);
for (int number : listOfNumbers) {
System.out.print(number+" ");
}
}
FirstCustomComparator class:
public class FirstCustomComparator implements Comparator<Integer> {
private final int exception;
public FirstCustomComparator(int i)
{
exception = i;
}
#Override
public int compare(Integer a, Integer b)
{
if (a < exception)
{
return -1;
}
return a.compareTo(b);
}
}
I am coding a program which is basically going to compute the number of inversions in the array. The requirement is to use a divide-and-conquer algorithm.
I have used merge sort but afterwards I am stuck. I need to create another method called count in order to count the inversions using recursion. Here I need your help...
Thank you in advance
import java.util.*;
public class inversions
{
public static void main(String[] args)
{
Integer[] a = {2, 6, 3, 5, 1};
mergeSort(a);
System.out.println(Arrays.toString(a));
}
public static void mergeSort(Comparable [ ] a)
{
Comparable[] tmp = new Comparable[a.length];
mergeSort(a, tmp, 0, a.length - 1);
}
private static void mergeSort(Comparable [ ] a, Comparable [ ] tmp, int left, int right)
{
if( left < right )
{
int center = (left + right) / 2;
mergeSort(a, tmp, left, center);
mergeSort(a, tmp, center + 1, right);
merge(a, tmp, left, center + 1, right);
}
}
private static void merge(Comparable[ ] a, Comparable[ ] tmp, int left, int right, int rightEnd )
{
int leftEnd = right - 1;
int k = left;
int num = rightEnd - left + 1;
while(left <= leftEnd && right <= rightEnd)
if(a[left].compareTo(a[right]) <= 0)
tmp[k++] = a[left++];
else
tmp[k++] = a[right++];
while(left <= leftEnd) // Copy rest of first half
tmp[k++] = a[left++];
while(right <= rightEnd) // Copy rest of right half
tmp[k++] = a[right++];
// Copy tmp back
for(int i = 0; i < num; i++, rightEnd--)
a[rightEnd] = tmp[rightEnd];
}
public int count(int[] A, int n){}
}
Added some changes in Your Code.
import java.util.*;
public class inversions
{
public static int countInversions = 0;
public static void main(String[] args)
{
Integer[] a = {2, 6, 3, 5, 1};
mergeSort(a);
System.out.println(Arrays.toString(a));
System.out.println(countInversions);
}
public static void mergeSort(Comparable [ ] a)
{
Comparable[] tmp = new Comparable[a.length];
mergeSort(a, tmp, 0, a.length - 1);
}
private static void mergeSort(Comparable [ ] a, Comparable [ ] tmp, int left, int right)
{
if( left < right )
{
int center = (left + right) / 2;
mergeSort(a, tmp, left, center);
mergeSort(a, tmp, center + 1, right);
merge(a, tmp, left, center + 1, right);
}
}
private static void merge(Comparable[ ] a, Comparable[ ] tmp, int left, int right, int rightEnd )
{
int leftEnd = right - 1;
int k = left;
int num = rightEnd - left + 1;
while(left <= leftEnd && right <= rightEnd)
if(a[left].compareTo(a[right]) <= 0)
tmp[k++] = a[left++];
else {
countInversions+=((leftEnd-left)+1); // Counts the inversions
tmp[k++] = a[right++];
}
while(left <= leftEnd) // Copy rest of first half
tmp[k++] = a[left++];
while(right <= rightEnd) // Copy rest of right half
tmp[k++] = a[right++];
// Copy tmp back
for(int i = 0; i < num; i++, rightEnd--)
a[rightEnd] = tmp[rightEnd];
}
}
In the above code, we are counting the inversions when two arrays are merging. For example 1st sub-array contains [1, 6] and 2nd sub-array has [2, 3]. So when these are merged together inversion count will be 2 i.e. [6>2] & [6>3]. When the condition comes that a[left] > a[right] it will count the number of elements remaining on the right sub-array because will be less than the a[left] and will add them to countInversions.
I need to split this array after it is sorted so that it prints something like
A: [8, 7, 6, 5]
B: [4, 3, 2, 1]
I know it might be simple but I cant figure it out. Do I need to do something like x.length / 2 ?
import java.util.Arrays;
public class RecursiveMerge
{
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] x= {8,7,5,6,2,4,3,1};
System.out.println(Arrays.toString(x));
System.out.println(Arrays.toString(mergeSort(x)));
}
public static int [] mergeSort (int []a)
{
if(a.length ==1)
return a;
else
{
int mid = a.length/2;
int [] left =mergeSort(Arrays.copyOfRange(a, 0 , mid ));
int [] right =mergeSort(Arrays.copyOfRange(a, mid, a.length ));
mergeSort(left);
mergeSort(right);
return merge (left, right);
}
}
public static int[] merge (int[] left, int[] right)
{
int [] result = new int [left.length + right.length];
int leftPtr=0, rightPtr=0, resultPtr=0;
while(leftPtr < left.length && rightPtr < right.length)
if (left[leftPtr] < right [rightPtr])
result[resultPtr++] = left[leftPtr++];
else
result[resultPtr++] = right[rightPtr++];
while (leftPtr < left.length)
result[resultPtr++] = left[leftPtr++];
while (rightPtr <right.length)
result[resultPtr++] = right[rightPtr++];
return result;
}
}
To make it dynamically, do it based on array length and split it in two:
int [] x= {8,7,5,6,2,4,3,1};
int len = x.length;
int a[] = Arrays.copyOfRange(mergeSort(x), 0, len/2);
int b[] = Arrays.copyOfRange(mergeSort(x), (len/2), len);
System.out.println("A: " + Arrays.toString(a));
System.out.println("B: " + Arrays.toString(b));
Hope it helps.
An edit to the accepted answer could take into account that half an odd numbered int is actually the nearest, smaller, whole number, to the half. So, something like this is more appropriate:
int size = array.size();
int half = size % 2 == 0 ? size / 2 : (size / 2) + 1;
I have three classes. Each creates an array of 1000 int values.
class a: uses QuickSort
class b: uses QuickSort until the size of each partition is <10 then executes InsertSort for sorting the smaller partitions.
class c: (this is the one I'm having trouble with): same as class b except executes InsertSort on the whole almost sorted array.
It would seem that class c is only a slight variation of the code in class b (which basically adds to class a). I just don't really know HOW to make this happen... Help! Thanks in advanced...
Class a:
import java.util.Arrays;
import java.util.Random;
public class QuickSort {
private static final Random random = new Random();
private static final int RANDOM_INT_RANGE = 9999;
private static int[] randomArray(int size) {
// Randomize data (array)
final int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(RANDOM_INT_RANGE);
}
return arr;
}
// Sort
private static void sort(int[] arr) {
if (arr.length > 0)
sortInPlace(arr, 0, arr.length - 1);
}
private static void sortInPlace(int[] arr, int left, int right) {
if (left >= right)
return; // sorted
final int range = right - left + 1;
int pivot = random.nextInt(range) + left;
int newPivot = partition(arr, left, right, pivot);
sortInPlace(arr, left, newPivot - 1);
sortInPlace(arr, newPivot + 1, right);
}
private static int partition(int[] arr, int left, int right, int pivot) {
int pivotVal = arr[pivot];
swapArrayVals(arr, pivot, right);
int storeIndex = left;
for (int i = left; i <= (right - 1); i++) {
if (arr[i] < pivotVal) {
swapArrayVals(arr, i, storeIndex);
storeIndex++;
}
}
swapArrayVals(arr, storeIndex, right);
return storeIndex;
}
private static void swapArrayVals(int[] arr, int from, int to) {
int fromVal = arr[from];
int toVal = arr[to];
arr[from] = toVal;
arr[to] = fromVal;
}
public static void main(String[] args) {
long StartTime = System.nanoTime();
// Array size
int[] arr = randomArray(1000);
int[] copy = Arrays.copyOf(arr, arr.length);
// Print original data (array)
System.out.println("The starting/unsorted array: \n"
+ Arrays.toString(arr));
sort(arr);
// check the result
Arrays.sort(copy);
if (Arrays.equals(arr, copy)) {
System.out.println("The ending/sorted array: \n"
+ Arrays.toString(arr));
// print time
long TotalTime = System.nanoTime() - StartTime;
System.out.println("Total elapsed time (milliseconds) " + "is: "
+ TotalTime);
}
}
}
Class b:
import java.util.Arrays;
import java.util.Random;
public class OptQSort1 {
private static final Random random = new Random();
private static final int RANDOM_INT_RANGE = 9999;
private static int[] randomArray(int size) {
// Randomize data (array)
final int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(RANDOM_INT_RANGE);
}
return arr;
}
// Sort
private static void sort(int[] arr) {
if (arr.length > 0)
sortInPlace(arr, 0, arr.length - 1);
}
private static void sortInPlace(int[] arr, int left, int right) {
boolean insertionSortCalled = false;
// OptQSort1:
int size = right - left + 1;
if (size < 10 && !insertionSortCalled) {
insertionSortCalled = true;
insertionSort(arr, 0, arr.length - 1);
}
if (left >= right)
return; // sorted
final int range = right - left + 1;
int pivot = random.nextInt(range) + left;
int newPivot = partition(arr, left, right, pivot);
sortInPlace(arr, left, newPivot - 1);
sortInPlace(arr, newPivot + 1, right);
}
private static int partition(int[] arr, int left, int right, int pivot) {
int pivotVal = arr[pivot];
swapArrayVals(arr, pivot, right);
int storeIndex = left;
for (int i = left; i <= (right - 1); i++) {
if (arr[i] < pivotVal) {
swapArrayVals(arr, i, storeIndex);
storeIndex++;
}
}
swapArrayVals(arr, storeIndex, right);
return storeIndex;
}
private static void swapArrayVals(int[] arr, int from, int to) {
int fromVal = arr[from];
int toVal = arr[to];
arr[from] = toVal;
arr[to] = fromVal;
}
public static void insertionSort(int[] arr, int left, int right) {
int in, out;
for (out = left + 1; out <= right; out++) {
int temp = arr[out];
in = out;
while (in > left && arr[in - 1] >= temp) {
arr[in] = arr[in - 1];
--in;
}
arr[in] = temp;
}
}
public static void main(String[] args) {
long StartTime = System.nanoTime();
// Array size
int[] arr = randomArray(1000);
int[] copy = Arrays.copyOf(arr, arr.length);
// Print original data (array)
System.out.println("The starting/unsorted array: \n"
+ Arrays.toString(arr));
sort(arr);
// check the result
Arrays.sort(copy);
if (Arrays.equals(arr, copy)) {
System.out.println("The ending/sorted array: \n"
+ Arrays.toString(arr));
// print time
long TotalTime = System.nanoTime() - StartTime;
System.out.println("Total elapsed time (milliseconds) " + "is: "
+ TotalTime);
}
}
}
Class c:
import java.util.Arrays;
import java.util.Random;
public class OptQSort2 {
private static final Random random = new Random();
private static final int RANDOM_INT_RANGE = 9999;
private static int[] randomArray(int size) {
// Randomize data (array)
final int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(RANDOM_INT_RANGE);
}
return arr;
}
// Sort
private static void sort(int[] arr) {
if (arr.length > 0)
sortInPlace(arr, 0, arr.length - 1);
insertionSort(arr, 0, arr.length - 1);
}
private static void sortInPlace(int[] arr, int left, int right) {
// OptQSort2:
int size = right - left + 1;
if (size < 10)
return;
if (left >= right)
return; // sorted
final int range = right - left + 1;
int pivot = random.nextInt(range) + left;
int newPivot = partition(arr, left, right, pivot);
sortInPlace(arr, left, newPivot - 1);
sortInPlace(arr, newPivot + 1, right);
}
private static int partition(int[] arr, int left, int right, int pivot) {
int pivotVal = arr[pivot];
swapArrayVals(arr, pivot, right);
int storeIndex = left;
for (int i = left; i <= (right - 1); i++) {
if (arr[i] < pivotVal) {
swapArrayVals(arr, i, storeIndex);
storeIndex++;
}
}
swapArrayVals(arr, storeIndex, right);
return storeIndex;
}
private static void swapArrayVals(int[] arr, int from, int to) {
int fromVal = arr[from];
int toVal = arr[to];
arr[from] = toVal;
arr[to] = fromVal;
}
public static void insertionSort(int[] arr, int left, int right) {
int in, out;
for (out = left + 1; out <= right; out++) {
int temp = arr[out];
in = out;
while (in > left && arr[in - 1] >= temp) {
arr[in] = arr[in - 1];
--in;
}
arr[in] = temp;
}
}
public static void main(String[] args) {
// Start the clock
long StartTime = System.nanoTime();
// Array size
int[] arr = randomArray(1000);
int[] copy = Arrays.copyOf(arr, arr.length);
// Print original data (array)
System.out.println("The starting/unsorted array: \n"
+ Arrays.toString(arr));
sort(arr);
// check the result
Arrays.sort(copy);
if (Arrays.equals(arr, copy)) {
System.out.println("The ending/sorted array: \n"
+ Arrays.toString(arr));
// print time
long TotalTime = System.nanoTime() - StartTime;
System.out.println("Total elapsed time (milliseconds) " + "is: "
+ TotalTime);
}
}
}
You're saying that class c just implements insertion-sort, with no quick-sort at all, right?
Then in principle, class c could just be class b, with this line:
sort(arr);
changed to this:
insertionSort(arr, 0, arr.length);
(And then you'd want to start stripping out a lot of code — removing methods that are never called, modifying the insertionSort method to assume that left is 0 and right is arr.length rather than requiring them to be specified, renaming the insertionSort method to sort, etc.)
By the way, class c is actually much easier than the classes you've already managed to create. You probably just need to get some sleep. You'll have no problem with it in the morning. :-)
To create class c copy class b and then change it in the following way:
Add instance variable insertionSortCalled so you don't call insertion sort multiple times in different recursive calls
boolean insertionSortCalled= false;
And change this part to the following: insertionSort(arr, 0, arr.length-1);
private static void sortInPlace(int[] arr, int left, int right) {
// OptQSort1:
int size = right - left + 1;
**if (size < 10 && !insertionSortCalled){**
**insertionSortCalled=true;**
**insertionSort(arr, 0, arr.length-1);**
}
if (left >= right)
return; // sorted
final int range = right - left + 1;
int pivot = random.nextInt(range) + left;
int newPivot = partition(arr, left, right, pivot);
sortInPlace(arr, left, newPivot - 1);
sortInPlace(arr, newPivot + 1, right);
}