Basically I have this code that is using multiple threads to execute a merge sort algorithm I hope to scale this up to N given threads but currently I'm just trying to get four to work. Basically I create four different threads and pass each of them a subarray of the whole. After they've executed I have 4 different sorted sub-arrays that I then need to merge. Because I'm not really sure how to close threads and clear those resources entirely I am trying to reuse two of those threads to absorb a given array into their internal arrays and then re-run the thread with a boolean which tells the thread to merge the two halves rather than sort everything again. This seems to work the first time when I try with merger 0, and merger 1, but then when I try to do the same thing with 2 and three I get a concurrent modification exception. Now I'm not really sure what I'm doing wrong and if anyone has suggestions on how I could improve this code or reduce the number of array creations and copies that would be greatly appreciated.
import java.util.ArrayList;
import java.util.List;
public class RecursiveSimples {
public static void main(String[] args) throws InterruptedException {
List<Comparable> nums = new ArrayList<Comparable>();
nums.add(7); nums.add(4);
nums.add(8); nums.add(6);
nums.add(1); nums.add(3);
nums.add(4); nums.add(7);
nums.add(2); nums.add(1);
nums.add(5); nums.add(9);
nums.add(8); nums.add(3);
nums.add(2); nums.add(2);
System.out.println(Runtime.getRuntime().availableProcessors());
int r = nums.size() % 4;
int num = nums.size() / 4;
List<Merger> mergers = new ArrayList<Merger>();
mergers.add(new Merger(nums.subList(0, num)));
mergers.add(new Merger(nums.subList(num, num*2)));
mergers.add(new Merger(nums.subList(num*2, num*3)));
mergers.add(new Merger(nums.subList(num*3, (num*4) +r)));
mergers.get(0).start(); mergers.get(1).start();
mergers.get(2).start(); mergers.get(3).start();
mergers.get(0).join(); mergers.get(1).join();
mergers.get(2).join(); mergers.get(3).join();
System.out.println(mergers.get(0).getNums());
System.out.println(mergers.get(1).getNums());
System.out.println(mergers.get(2).getNums());
System.out.println(mergers.get(3).getNums());
mergers.get(0).absorbList(mergers.get(1).getNums());
mergers.get(0).setMerger(true);
mergers.get(0).run();
System.out.println(mergers.get(0).getNums());
mergers.get(2).absorbList(mergers.get(3).getNums());
mergers.get(2).setMerger(true);
mergers.get(2).run();
System.out.println(mergers.get(1).getNums());
System.out.println(mergers.get(3).getNums());
int maxThreads = nums.size() / 2;
}
}
class Merger extends Thread {
private List<Comparable> nums;
private boolean merge = false;
public List<Comparable> getNums() {
return nums;
}
public void setMerger(boolean bool) {
merge = bool;
}
public void absorbList(List<Comparable> list) {
nums.addAll(list);
}
Merger(List<Comparable> arr) {
nums = arr;
}
public void run() {
if(merge == false) {
mergeSort(nums, 0, nums.size() -1);
}else {
merge(nums, 0, (nums.size() -1)/2, nums.size() -1);
}
}
public static void swap(List<Comparable> nums, int index1, int index2)
{
Comparable temp;
temp = nums.get(index1);
nums.set(index1, nums.get(index2));
nums.set(index2, temp);
}
private static void mergeSort(List<Comparable> nums, int first, int last) {
if (first < last)
{
int m = (first+last)/2;
mergeSort(nums, first, m);
mergeSort(nums, m+1, last);
merge(nums, first, m, last);
}
}
private static void merge(List<Comparable> nums, int first, int mid, int last){
List<Comparable> newList = new ArrayList<Comparable>();
int loopCountA = 0;
int loopCountB = 0;
while(true) {
if(loopCountB == (last - mid)) {
while(first + loopCountA <= mid) {
newList.add(nums.get(first + loopCountA)); loopCountA++;
}
break;
}else if(first + loopCountA > mid) {
while(loopCountB < (last - mid)) {
newList.add(nums.get(mid + (loopCountB + 1))); loopCountB++;
}
break;
}else {
if(nums.get(mid + (loopCountB + 1)).compareTo(nums.get(first + loopCountA)) < 0) {
newList.add(nums.get(mid + (loopCountB + 1)));
loopCountB++;
}else {
newList.add(nums.get(first + loopCountA));
loopCountA++;
}
}
}
for(int i = 0; (i - 1) < (last - first); i++)
nums.set(first + i, newList.get(i));
}
}
I would say the problem here (causing the exception) is the way you create sublists - you are using subList(...) method, but it doesn't create another list, just a view for existing one. When you process these different views of one list in different threads you are causing the exception (as every thread changes the same list).
Possible solution would be to change the method to create a sub list or modify constructor to keep a copy, e.g.:
Merger(List<Comparable> arr) {
nums = new ArrayList<>(arr);
}
Related
I am trying to randomly generate jobs for the weighted job schedulling problem but it gives me an error, the jobs are generated and it shows them when i print them, but when it tries to find the maximum value it gives an error
Code:
package classGenerator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
public class Test1 {
// A job has start time, finish time and profit.
static class Job
{
int start, finish, profit;
Job(int start, int finish, int profit)
{
this.start = start;
this.finish = finish;
this.profit = profit;
}
#Override
public String toString() {
return "{" + "start='" + start + '\'' + "finish=" + finish + '\'' + "profit=" + profit + '}';
}
}
static int latestNonConflict(Job arr[], int i)
{
for (int j = i - 1; j >= 0; j--)
{
if (arr[j].finish <= arr[i - 1].start)
return j;
}
return -1;
}
// A recursive function that returns the maximum possible
// profit from given array of jobs. The array of jobs must
// be sorted according to finish time.
static int findMaxProfitRec(Job arr[], int n)
{
// Base case
if (n == 1) return arr[n-1].profit;
// Find profit when current job is included
int inclProf = arr[n-1].profit;
int i = latestNonConflict(arr, n);
if (i != -1)
inclProf += findMaxProfitRec(arr, i+1);
// Find profit when current job is excluded
int exclProf = findMaxProfitRec(arr, n-1);
return Math.max(inclProf, exclProf);
}
// The main function that returns the maximum possible
// profit from given array of jobs
static int findMaxProfit(Job arr[], int n)
{
// Sort jobs according to finish time
Arrays.sort(arr,new Comparator<Job>(){
public int compare(Job j1,Job j2)
{
return j1.finish-j2.finish;
}
});
return findMaxProfitRec(arr, n);
}
// Driver program
public static void main(String args[])
{
int m = 4;
Job arr[] = new Job[m];
Random rand = new Random();
for (int i = 0; i<arr.length; i++) {
arr[i] = new Job(rand.nextInt(30),rand.nextInt(50),rand.nextInt(300));
//System.out.println("Job[" + i + "]" + arr[i].toString());
}
int n =arr.length;
System.out.println("The optimal profit is " + findMaxProfit(arr, n));
}
}
The error is:
Exception in thread "main" java.lang.StackOverflowError
at classGenerator.Test1.findMaxProfitRec(Test1.java:45)
at classGenerator.Test1.findMaxProfitRec(Test1.java:47)
I wrote two pieces of code for knapsack problem. The first code gives me the correct answer (which is 16) and the second one doesn't. Is it something wrong with my recursive function?
First code (correct answer):
public class knapsackProblem {
static int[] weight = {1,2,4,2,5};
static int[] value = {5,3,5,3,2};
int result = 0;
// recursive function
public int sack(int i, int cap)
{
//base case
if(i<0 || cap == 0)
{
return 0;
} else if(weight[i] > cap)
{
return sack(i-1, cap);
} else
{
//get maximum value
return Math.max(sack(i-1, cap), value[i] + sack(i-1, cap - weight[i]));
}
}
public static void main(String[] args)
{
int capacity = 10;
int len = weight.length;
knapsackProblem kp = new knapsackProblem();
int total = kp.sack(len - 1, capacity);
System.out.println("sacked array is " + total);
}
}
Second code (incorrect answer):
public class knapsackProblem {
static int[] weight = {1,2,4,2,5};
static int[] value = {5,3,5,3,2};
int result = 0;
int tempNO = 0;
int tempYES = 0;
// recursive function
public int sack(int i, int cap)
{
//base case
if(i<0 || cap == 0)
{
return 0;
} else if(weight[i] > cap)
{
return sack(i-1, cap);
} else
{
//no case, move on to next value
tempNO = sack(i-1, cap);
//yes case, add the current value and move on to next value with decreased capacity
tempYES = value[i] + sack(i-1, cap - weight[i]);
//get maximum value
return Math.max(tempNO, tempYES);
}
}
public static void main(String[] args)
{
int capacity = 10;
int len = weight.length;
knapsackProblem kp = new knapsackProblem();
int total = kp.sack(len - 1, capacity);
System.out.println("sacked array is " + total);
}
}
The only difference is that in second code I put the results from recursion into variables before comparing for maximum value.
Thanks
Your variables are attributes of the class. The recursive calls are modifying those attributes every time, because you're using one single instance of the class to make the calls to the function. Declare the variables inside the method and remove them from the class to make it work. :)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm trying to make a bubble sorting algorithm in Java however my code just keeps going when It's supposed to sort without returning anything. When the program is run it gets as far as printing the array before the sorting however after that nothing happens but the program doesnt stop it keeps running
package src;
import java.util.Scanner;
import java.util.Random;
import java.util.ArrayList;
import java.util.List;
public class bubbleSort {
public static void main(String[] args) {
int length = getLength();
List<Integer> randomList = createList(length);
System.out.println("The list before sorting:\n" + randomList);
List<Integer> newList = sortList(randomList, length);
System.out.println("The list after sorting:\n" + newList);
}
public static int getLength() {
System.out.println("Please enter how long you want the array to be");
Scanner reader = new Scanner(System.in);
int length = Integer.parseInt(reader.nextLine());
return length;
}
public static List<Integer> createList(int length) {
Random rand = new Random();
List<Integer> randomList = new ArrayList<Integer>();
for(int x = 0 ; x < length ; x++){
int randomnumber = rand.nextInt((100 - 1) + 1) + 1;
randomList.add(randomnumber);
}
return randomList;
}
public static List<Integer> sortList(List<Integer> randomList, int length){
boolean sorted = false;
while(sorted == false){
sorted = true;
for(int x = 0 ; x < (length - 1) ; x++) {
if(randomList.get(x) > randomList.get(x + 1)) {
sorted = false;
int temp = randomList.get(x + 1);
randomList.set((x + 1), (x));
randomList.set((x + 1), temp);
}
}
}
return randomList;
}
}
Create a swap method to make it clearer (both for us and yourself):
private void swap(List<Integer> values, x, y) {
int temp = values.get(x);
values.set(x, values.get(y));
values.set(y, temp);
}
Other suggestions:
name your class BubbleSort rather than bubbleSort. Convention for class names is to start with uppercase.
don't pass the length as a second argument to your sort method. It's redundant and might become incorrect if someone sneakily adds an item to the list.
rename randomList to values or numbers or randomNumbers. No need to repeat the type in the variable name.
replace sorted == false with !sorted. This is the common and more readable notation
getLength and createList can be private
Consider using the main method to create an instance of your sorting class, with the list as a field. In that way the methods won't have to pass the list along to each other. Your code will be more readable and more object-oriented.
EDIT: you could take the separation even further and move all the static methods into a separate class called 'Application' or 'Main'. See edited code below:
Here's roughly how the code would look following my suggestions:
public class BubbleSort {
// a field
private List<Integer> numbers;
public BubbleSort(List<Integer> numbers) {
this.numbers = numbers;
}
public static List<Integer> sort() {
boolean sorted = false;
while(!sorted) {
sorted = true;
for(int x = 0; x < length - 1; x++) {
if(numbers.get(x) > numbers.get(x + 1)) {
sorted = false;
swap(x, x + 1);
}
}
}
return numbers;
}
private void swap(x, y) {
int temp = numbers.get(x);
numbers.set(x, numbers.get(y));
numbers.set(y, temp);
}
}
The Application class. It's purpose is to get the length from the user, create test data and set up and call a BubbleSort instance:
public class Application {
public static void main(String[] args) {
int length = getLength();
List<Integer> unsorted = createList(length);
System.out.println("The list before sorting:\n" + unsorted);
// creating an instance of the BubbleSort class
BubbleSort bubbleSort = new BubbleSort(unsorted );
List<Integer> sorted = bubbleSort.sort();
System.out.println("The list after sorting:\n" + sorted);
}
private static int getLength() {
System.out.println("Please enter how long you want the array to be");
Scanner reader = new Scanner(System.in);
return Integer.parseInt(reader.nextLine());
}
private static List<Integer> createList(int length) {
Random rand = new Random();
List<Integer> numbers = new ArrayList<Integer>();
for(int x = 0 ; x < length ; x++){
int randomnumber = rand.nextInt((100 - 1) + 1) + 1;
numbers.add(randomnumber);
}
return numbers;
}
BTW Good job splitting off those methods getLength and createList. That's the right idea.
you made a couple of mistakes
this:
randomList.set((x + 1), (x));
randomList.set((x + 1), temp);
should be:
randomList.set((x + 1), randomList.get(x));
randomList.set((x), temp);
full method:
public static List<Integer> sortList(List<Integer> randomList, int length){
boolean sorted = false;
while(sorted == false){
sorted = true;
for(int x = 0 ; x < (length - 1) ; x++) {
if(randomList.get(x) > randomList.get(x + 1)) {
sorted = false;
int temp = randomList.get(x + 1);
randomList.set((x + 1), randomList.get(x));
randomList.set((x), temp);
}
}
}
return randomList;
}
I am trying to convert the following iterative code:
int rows = 3;
for (int i = 0; i <= rows; i++)
{
for (int j = 0; j < i; j++)
{
System.out.print("*");
}
for (int j = 0; j < rows-i; j++)
{
System.out.print("-");
}
System.out.println();
}
with the output:
---
*--
**-
***
to recursive code. This is for an assignment. I created the iterative code in hopes of being able to figure out how to directly convert it to recursive. Here's my effort of that:
public void stringY(int star, int count){
if (star > 0){
System.out.print("*");
stringY(star - 1, count);
}
}
public void stringX(int dash,int count){
if (dash == -1) {
return;
}else if (dash < count){
System.out.print("-");
stringX(dash - 1, count);
} else if (dash == count){
stringX(dash - 1, count);
}
}
public void printPattern(int n) {
if (n == -1){
return;
} else {
printPattern(n-1);
stringY(n, n);
stringX(n, n);
System.out.println();
}
}
My issue here is that while I get the output I am looking for with regard to the "*" part of the pattern, I have absolutely no clue how to get the "-" part of the pattern. Now being that this is an assignment I don't want any solutions, but any pointers in the right direction are absolutely welcome. I should note that my two requirements are: 1) I have to complete my assignment entirely without using loops and 2) I can use as many helper methods as I need, but the main calling method (printPattern) must stay public void and must continue to only accept integers. Further clarification: The other two methods in the recursive code block are helper methods I created.
First let m = number of '*' to print and let n = number of '-' to print
For each recursion, increment m by 1 and decrement n by 1.
public static void main(String[] args) {
printPattern(3);
}
public static void printPattern(int n) {
printing(n, n);
}
//Variable size basically represent the number of columns
public static void printing(int n, int size) {
//stop condition
if(n == -1)
return;
//m is the number of * to print
int m = size - n;
printAsterisk(m);
//n is the number of - to print
printHyphen(n);
System.out.println();
printing(n - 1, size);
}
public static void printAsterisk(int m) {
if(m == 0)
return;
System.out.print('*');
printAsterisk(m - 1);
}
public static void printHyphen(int n) {
if(n == 0)
return;
System.out.print('-');
printHyphen(n - 1);
}
Think of it this way, they are all just loops doing some work. All you need is theoretically one recursive function that calls itself till the passed value.
void loop(int i, int till, Worker doThis) {
if (i>=till) return;
doThis.work(i);
loop(i+1, till, doThis);
}
Worker is just an interface,
public interface Worker {
void work(int index);
}
Now we need to pass the work that needs to be done. There are three loops, hence three calls to the loop function.
final int rows = 3;
// outer loop
loop(0, rows+1, new Worker() {
public void work(int index) {
// Stars
loop(0, index, new Worker() {
public void work(int index) {
System.out.print("*");
}
});
// Dashes
loop(0, rows-index, new Worker() {
public void work(int index) {
System.out.print("-");
}
});
System.out.println();
}
});
I would start by extracting then STAR and DASH,
private static final String DASH = "-";
private static final String STAR = "*";
Next, I would write a method to repeat a String a given number of times. Also, I would use a StringBuilder (here I've done it recursively)
private static StringBuilder repeat(StringBuilder sb, String str, int n) {
if (n > 0) {
sb.append(str);
repeat(sb, str, n - 1);
}
return sb;
}
Next, a private recursive method to print the pattern based on StringBuilder
private static void printPattern(StringBuilder sb, int s) {
System.out.println(sb);
int p = sb.indexOf(DASH, s);
if (p > -1) {
sb.replace(p, p + DASH.length(), STAR);
printPattern(sb, s + STAR.length());
}
}
And finally the public method
public static void printPattern(int n) {
printPattern(repeat(new StringBuilder(), DASH, n), 0);
}
I am writing a program which has to be able to sort up to 1 billion random Squares. I wrote a small example program below that creates a random ArrayList of Squares and then sorts it with two different methods.
When I was looking for an efficient method of sorting I found that using a Merge Sort was meant to be the most efficient/quickest. However, when comparing a merge sort to a custom sort (don't know if this sort of sort has a name) which I wrote I found the sort I wrote was more efficient.
The output I got from my program was
Time in nanoseconds for comparator sort: 2346757466
Time in nanoseconds for merge sort: 24156585699
Standard Sort is faster
So why is the sort I wrote so much quicker than a merge sort?
Can either of the used sorts be improved to make a faster, more efficient sort?
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Objects;
public class SortSquares {
public void run() {
ArrayList<Square> list = new ArrayList<Square>();
SecureRandom rand = new SecureRandom();
int randSize = 10;
for(int i = 1; i <= 10000000; i++)
list.add(new Square(i + rand.nextInt(randSize), i + rand.nextInt(randSize)));
//Create shallow copies to allow for timing
ArrayList<Square> comp = new ArrayList<Square>(list);
ArrayList<Square> merge = new ArrayList<Square>(list);
long startTime = System.nanoTime();
comp.sort(new SquareSort());
long endTime = System.nanoTime();
long duration = (endTime - startTime);
System.out.println("Time in nanoseconds for comparator sort: " + duration);
long startTime1 = System.nanoTime();
merge = mergeSort(merge);
long endTime1 = System.nanoTime();
long duration1 = (endTime1 - startTime1);
System.out.println("Time in nanoseconds for merge sort: " + duration1);
if(duration < duration1)
System.out.println("Standard Sort is faster");
else if(duration == duration1)
System.out.println("The sorts are the same");
else
System.out.println("Merge Sort is faster");
}
private class SquareSort implements Comparator<Square> {
#Override
public int compare(Square s1, Square s2) {
if(s1.getLocation()[0] > s2.getLocation()[0]) {
return 1;
} else if(s1.getLocation()[0] == s2.getLocation()[0]) {
if(s1.getLocation()[1] > s2.getLocation()[1]) {
return 1;
} else if(s1.getLocation()[1] == s2.getLocation()[1]) {
return 0;
} else {
return -1;
}
} else {
return -1;
}
}
}
public ArrayList<Square> mergeSort(ArrayList<Square> whole) {
ArrayList<Square> left = new ArrayList<Square>();
ArrayList<Square> right = new ArrayList<Square>();
int center;
if (whole.size() <= 1) {
return whole;
} else {
center = whole.size()/2;
for (int i = 0; i < center; i++) {
left.add(whole.get(i));
}
for (int i = center; i < whole.size(); i++) {
right.add(whole.get(i));
}
left = mergeSort(left);
right = mergeSort(right);
merge(left, right, whole);
}
return whole;
}
private void merge(ArrayList<Square> left, ArrayList<Square> right, ArrayList<Square> whole) {
int leftIndex = 0;
int rightIndex = 0;
int wholeIndex = 0;
while (leftIndex < left.size() && rightIndex < right.size()) {
if ((left.get(leftIndex).compareTo(right.get(rightIndex))) < 0) {
whole.set(wholeIndex, left.get(leftIndex));
leftIndex++;
} else {
whole.set(wholeIndex, right.get(rightIndex));
rightIndex++;
}
wholeIndex++;
}
ArrayList<Square> rest;
int restIndex;
if (leftIndex >= left.size()) {
rest = right;
restIndex = rightIndex;
} else {
rest = left;
restIndex = leftIndex;
}
for (int i = restIndex; i < rest.size(); i++) {
whole.set(wholeIndex, rest.get(i));
wholeIndex++;
}
}
private class Square {
private int[] location = new int[2];
public Square(int x, int y) {
location[0] = x;
location[1] = y;
}
public int[] getLocation() {
return location;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof Square)
if(getLocation()[0] == ((Square) obj).getLocation()[0] &&
getLocation()[1] == ((Square) obj).getLocation()[1])
return true;
return false;
}
#Override
public int hashCode() {
return Objects.hash(getLocation()[0], getLocation()[1]);
}
public int compareTo(Square arg0) {
if(getLocation()[0] > arg0.getLocation()[0]) {
return 1;
} else if(getLocation()[0] == arg0.getLocation()[0]) {
if(getLocation()[1] > arg0.getLocation()[1]) {
return 1;
} else if(getLocation()[1] == arg0.getLocation()[1]) {
return 0;
} else {
return -1;
}
} else {
return -1;
}
}
}
public static void main(String[] args) {
SortSquares e = new SortSquares();
e.run();
}
}
You can use java.util.Collections.sort( List list ) method from jdk. As mentioned above it uses merge sort with complexity O(nlogn).
In order to measure the performance of your implementation and compared it against other implementation I would suggest to use jmh http://openjdk.java.net/projects/code-tools/jmh/. Please find below a short example.
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.*;
import java.util.concurrent.TimeUnit;
#BenchmarkMode( Mode.AverageTime )
#OutputTimeUnit( TimeUnit.NANOSECONDS )
#State( Scope.Benchmark )
#Warmup( iterations = 5)
#Measurement( iterations = 5 )
#Fork( value = 1)
public class SortingPerformanceBenchmark
{
private final int[] dataArray = new int[10_000_000];
List<Integer> arrayList;
#Setup
public void load() {
Random rand = new Random();
for (int i = 0; i < dataArray.length; ++i) {
dataArray[i] = rand.nextInt();
}
}
#Benchmark
public List<Integer> Benchmark_SortObjects() {
arrayList = new ArrayList( Arrays.asList( dataArray ) );
Collections.sort( arrayList );
return arrayList;
}
public static void main(String... args) throws Exception {
Options opts = new OptionsBuilder()
.include(SortingPerformanceBenchmark.class.getSimpleName())
.build();
new Runner( opts).run();
}
}
The opposite is true: the standard method is much faster.
First, you create two arrays in each call to the recursive function mergeSort. The standard one probably merges the elements inplace in the original array, and use indices to the begin and the end of a range.
Second, the standard method can start new threads on multicore machines.
Considering algorithms It depends largely on the data.
Supposedly your sort method is quicksort.
You have O(n2) worst-case runtime and O(nlogn) average case runtime.
Mergesort is always O(n log n). This means stability. That's why it was chosen for sorting for the java collections.
Both sort and the mergesort you implemented is the same algorithm (sort on java collections is based on merge sort). You need to run the same code many times and warm up your jvm first to have more reliable results.
Somehow you can ensure that your custom mergesort is efficient and make comparisons with the collections one.
In any case you don't have to implement you own merge sort for something simple.