The main idea of this project is to parallel bubble sort. my approach to this project is,to create one big array and then divide it in to parts ( 4 or 5) based on the number of threads. for instance if the size of the array is 10, i divide it into 2 sub arrays, 0-4 and 5-9, then one thread has to scan the big arrays, and if the value is between 0-4 , assign the the the first sub arrays, if not assign to the next sub-array. then apple the bubble sort algorithm to all sub-arrays simultaneously. finally, all the sub arrays should be added to a thread safe queue.
for now i have three class, the main class where i created the array, the U tiles class for shuffling the array, find the min and max of the array and the bubble sort class that has a bubble sorting algorithms.
my challenge for now is, how divide the big array into small sub-arrays and fill the sub-array with values.
i will appreciate all suggestions and helps. under is my classes.
package com.company;
import javax.xml.transform.sax.SAXSource;
import java.util.Random;
public class Main {
public static void main(String[] args) {
// filling the array with integer values
int[] anArray = Utils.fillArray((int) 10);
Utils.shuffleArray(anArray);
// find the min and max of the array
System.out.println("************************");
BubbleSort sort = new BubbleSort(anArray);
profiler.start();
sort.sortMethod();
// Utils.printArray(anArray);
Utils.findMinMax(anArray);
}
}
package com.company;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class Utils {
private static volatile int max;
private static volatile int min;
private static int[][] arrays;
public Utils(int[][] arrays,int[] array) {
max = array[0];
min = array[0];
}
// taken from the kings class
// source: http://stackoverflow.com/questions/1519736/random-shuffling-of-an-array
// Implementing Fisher�Yates shuffle
public static void shuffleArray(int[] ar) {
// If running on Java 6 or older, use `new Random()` on RHS here
ThreadLocalRandom rnd = ThreadLocalRandom.current();
for (int i = ar.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
public static void printArray(int[] anArray) {
System.out.print("Array: ");
for (int i=0; i< anArray.length; i++){
System.out.print(anArray[i]+" ");
}
System.out.println();
}
public static int[] fillArray(int amount) {
int[] result = new int[amount];
for (int i=0; i<amount; i++){
result[i] = i;
}
return result;
}
public static void findMinMax(int[] array) {
int i = 0;
for (; i < (array.length) / 2; i++) {
int num1 = array[1 * 2];
int num2 = array[i * 2 + 1];
if (num1 >= num2) {
if (num1 > max)
max = num1;
if (num2 < min)
min = num2;
} else {
if (num2 > max) {
max = num2;
if (num1 < min)
min = num1;
}
}
}
if (i * 2 < array.length) {
int num = array[i * 2];
if (num > max)
max = num;
if (num < min)
min = num;
}
System.out.println("min is: " + min);
System.out.println("max is : " + max);
}
}
public static int getMax() {
return max;
}
public static int getMin() {
return min;
}
public static void print(int[] anArray, int i) {
}
}
I think you should try merge sort, using Fork/Join.
Like here:
import java.util.Random;
import java.util.concurrent.*;
/**
* Example of Merge Sort using Fork/Join framework.
*
* #author L.Gobinath
*/
public class ForkJoinArraySort {
// From Java 7 '_' can be used to separate digits.
public static final int ARRAY_SIZE = 10_000_000;
public static void main(String[] args) {
// Create a pool of threads
ForkJoinPool pool = new ForkJoinPool();
int[] array = createArray(ARRAY_SIZE);
long startTime;
long endTime;
MergeSort mergeSort = new MergeSort(array, 0, array.length - 1);
startTime = System.currentTimeMillis();
pool.invoke(mergeSort); // Start execution and wait for result/return
endTime = System.currentTimeMillis();
System.out.println("Time taken: " + (endTime - startTime) + " millis");
}
/**
* Create an array with random numbers.
* #param size Size of the array.
* #return An array with the given size.
*/
private static int[] createArray(final int size) {
int[] array = new int[size];
Random rand = new Random();
for (int i = 0; i < size; i++) {
array[i] = rand.nextInt(1000);
}
return array;
}
}
/**
* Extends RecursiveAction.
* Notice that the compute method does not return anything.
*/
class MergeSort extends RecursiveAction {
private int array[];
private int left;
private int right;
public MergeSort(int[] array, int left, int right) {
this.array = array;
this.left = left;
this.right = right;
}
/**
* Inherited from RecursiveAction.
* Compare it with the run method of a Thread.
*/
#Override
protected void compute() {
if (left < right) {
int mid = (left + right) / 2;
RecursiveAction leftSort = new MergeSort(array, left, mid);
RecursiveAction rightSort = new MergeSort(array, mid + 1, right);
invokeAll(leftSort, rightSort);
merge(left, mid, right);
}
}
/**
* Merge two parts of an array in sorted manner.
* #param left Left side of left array.
* #param mid Middle of separation.
* #param right Right side of right array.
*/
private void merge(int left, int mid, int right) {
int temp [] = new int[right - left + 1];
int x = left;
int y = mid + 1;
int z = 0;
//There some kind of sort at the leaf
//You can use your BubbleSort class
//***************************************************************
while (x <= mid && y <= right) {
if (array[x] <= array[y]) {
temp[z] = array[x];
z++;
x++;
} else {
temp[z] = array[y];
z++;
y++;
}
}
//***************************************************************
while (y <= right) {
temp[z++] = array[y++];
}
while (x <= mid) {
temp[z++] = array[x++];
}
for (z = 0; z < temp.length; z++) {
array[left + z] = temp[z];
}
}
}
(I had my own algorithm, where I used merge sorting, and in the leaf nodes sorting with a bubble sort when I studied algorithmization. But it was a long time ago, I lost it, sorry.)
P.S. I think it will be superfluous to recall that Array.sort will still be faster than the personal implementation of bubble sorting.
Related
I have a program that generates an array based on the user input (the array can be descending, ascending and two types of random) and then it calculates the maximum subarray sum using bruteforce, divide and conquer, and dynamic programming. It seems to work fine and dandy up to values of 65535. After that, each sum is different, which shouldn't happen. 35535 is 2 to the power of 16 minus 1, so I was wondering if I'm hitting some limit. When I print the array it seems to print fine, so I don't think that the problem is that the array isn't generating properly.
This is the main class:
public class MainClass {
public static void main(String[] args) {
int n = Integer.parseInt(args[1]);
int[] maxsubarray1;
maxsubarray1 = new Generator(n,args[3]).getArray();
int[] maxsubarray2 = Arrays.copyOf(maxsubarray1,maxsubarray1.length);
int[] maxsubarray3 = Arrays.copyOf(maxsubarray1,maxsubarray1.length);
System.out.println(Arrays.toString(maxsubarray1));
solver solver = new solver();
int solution;
//if (args[5].equalsIgnoreCase("bruteforce")){
long startTime = System.currentTimeMillis();
solution = solver.bruteforce(maxsubarray1, n);
System.out.println("__________BRUTE FORCE________\nThe sum of the array is "+solution);
long endTime = System.currentTimeMillis() - startTime;
System.out.println(endTime);
//}
//if (args[5].equalsIgnoreCase("divideconquer")){
long startTime2 = System.currentTimeMillis();
int solutiondivideconquer = solver.divideconquer(maxsubarray2, 0, n);
System.out.println("__________DIVIDE AND CONQUERE________\nThe sum of the array is "+ solutiondivideconquer);
long endTime2 = System.currentTimeMillis() - startTime2;
System.out.println(endTime2);
//}
//if (args[5].equalsIgnoreCase("dynprog")){
long startTime3 = System.currentTimeMillis();
int solutiondynprog = solver.dynprog(maxsubarray3, n);
System.out.println("__________DYNAMIC PROGRAMMING________\nThe sum of the array is "+ solutiondynprog);
long endTime3 = System.currentTimeMillis() - startTime3;
System.out.println(endTime3);
//}
}
}
This is the generator code:
import java.util.concurrent.ThreadLocalRandom;
public class Generator {
int size;
String type;
int[] generatedArray;
public Generator(int mysize, String mytype){
size = mysize;
type = mytype;
generatedArray = new int[size];
}
public void ascending(){
for(int i = 0; i < this.size; i++)
generatedArray[i] = i+1;
}
public void descending(){
for(int i = this.size -1; i >= 0; i--)
generatedArray[i] = i+1;
}
public void random(){
for(int i = 0; i <= this.size -1; i++)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10*this.size, 10*this.size);
}
public void randominter(){
for(int i = 0; i <= this.size -1; i++)
if (i % 2 == 0)
generatedArray[i] = ThreadLocalRandom.current().nextInt(1, 10*this.size);
else if (i % 2 == 1)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10*this.size, -1);
}
public int[] getArray(){
if (type.equalsIgnoreCase("descending")){
this.descending();
return generatedArray;
}
if (type.equalsIgnoreCase("ascending")){
this.ascending();
return generatedArray;
}
if (type.equalsIgnoreCase("random")){
this.random();
return generatedArray;
}
if (type.equalsIgnoreCase("randominter")){
this.randominter();
return generatedArray;
}
return null;
}
}
And this is the solver class:
public class solver {
//brute force algorithm with complexity O(n^2)
int bruteforce(int array[], int n){
int max = Integer.MIN_VALUE;
//We go throght all the elements of the list and we try all the
//posible combinations with all the other elements
for (int i = 0; i < n; i++){
int sum = 0;
for (int j = i; j < n ; j++){
//we add the an element in the sum
sum += array[j];
//we check if the sum with the new element is greater that the value we had before
if(sum > max){
//if it's greater, it becomes the new value
max = sum;
}
}
}
//we return the maximum value we have found
return max;
}
//to implement the divide and conquer algorithm we have to take into account the
// maximum subarray can have elements in the right subarray and in the left subarray
int maxCrossingSum(int array[], int l, int m, int h){
int sum = 0;
int left_sum = Integer.MIN_VALUE;
//Has the elements on the left part of the arrray
for ( int i = (int)m; i >= l; i--){
sum = sum + array[i];
if( sum > left_sum ){
left_sum = sum;
}
}
sum = 0;
int right_sum = 0;
//Has the elements in the right part of the array
for ( int j = (int)m+1; j <= h; j++){
sum = sum + array [j];
if (sum > right_sum){
right_sum = sum;
}
}
//returns the sun of the elements on the left and the right of the array
return left_sum + right_sum;
}
//returns the sum of the maximum subarray
int maxSubarraySum(int array[], int l, int h){
if(l == h)
return array[1];
int m = (l + h)/2;
//checks which is the maximum between left and right
int maxBetweenLeftRight = max(maxSubarraySum(array, l, m), maxSubarraySum(array, m+1,h));
int crossing = maxCrossingSum(array, l, m,h-1);
//retrns the maximum between one of the sides and the crossing sum
return max(maxBetweenLeftRight, crossing);
}
//divide and conquere algorithm with complexity O(nlogn)
//only made to make it more understandable from the main
//can call maxSubarraySum and it would be the same
int divideconquer (int array[], int l, int h){
return maxSubarraySum(array, l, h);
}
//dynamic programming algorithm with complexity O(n)
int dynprog(int array[], int n){
int a = array[0];
int b = array[0];
//for all the elements checks if the sum was better until the
//step before or adding the element
for (int i = 1 ; i < n; i++){
a= max (a+ array[i], array[i]);
b= max(b, a);
}
return b;
}
}
Changing all the ints to longs didn't help either.
I've copied your code, changed all ints to longs and it's working fine. Also changed n = Integer.parseInt(args[0]) instead of n = Integer.parseInt(args[1]).
Then I called my program like program_name 1000 random.
I've checked in excel, and only bruteforce was wrong. I've changed Integer.MIN_VALUE to Long.MIN_VALUE. And int sum to long sum.
Main.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class Main {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long[] maxsubarray1;
maxsubarray1 = new Generator(n, args[1]).getArray();
long[] maxsubarray2 = Arrays.copyOf(maxsubarray1, maxsubarray1.length);
long[] maxsubarray3 = Arrays.copyOf(maxsubarray1, maxsubarray1.length);
System.out.println(Arrays.toString(maxsubarray1));
solver solver = new solver();
long solution;
//if (args[5].equalsIgnoreCase("bruteforce")){
long startTime = System.currentTimeMillis();
solution = solver.bruteforce(maxsubarray1, n);
System.out.println("__________BRUTE FORCE________\nThe sum of the array is " + solution);
long endTime = System.currentTimeMillis() - startTime;
System.out.println(endTime);
//}
//if (args[5].equalsIgnoreCase("divideconquer")){
long startTime2 = System.currentTimeMillis();
long solutiondivideconquer = solver.divideconquer(maxsubarray2, 0, n);
System.out.println("__________DIVIDE AND CONQUERE________\nThe sum of the array is " + solutiondivideconquer);
long endTime2 = System.currentTimeMillis() - startTime2;
System.out.println(endTime2);
//}
//if (args[5].equalsIgnoreCase("dynprog")){
long startTime3 = System.currentTimeMillis();
long solutiondynprog = solver.dynprog(maxsubarray3, n);
System.out.println("__________DYNAMIC PROGRAMMING________\nThe sum of the array is " + solutiondynprog);
long endTime3 = System.currentTimeMillis() - startTime3;
System.out.println(endTime3);
//}
}
}
solver.java
public class solver {
//brute force algorithm with complexity O(n^2)
long bruteforce(long array[], int n){
long max = Long.MIN_VALUE;
//We go throght all the elements of the list and we try all the
//posible combinations with all the other elements
for (int i = 0; i < n; i++){
long sum = 0;
for (int j = i; j < n ; j++){
//we add the an element in the sum
sum += array[j];
//we check if the sum with the new element is greater that the value we had before
if(sum > max){
//if it's greater, it becomes the new value
max = sum;
}
}
}
//we return the maximum value we have found
return max;
}
//to implement the divide and conquer algorithm we have to take into account the
// maximum subarray can have elements in the right subarray and in the left subarray
long maxCrossingSum(long array[], long l, long m, long h){
long sum = 0;
long left_sum = Integer.MIN_VALUE;
//Has the elements on the left part of the arrray
for ( int i = (int)m; i >= l; i--){
sum = sum + array[i];
if( sum > left_sum ){
left_sum = sum;
}
}
sum = 0;
long right_sum = 0;
//Has the elements in the right part of the array
for ( int j = (int)m+1; j <= h; j++){
sum = sum + array [j];
if (sum > right_sum){
right_sum = sum;
}
}
//returns the sun of the elements on the left and the right of the array
return left_sum + right_sum;
}
//returns the sum of the maximum subarray
long maxSubarraySum(long array[], long l, long h){
if(l == h)
return array[1];
long m = (l + h)/2;
//checks which is the maximum between left and right
long maxBetweenLeftRight = max(maxSubarraySum(array, l, m), maxSubarraySum(array, m+1,h));
long crossing = maxCrossingSum(array, l, m,h-1);
//retrns the maximum between one of the sides and the crossing sum
return max(maxBetweenLeftRight, crossing);
}
//divide and conquere algorithm with complexity O(nlogn)
//only made to make it more understandable from the main
//can call maxSubarraySum and it would be the same
long divideconquer (long array[], int l, int h){
return maxSubarraySum(array, l, h);
}
//dynamic programming algorithm with complexity O(n)
long dynprog(long array[], int n){
long a = array[0];
long b = array[0];
//for all the elements checks if the sum was better until the
//step before or adding the element
for (int i = 1 ; i < n; i++){
a= max (a+ array[i], array[i]);
b= max(b, a);
}
return b;
}
private long max(long a, long b) {
if (a > b ) return a;
else return b;
}
}
Generator.java
import java.util.concurrent.ThreadLocalRandom;
public class Generator {
int size;
String type;
long[] generatedArray;
public Generator(int mysize, String mytype) {
size = mysize;
type = mytype;
generatedArray = new long[size];
}
public void ascending() {
for (int i = 0; i < this.size; i++)
generatedArray[i] = i + 1;
}
public void descending() {
for (int i = this.size - 1; i >= 0; i--)
generatedArray[i] = i + 1;
}
public void random() {
for (int i = 0; i <= this.size - 1; i++)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10 * this.size, 10 * this.size);
}
public void randominter() {
for (int i = 0; i <= this.size - 1; i++)
if (i % 2 == 0)
generatedArray[i] = ThreadLocalRandom.current().nextInt(1, 10 * this.size);
else if (i % 2 == 1)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10 * this.size, -1);
}
public long[] getArray() {
if (type.equalsIgnoreCase("descending")) {
this.descending();
return generatedArray;
}
if (type.equalsIgnoreCase("ascending")) {
this.ascending();
return generatedArray;
}
if (type.equalsIgnoreCase("random")) {
this.random();
return generatedArray;
}
if (type.equalsIgnoreCase("randominter")) {
this.randominter();
return generatedArray;
}
return null;
}
}
I was wrong, it CAN BE an overflow error if Array[i] = i + 1, since the sum is length * (min + max) / 2 > Integer.MAX_VALUE
I am facing one problem in multithreaded merge sort algorithm in java.
I should modify the code into 3,4,5,6,7,8 threaded merge sorting by dividing original array into subArrays. Currently it has 2 subArrays.
How can I split original array into 3, 4 ,5,6,7,8 subArrays to achive my goal?
Moreover, I should write some more methods because mergeSort method calls lefthalf and righthalf methods at the moment. So for 3,4,5,6,7,8 threads I should write additional methods.
How can i handle this?
two_threaded_merge_sort.java
public class two_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[9000000];
for (int i=0; i<original.length; i++) {
original[i] = rand.nextInt(1000);
}
long startTime = System.currentTimeMillis();
int[] subArr1 = new int[original.length/2];
int[] subArr2 = new int[original.length - original.length/2];
System.arraycopy(original, 0, subArr1, 0, original.length/2);
System.arraycopy(original, original.length/2, subArr2, 0, original.length - original.length/2);
Worker runner1 = new Worker(subArr1);
Worker runner2 = new Worker(subArr2);
runner1.start();
runner2.start();
runner1.join();
runner2.join();
finalMerge (runner1.getInternal(), runner2.getInternal());
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println("2-thread MergeSort takes: " + (float)elapsedTime/1000 + " seconds");
}
}
Worker.java
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);
}
}
Thanks very much!
There needs to be a sort function that separates the array into k parts, then create k threads to sort each part, using either top down or bottom up approach, (bottom up would slightly faster), and wait for all threads to complete.
At this point there are k sorted parts. These could be merged all at once using a k-way merge (complicated), or merged a pair of parts at a time (2 way merge), perhaps using multiple threads, but at this point the process is probably memory bandwidth limited, so multi-threading may not help much.
When separating the array into k parts, something like this can be used to keep the sizes similar:
int r = n % k;
int s = n / k;
int t;
for each part{
t = r ? 1 : 0;
r -= t;
size = s + t;
}
or
int r = n % k;
int s = n / k + 1;
while(r--){
next part size = s; // n / k + 1
}
s -= 1;
while not done{
next part size = s; // n / k
}
From my point of view, your hard work is done. now you must parametrize the algorithm with number of threads.
Your algorithm has two parts
split the work.
merge the k-parts.
And two components:
Main algorithm
Workers.
About the threads
In my opinion, Start/join method aren't useful in this case, because last merging can't start until all threads are finish. I prefer '2 way merge' (#rcgldr answer) and a thread pool (ExecutorService).
You must be careful with threads synchronization and shared memory.
To sum up, I propose a little different solution:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class MultithreadedMergeSort {
private int[] array;
private int numThreads;
private List<int[]> sortedFragments;
private MultithreadedMergeSort(int numThreads, int[] array) {
this.numThreads = numThreads;
this.array = array;
}
// Basic algorithm: it sort recursively a fragment
private static void recursiveMergeSort(int[] array, int begin, int end) {
if (end - begin > 1) {
int middle = (begin + end) / 2;
recursiveMergeSort(array, begin, middle);
recursiveMergeSort(array, middle, end);
merge(array, begin, middle, end);
}
}
// Basic algorithm: it merges two consecutives sorted fragments
private static void merge(int[] array, int begin, int middle, int end) {
int[] firstPart = Arrays.copyOfRange(array, begin, middle);
int i = 0;
int j = middle;
int k = begin;
while (i < firstPart.length && j < end) {
if (firstPart[i] <= array[j]) {
array[k++] = firstPart[i++];
} else {
array[k++] = array[j++];
}
}
if (i < firstPart.length) {
System.arraycopy(firstPart, i, array, k, firstPart.length - i);
}
}
public static void sort(int[] array, int numThreads) throws InterruptedException {
if (array != null && array.length > 1) {
if (numThreads > 1) {
new MultithreadedMergeSort(numThreads, array).mergeSort();
} else {
recursiveMergeSort(array, 0, array.length);
}
}
}
private synchronized void mergeSort() throws InterruptedException {
// A thread pool
ExecutorService executors = Executors.newFixedThreadPool(numThreads);
this.sortedFragments = new ArrayList<>(numThreads - 1);
int begin = 0;
int end = 0;
// it split the work
for (int i = 1; i <= (numThreads - 1); i++) {
begin = end;
end = (array.length * i) / (numThreads - 1);
// sending the work to worker
executors.execute(new MergeSortWorker(begin, end));
}
// this is waiting until work is done
wait();
// shutdown the thread pool.
executors.shutdown();
}
private synchronized int[] notifyFragmentSorted(int begin, int end) {
if (begin > 0 || end < array.length) {
// the array is not completely sorted
Iterator<int[]> it = sortedFragments.iterator();
// searching a previous or next fragment
while (it.hasNext()) {
int[] f = it.next();
if (f[1] == begin || f[0] == end) {
// It found a previous/next fragment
it.remove();
return f;
}
}
sortedFragments.add(new int[]{begin, end});
} else {
// the array is sorted
notify();
}
return null;
}
private class MergeSortWorker implements Runnable {
int begin;
int end;
public MergeSortWorker(int begin, int end) {
this.begin = begin;
this.end = end;
}
#Override
public void run() {
// Sort a fragment
recursiveMergeSort(array, begin, end);
// notify the sorted fragment
int[] nearFragment = notifyFragmentSorted(begin, end);
while (nearFragment != null) {
// there's more work: merge two consecutives sorted fragments, (begin, end) and nearFragment
int middle;
if (nearFragment[0] < begin) {
middle = begin;
begin = nearFragment[0];
} else {
middle = nearFragment[0];
end = nearFragment[1];
}
merge(array, begin, middle, end);
nearFragment = notifyFragmentSorted(begin, end);
}
}
}
public static void main(String[] args) throws InterruptedException {
int numThreads = 5;
Random rand = new Random();
int[] original = new int[9000000];
for (int i = 0; i < original.length; i++) {
original[i] = rand.nextInt(1000);
}
long startTime = System.currentTimeMillis();
MultithreadedMergeSort.sort(original, numThreads);
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
// warning: Take care with microbenchmarks
System.out.println(numThreads + "-thread MergeSort takes: " + (float) elapsedTime / 1000 + " seconds");
}
}
I'm trying to learn heapsort. I follow the pseudocode instruction, however, my program doesn't work properly. I have already debugging for an hour now and couldn't find the bug. There are a couple of bug: first, the arraylist doesn't sort properly; and second, the arraylist seem to be sorting from max -> min, even though it is suppose to be from min -> max.
Sorry for beginner question.
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int n;
Scanner input = new Scanner(System.in);
ArrayList<Integer> intList = new ArrayList<Integer>();
Random rand = new Random();
int minMax = 7000;
System.out.print("Input a positive integer: ");
n = input.nextInt();
for (int i = 0; i < n; i++) {
intList.add(rand.nextInt(minMax * 2) - minMax);
}
System.out.println(intList);
Heapsort(intList);
System.out.println(intList);
}
// Heapsort
public static void Heapsort(ArrayList<Integer> num) {
build_MaxHeap(num);
int n = num.size() - 1;
for (int i = n; i > 0; i--) {
swap(num, 0, i);
n = n - 1;
max_heapify(num, 0);
}
}
// build max heap from arraylist
public static void build_MaxHeap(ArrayList<Integer> num) {
for (int i = (num.size() - 1) / 2; i >= 0; i--)
max_heapify(num, i);
}
// max heapify
public static void max_heapify(ArrayList<Integer> num, int i) {
int left = 2 * i;
int right = 2 * i + 1;
int max = i;
int n = num.size() - 1;
if (left <= n && num.get(left) > num.get(i))
max = left;
if (right <= n && num.get(right) > num.get(max))
max = right;
if (max != i) {
swap(num, i, max);
max_heapify(num, max);
}
}
// swap 2 numbers in arraylist
public static void swap(ArrayList<Integer> num, int i, int j) {
int temp = num.get(i);
num.set(i, num.get(j));
num.set(j, temp);
}
}
I am wondering why my code keeps having this "time limit exceed" on the uva-online judge page (http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2511), it is supposed to execute in 1 second but I don't know which input they use (my code works and do exactly what it supposed).. I am wondering that maybe the while loop of the testCases have something to do, because when I remove it it says wrong answer.. this is my code:
public class Main {
private static final int TAM = 10000; // TAM equals to the posible numbers of houses
private static int[] auxHouses;
private static int nHouses[];
private static int testCases;
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
nHouses = new int[TAM];
// First we read the input
// Read the variable of testCases
testCases = scanner.nextInt();
while (testCases > 0) {
float sol = binarySearch(testCases);
System.out.println(sol);
testCases--;
}
}
public static float binarySearch(int tC) {
int routers = 0, houses = 0;
int pivot = 0;
int hi = 0;
// While for the testCases
routers = scanner.nextInt();
houses = scanner.nextInt();
// Read the numbers of the houses
for (int i = 0; i < houses; i++) {
nHouses[i] = scanner.nextInt();
}
if (routers >= houses) {
return 0;
}
// First we sort the array
sortHouses(nHouses, houses);
// Prepare the variables of the index
int lo = 0;
hi = 2 * (nHouses[houses - 1] - nHouses[0] + 1); // 2*(loc[h-1]-loc[0]+1);
// Now we execute the binary search algorithm
while (hi > lo) {
pivot = (lo + hi) / 2;
int start = nHouses[0];
int need = 1;
for (int i = 0; i < houses; i++) {
if (nHouses[i] > start + pivot) {
start = nHouses[i];
need++;
}
}
if (need > routers) {
lo = pivot + 1;
} else {
hi = pivot;
}
}
return (float) hi / 2;
}
public static void sortHouses(int[] nhouses, int length) {
// First we check if the are actually values on the array
if (nhouses.length == 0) {
return;
}
// Copy the array of int into an auxiliary variable and the numbers of
// int in the array
auxHouses = nhouses;
int lengthArray = length;
quickSort(0, lengthArray - 1);
}
public static void quickSort(int low, int high) {
// System.out.println("Array " + Arrays.toString(auxHouses));
int i = low, j = high;
// Get the pivot element from the middle of the list
int pivot = auxHouses[low + (high - low) / 2];
// Divide into two lists
while (i <= j) {
// If the current value from the left list is smaller then the pivot
// element then get the next element from the left list
while (auxHouses[i] < pivot) {
i++;
}
// If the current value from the right list is larger then the pivot
// element then get the next element from the right list
while (auxHouses[j] > pivot) {
j--;
}
// If we have found a values in the left list which is larger then
// the pivot element and if we have found a value in the right list
// which is smaller then the pivot element then we exchange the
// values.
// As we are done we can increase i and j
if (i <= j) {
exchange(i, j);
i++;
j--;
}
}
// Recursion
if (low < j)
quickSort(low, j);
if (i < high)
quickSort(i, high);
}
private static void exchange(int i, int j) {
int temp = auxHouses[i];
auxHouses[i] = auxHouses[j];
auxHouses[j] = temp;
}
}
I have it with the quicksort implemented, but if you use Arrays.sort(..) method instead it says the same thing..TLE, what could be doing wrong?
I'm trying to compare the execution of the java implementation of QuickSort and its hybrid version (using InsertionSort for those partitions which are smaller than an integer k). I wrote a test class to analyze the behaviour of the algorithms for some values ok k (1 <= k <= 25). For each value of k the class compares for different sizes of the input array the two algorithms.
I can't run the program for some values of the size of the array, for instance for values greater than 4000. The execution reach some different values and then freeze, after a while it will finish but I have no output of the computation. (I'm using eclipse).
What could be the problem? I wish to perform the comparation of the two algoritms for an array size from 10 to 10000 (at least). The code is listed below:
public class Main {
private static final int MAX_K = 25;
private static final int MAX_SIZE = 4500;
private static final int ADD_SIZE = 100;
private static int size = 10;
private static QuickSort qSort;
private static HybridSort hSort;
private static void initArray(int[] A) {
Random rand = new Random();
for (int i = 0; i < A.length; i++) {
// A[i] = (int)(Math.random()*100000);
A[i] = rand.nextInt();
}
}
private static int[] A = new int[10];
private static int[] B = new int[10];
public static void main(String[] args) {
try {
FileWriter fstream = new FileWriter("out.txt");
BufferedWriter out = new BufferedWriter(fstream);
out.write("Init file");
qSort = new QuickSort();
hSort = new HybridSort();
/************************************************/
/* Comparison */
/************************************************/
for (int i = 1; i <= MAX_K; i++) {
hSort.setK(i);
int p = 0;
for (int j = size; j <= MAX_SIZE; j = j + ADD_SIZE) {
A = new int[j];
B = new int[j];
initArray(A);
initArray(B);
long sTime = System.nanoTime();
qSort.quickSort(A, 0, A.length - 1);
long qDuration = System.nanoTime() - sTime;
sTime = System.nanoTime();
hSort.hybridSort(B, 0, B.length - 1);
long hDuration = System.nanoTime() - sTime;
out.append(/* "\nA: " +printArray(A)+ */"K: " + i + " A["
+ j + "]\tQ = " + qDuration + " H = " + hDuration
+ "\n");
String h = Long.toString(hDuration);
String q = Long.toString(qDuration);
if (h.length() < q.length()) {
p++;
out.append("\t#OUTPERM for K: "
+ i
+ "\t\t"
+ hDuration
+ "\t\t < \t\t "
+ qDuration
+ "\t\t\t\t| A[]\t\t"
+ A.length
+ ((q.length() - h.length()) == 2 ? "\t Magn. 2"
: "") + "\n");
}
}
if (p > 0)
out.append("#P= " + p + " for K= " + i + "\n\n");
}
out.append("Close file");
out.close();
} catch (IOException e) {
}
}
}
The algorithm classes:
public class QuickSort {
public void quickSort(int[] A, int left, int right){
if (left < right) {
int m = Partition(A, left, right);
quickSort(A, left, m-1);
quickSort(A, m, right);
}
}
private int Partition(int[] A, int left, int right){
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ( (A[j] > pivot)) {
j--;
}
while ((A[i] < pivot)) {
i++;
}
if (i < j){
int swap = A[j];
A[j] = A[i];
A[i] = swap;
}else{
return i;
}
}
}
}
public class HybridSort {
int k;
int m;
InsertionSort iSort;
public HybridSort() {
k = 3;
iSort = new InsertionSort();
}
public void hybridSort(int[] A, int left, int right) {
if (left < right) {
if ((right - left) < k) {
iSort.sort(A,left,right);
} else {
m = Partition(A, left, right);
hybridSort(A, left, m - 1);
hybridSort(A, m, right);
}
}
}
private int Partition(int[] A, int left, int right) {
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ((A[j] > pivot) && (j >= 0)) {
j--;
}
while ((A[i] < pivot) && (i < A.length)) {
i++;
}
if (i < j) {
int swap = A[j];
A[j] = A[i];
A[i] = swap;
} else {
return i;
}
}
}
public void setK(int k) {
this.k = k;
}
}
Your implementation of Partition is not correct. Consider the small test below (I made Partition static for my convenience).
Both while loops won't be executed, because A[i] == A[j] == pivot. Moreover, i<j, so the two elements will be swapped, resulting in exactly the same array. Therefore, the outer while loop becomes infinite.
The same problem occurs for any array for which the first and last element are the same.
public class Test {
public static void main(String[] args) {
int[] A = {1, 1};
Partition(A, 0, 1);
}
private static int Partition(int[] A, int left, int right){
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ( (A[j] > pivot)) {
j--;
}
while ((A[i] < pivot)) {
i++;
}
if (i < j){
int swap = A[j];
A[j] = A[i];
A[i] = swap;
}else{
return i;
}
}
}
}
Have you tried increasing memory settings for your code to run in eclipse.
You may find this Setting memory of Java programs that runs from Eclipse helpful.
Some tips / possible solution?:
I haven't read your implementation of QuickSort or HybridSort but I am assuming they are correct.
If you are comparing the performance of two algorithms you should most definitely compare their performance to indentical inputs. Currently you are generating two random arrys (albeit of the same size). This isn't necessarily going to be an accurate test as I can easily find a test case where one algorithm will outperform the other if the random generator is out to troll you.
Your logic for comparing the two algorithms is a bit weird and incorrect according to me. Why do you compare the lengths of the strings of the times? according to your logic 1 is the same as 9 and 1,000,000,000 is the same as 9,999,999,999 which is clearly incorrect. One algorithm is almost 10 times faster than the other.
Moreover, one reason for no output might be the reason that you are only outputing when hybridsort is better than quicksort and not the other way around. I am sure there are other reasons as well but this could be one easily noticable reason (if your implementations are incorrect).
I do notice that you close your outputstream which is good as that is a very common reason why there is no output. You should however, close steams in the finally section of the try-catch as then they are guaranteed to close. You could be getting an IOException and in your case this would also not close the outputsteam and consequently lead to no ouput in your file.
Here is a sample structure that I would follow for doing any comparitive testing. It is easy to read and easy to debug with enough output for you to figure out which algorithm performs better. This is merely a suggestion.
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Random;
public class Tester {
private static int[] initArray(int size) {
Random rand = new Random();
int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = rand.nextInt();
}
return arr;
}
public static void main(String[] args) {
final int MAX_ITERATIONS = 25;
final int INITIAL_ARRAY_SIZE = 10;
final int MAX_ARRAY_SIZE = 4500;
final int ARRAY_SIZE_INCREMENT = 100;
long start;
int[] score = null;
PrintWriter out = null;
try {
out = new PrintWriter(new FileOutputStream("out.txt"));
for (int arraySize = INITIAL_ARRAY_SIZE; arraySize <= MAX_ARRAY_SIZE; arraySize += ARRAY_SIZE_INCREMENT) {
// score[0] is for quickSort and score[1] is for hybridSort
score = new int[2];
for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
int[] testArray = initArray(arraySize);
int[] testArrayCopy = new int[arraySize];
System.arraycopy(testArray, 0, testArrayCopy, 0, arraySize);
start = System.nanoTime();
// Do quicksort here using testArray
long qSortfinish = System.nanoTime() - start;
System.arraycopy(testArray, 0, testArrayCopy, 0, arraySize);
start = System.nanoTime();
// Do hybridsort here using testArrayCopy
long hybridSortfinish = System.nanoTime() - start;
// Keep score
if (qSortfinish < hybridSortfinish)
score[0]++;
else if (qSortfinish > hybridSortfinish) {
score[1]++;
} else {
score[0]++;
score[1]++;
}
}
out.println("Array Size: " + arraySize + " QuickSort: " + score[0] + " HybridSort: " + score[1]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (out != null)
out.close();
}
}
}