How to do sort/merg using two threads? - java

I am trying to do Array sort/merg using two threads. But somehow it is not working (Still the array is not sorted) probably due to some misunderstanding of threading or something else. Would appreciate to have your help. ps: I do have to use two threads as it is required for the assignment.
Original Code
public void sort(int[] data, int lo, int hi)
{
if (lo < hi) {
// divide into two halves
int mid = (lo + hi) / 2;
// sort the two half recursively
sort(data, lo, mid);
sort(data, mid+1, hi);
//Combine the two halves
merge(data, lo, hi, mid);
}
}
private static void merge(int[] data, int lo, int hi, int m)
{
.....
This is what I do
public class Sort
{
public void sort(int[] data, int lo, int hi)
{
if (lo < hi) {
int mid = (lo + hi) / 2;
Thread t1=new Thread(new Runnable() {
public void run() {
sort(data, lo, mid);
}
});
Thread t2=new Thread(new Runnable(){
public void run() {
sort(data, mid+1, hi);
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Combining two halves
merge(data, lo, hi, mid);
}
}
private static void merge(int[] data, int lo, int hi, int m)
{
int[] temp = new int[hi - lo + 1];
int i = lo;
int j = m+1;
int k = 0;
while(k < temp.length) {
if (i <= m) {
if (j <= hi) {
if (data[i] < data[j])
temp[k++] = data[i++];
else
temp[k++] = data[j++];
} else
temp[k++] = data[i++];
} else
temp[k++] = data[j++];
}
for (k = lo; k<=hi; k++)
data[k] = temp[k - lo];
}

Related

First and last pivot element vs generic placement with very large N

I've implemented a QuickSort algorithm along with a Time-Complexity control. It works fine with smaller N but once i get closer to larger N the StackOverflow is inevitable. Im thinking that having the pivot element as the last element might be what's causing this.
My first thought was to simply always use the middle element as the pivot element to avoid this but since the test-program throws an 'unsorted exception', it's not a valid solution.
Any ideas how i can work my way around this?
public class QuickSorter implements IntSorter{
int partition (int a[], int lo, int hi) {
int pivot = a[hi]; // pivot element
int i = (lo - 1);
for (int j = lo; j <= hi - 1; j++) {
if (a[j] < pivot) {
i++;
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
int temp = a[i+1];
a[i+1] = a[hi];
a[hi] = temp;
return (i + 1);
}
#Override
public void sort(int[] a) {
int lo = 0;
int hi = a.length-1;
if (lo < hi) {
int p = partition(a, lo, hi);
sort(a, lo, p - 1);
sort(a, p + 1, hi);
}
}
private void sort(int[] a, int lo, int hi) {
if (lo < hi) {
int p = partition(a, lo, hi);
sort(a, lo, p - 1);
sort(a, p + 1, hi);
}
}
}
Testcode:
private static void testSort(IntSorter sorter, int firstN, boolean ordered) {
double t1 = 0;
int N = firstN/2;
while (t1 < 0.7 && N < 10000000) {
N *= 2;
int[] a = create(N, ordered);
t1 = timeit(sorter, a);
System.out.println("T("+N+")="+t1);
ArrayUtil.testOrdered(a);
}
int[] a = create(4*N, ordered);
double t4 = timeit(sorter, a);
ArrayUtil.testOrdered(a);
double t01 = t1 / (N * Math.log(N ));
double t04 = t4 / (4*N * Math.log(4*N));
System.out.println("T("+4*N+")="+t4+" growth per N log N: "+t04/t01);
if (t04/t01 > 1.25) {
System.out.println(sorter.getClass().getName()+".sort appears not to run in O(N log N) time");
System.exit(1);
}
}
public static void testOrdered(int[] a) {
int N = a.length;
for (int i = 1; i < N; i++) {
if (a[i] < a[i-1]) {
throw new SortingException("Not sorted, a["+(i-1)+"] > a["+i+"]");
}
}
}
As Thomas comments, using the middle element as the pivot should work fine. It's a common choice, actually, because it works well with input arrays that happen to be already fully or partially sorted.
As for avoiding stack overflow, a common approach is to only recurse on the shorter part after a partitioning step - this ensures at least a halving of the array being processed at each level, so e.g. a 1,000,000 element array will have a maximum call depth of roughly 20 ( log2(1,000,000) ).
So, instead of
private void sort(int[] a, int lo, int hi) {
if (lo < hi) {
int p = partition(a, lo, hi);
sort(a, lo, p - 1);
sort(a, p + 1, hi);
}
}
You do
private void sort(int[] a, int lo, int hi) {
while (lo < hi) {
int p = partition(a, lo, hi);
// recurse on smaller part, loop on larger part
if (((p - 1) - lo) > (hi - (p + 1))) {
sort(a, p + 1, hi);
hi = p - 1;
}
else {
sort(a, lo, p - 1);
lo = p + 1;
}
}
}
Shuffle the array before sorting with the method below seems to have fixed the issues i had aswell
public void shuffle(int[] a) {
int N = a.length;
Random randomGenerator = new Random();
for (int i = 0; i < N; i++) {
int r = i + randomGenerator.nextInt(N-i); // between i and N-1
int t = a[i]; a[i] = a[r]; a[r] = t;
}
}

Why my quick sort implements failed with stack overflow?

I need to write a algorithm to sort a collection, more than 10, 000, 000 elements.
So I write a forkjoin quick sort...
But when the input become bigger, the code collapses.
Firstly, I use the test cases is a random list, implements can handle.
Then, I just try some extremely cases, just as a ordered numbers. Code fails.
I check the code, but have no idea of why.
This is code below:
public class ForkJoinSort {
private static int THRESHOLD = 1000;
private static ForkJoinPool pool = new ForkJoinPool();
public static <T extends Comparable<T>> void quickSortFJ(List<T> rawList) {
pool.invoke(new QuickSort<>(rawList));
}
static class QuickSort<T extends Comparable<T>> extends RecursiveAction {
List<T> rawList;
int lo;
int hi;
QuickSort(List<T> rawList) {
this.rawList = rawList;
this.lo = 0;
this.hi = rawList.size() - 1;
}
QuickSort(List<T> rawList, int lo, int hi) {
this.rawList = rawList;
this.lo = lo;
this.hi = hi;
}
#Override
protected void compute() {
if (hi > lo && hi - lo >= THRESHOLD) {
int pivot = partition(rawList, lo, hi);
invokeAll(new QuickSort<>(rawList, lo, pivot - 1),
new QuickSort<>(rawList, pivot + 1, hi));
} else {
quickSort(rawList, lo, hi);
}
}
}
private static <T extends Comparable<T>> int partition(List<T> rawList, int lo, int hi) {
T key = rawList.get(hi);
int index = lo;
for (int i=lo; i<hi; i++) {
if (rawList.get(i).compareTo(key) > 0) {
swap(rawList, index, i);
index ++;
}
}
swap(rawList, index, hi);
return index;
}
private static <T extends Comparable<T>> void swap(List<T> rawList, int left, int right) {
if (left != right) {
T temp = rawList.get(left);
rawList.set(left, rawList.get(right));
rawList.set(right, temp);
}
}
public static <T extends Comparable<T>> void quickSort(List<T> rawList, int lo, int hi) {
if (lo < hi) {
int pivot = partition(rawList, lo, hi);
quickSort(rawList, lo, pivot-1);
quickSort(rawList, pivot+1, hi);
}
}
}
Test case failed:
List<Long> longTwoList = new ArrayList<>();
for (long i=0; i!=17000; i++) {
longTwoList.add(i);
}
ForkJoinSort.quickSortFJ(longTwoList);//failed
ForkJoinSort.quickSort(longTwoList, 0, longTwoList.size()-1);//falied
Quite confused with this problem. Thank you for replying.

What is wrong the the merge function in my mergesort code?

Sorry, beginner here.This is what I have right now:
public class MergeSort
{
public static void main(String[] args)
{
int[] arr = {3, 5, 2, 4, 1};
sort(arr, 0, arr.length - 1);
for(int i = 0; i < arr.length; i++)
{
System.out.print(arr[i] + " ");
}
}
private static void sort(int[] arr, int lo, int hi)
{
if(lo >= hi)
{
return;
}
int mid = (lo + hi)/2;
sort(arr, lo, mid);
sort(arr, mid + 1, hi);
int size = hi - lo + 1;
int[] temp = new int[size]; //new array to merge into
merge(arr, temp, lo, mid + 1, hi);
for(int i = 0; i < size; i++)
{
arr[i + lo] = temp[i];
}
}
private static void merge(int[] arr, int[] temp, int lower, int mid, int upper)
{
int tempIndex = 0;
int leftLo = lower;
int leftHi = mid - 1;
int rightLo = mid;
int rightHi = upper;
while(leftLo <= leftHi && rightLo <= rightHi)
{
if(arr[leftLo] < arr[rightLo])
{
temp[tempIndex] = arr[leftLo];
tempIndex++;
leftLo++;
}
else
{
temp[tempIndex] = arr[rightLo];
tempIndex++;
rightLo++;
}
}
}
}
I know it's the merge function that is not working, because right now it prints out only the smallest element and the rest as 0's. I think it has something to do with needing another while loop to copy the array, but I don't know how to write that, or even the purpose of it, as right now it seems that the array is being merged into the temp array in a correct order. Why is it only printing the first element correctly? Thanks.
In merge, you copy values as long as leftLo and rightLo both haven't reached their limit yet. Typically one of them reaches early. Then you need to copy the remaining values of the other one. You can copy the remaining elements by adding these two loops:
while (leftLo <= leftHi) {
temp[tempIndex] = arr[leftLo];
tempIndex++;
leftLo++;
}
while (rightLo <= rightHi) {
temp[tempIndex] = arr[rightLo];
tempIndex++;
rightLo++;
}
That is, the complete method becomes:
private static void merge(int[] arr, int[] temp, int lower, int mid, int upper) {
int tempIndex = 0;
int leftLo = lower;
int leftHi = mid - 1;
int rightLo = mid;
int rightHi = upper;
while (leftLo <= leftHi && rightLo <= rightHi) {
if (arr[leftLo] < arr[rightLo]) {
temp[tempIndex] = arr[leftLo];
tempIndex++;
leftLo++;
} else {
temp[tempIndex] = arr[rightLo];
tempIndex++;
rightLo++;
}
}
while (leftLo <= leftHi) {
temp[tempIndex] = arr[leftLo];
tempIndex++;
leftLo++;
}
while (rightLo <= rightHi) {
temp[tempIndex] = arr[rightLo];
tempIndex++;
rightLo++;
}
}

merge sort with insertion sort

I was implementing a merge sort in Algorithms in Java 4th edition.
My basic merge sort works, and I want to improve the algorithm by using insertion sort when the array size is less than 7.
I thought it is obvious an efficient improvement, but actually the original one is faster than the improved one for large data.
Here is my improved merge sort, CUTOFF = 7:
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
// Copy to aux[]
for (int i = lo; i <= hi; i++) {
aux[i] = a[i];
}
// Merge back to a[]
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (less(aux[i], aux[j])) a[k] = aux[i++];
else a[k] = aux[j++];
}
}
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
// #1 improvement
// Stop condition for this recursion.
// This time we add a CUTOFF, when the items in array
// is less than 7, we will use insertion sort.
if (hi <= lo + CUTOFF - 1) {
Insertion.sort(a, lo, hi);
return;
}
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
if (!less(a[mid+1], a[mid])) return;
merge(a, aux, lo, mid, hi);
}
public static void sort(Comparable[] a) {
Comparable[] aux = new Comparable[a.length];
sort(a, aux, 0, a.length - 1);
}
The insertion sort code:
public static void sort(Comparable[] a, int lo, int hi) {
for (int i = lo; i <= hi; i++) {
for (int j = i; j > 0 && less(a[j], a[j - 1]); j--) {
exch(a, j, j - 1);
}
}
}
I used a SortCompare.java to compare the execute time:
public class SortCompare {
public static double time(String alg, Comparable[] a) {
Stopwatch timer = new Stopwatch();
if (alg.equals("Insertion")) Insertion.sort(a);
if (alg.equals("Selection")) Selection.sort(a);
if (alg.equals("Shell")) Shell.sort(a);
if (alg.equals("Merge")) Merge.sort(a);
if (alg.equals("MergeWithImprovements")) MergeWithImprovements.sort(a);
//if (alg.equals("Quick")) Quick.sort(a);
//if (alg.equals("Heap")) Heap.sort(a);
if (alg.equals("InsertionWithSentinel")) InsertionWithSentinel.sort(a);
return timer.elapsedTime();
}
public static double timeRandomInput(String alg, int N, int T) {
// Use alg to sort T random arrays of length N.
double total = 0.0;
Double[] a = new Double[N];
for (int t = 0; t < T; t++) {
for (int i = 0; i < N; i++) {
a[i] = StdRandom.uniform();
}
total += time(alg, a);
}
return total;
}
public static void main(String[] args) {
String alg1 = args[0];
String alg2 = args[1];
int N = Integer.parseInt(args[2]);
int T = Integer.parseInt(args[3]);
double t1 = timeRandomInput(alg1, N, T); // Total for alg1
double t2 = timeRandomInput(alg2, N, T);
StdOut.printf("For %d random Doubles\n %s is", N, alg1);
StdOut.printf(" %.1f times faster than %s\n", t2/t1, alg2);
}
}
I generated 100 arrays with 10000 elements each. The original merge sort is 30 times faster than the improved one!
You insertion sort function is definitely wrong. Note the j > 0 end condition. You pass in [lo..hi] but your code can iterate j all the way down to 1. I think you want something like:
public static void sort(Comparable[] a, int lo, int hi) {
for (int i = lo + 1; i <= hi; i++) {
for (int j = i; j > lo && less(a[j], a[j - 1]); j--) {
exch(a, j, j - 1);
}
}
}

Confused with Quicksort algorithm

I am implementing a quicksort algorithm and have succesfully partitioned the input array around a pivot. The problem is, I am confused in how to recursively sort the 1st part and 2nd part of the array (i.e specifying the range) using the same input array.
Below is my implementation
class QuickSort {
int i;
int l = 0;
public void quicksort(int A[], int n) {
if (n == 1) {
return;
} else {
partition(A, 0, n);
//----Confused as from this point
quicksort(A, A[i]);
//Recursively sort both parts of the array
}
}
public int partition(int A[], int l, int r) {
int p = A[l];//Choose pivot
i = l + 1;
//Partition around A through P
for (int j = i; j < r; j++) {
if (A[j] < p) {
swap(A, i, j);
++i;
}
}
swap(A, l, i - 1 );
return i;
}
public void swap(int A[], int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public void display(int A[]){
for (int i = 0; i < A.length; i ++){
System.out.print(A[i] + " ");
}
}
}
class QuickSortApp{
public static void main(String args[]){
QuickSort quick = new QuickSort();
int A[] = {6,2,7,8,4,3,5};
quick.quicksort(A, A.length);
quick.display(A);
}
}
Please, I would also appreciate being corrected on any other inefficencies in my algorithm. Thanks
Change your quicksort() signature to quicksort(int[] A, int begin, int end)
Since, you actually did the sorting inside partition(). What I would do is this:
if (end-begin <= 1) {
return;
} else {
int pivot = partition(A, begin, end);
quicksort(A, begin, pivot);
quicksort(A, pivot, end);
}
Create a wrapper for the quicksort call with the signature you have which calls another one like quicksort(A, i, j) and your call from the wrapper will be quicksort(A, 0, n).

Categories