Multithreaded bubblesort using a threshold - java

So I got this assignment where I had to split an array into two, split those split arrays in 2, etc... up to a certain threshold.
So if my threshold was lets say 1000 it would be like:
10k>2x 5k>4x 2500>8x 1250>16x 625 (numbers in array).
Then I'd have to sort those arrays and merge them:
16x 625 (merged)>8x 1250 (merged)>4x 2500 (merged)>2x 5000 (merged)>1x 10k.
All of them must remain sorted.
So I think I got pretty far but it seems like it does not work the way I want it to. I tried multiple things to figure what is going wrong but I haven#t figured it out which is why I am here.
Can someone help me understand what I am doing wrong and give me a solution?
Bubblesort.java:
package PartThree;
import java.util.ArrayList;
import java.util.List;
public class Bubblesort implements Runnable {
public List<Integer> arrayList;
private int threshold;
private int middle;
public Bubblesort(List<Integer> arrayList, int threshold) {
this.arrayList = arrayList;
this.threshold = threshold;
this.middle = arrayList.size() / 2;
System.out.println(arrayList.size() + " ha");
}
#Override
public void run() {
if (arrayList.size() <= treshold) {
sort();
}else if(threshold<arrayList.size()){
Bubblesort rLeft = new Bubblesort(arrayList.subList(0, middle), threshold);
Bubblesort rRight = new Bubblesort(arrayList.subList(middle, arrayList.size()), threshold);
Thread tLeft = new Thread(rLeft);
Thread tRight = new Thread((rRight));
tRight.start();
tLeft.start();
try {
tLeft.join();
tRight.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
merge(rLeft.arrayList, rRight.arrayList);
System.out.println(arrayList.size() + ":size");
}
}
private void merge(List<Integer> left, List<Integer> right) {
int i = 0, j = 0, k = 0;
List<Integer> temp = new ArrayList<>();
while (i < left.size() && j < right.size()) {
if (left.get(i) < right.get(j)) {
temp.add(k, left.get(i));
i++;
} else {
temp.add(k, right.get(j));
j++;
}
k++;
}
while (i < left.size()) {
temp.add(k, left.get(i));
i++;
k++;
}
while (j < right.size()) {
temp.add(k, right.get(j));
j++;
k++;
}
arrayList = temp;
temp.clear();
}
private void sort() {
int i, j, tijdelijk;
for (j = 0; j < arrayList.size(); j++) {
for (i = 1; i < arrayList.size() - j; i++) {
if (arrayList.get(i - 1) > arrayList.get(i)) {
tijdelijk = arrayList.get(i);
arrayList.set(i, arrayList.get(i - 1));
arrayList.set(i - 1, tijdelijk);
}
}
}
}
}
Implementation:
package PartThree;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class API {
private Random random = new Random();
private List<Integer> array_unsorted_main = new ArrayList<>();
private int maxSize;
private Thread t1;
private void run(){
this.maxSize = 10000;
for (int i = 0; i < maxSize; i++) {
array_unsorted_main.add(random.nextInt(10000));
}
t1 = new Thread(new Bubblesort(array_unsorted_main,1000));
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String args[]){
new PartThree.API().run();
}
}
Please help me out, thank you for your time.

One of your problems is in your merge method you do arrayList = temp; and then do temp.clear() thereby clearing arrayList since it now points to temp.
Remove the temp.clear() statement so arrayList will retain the sorted values.

Related

how to print last element after deleting odd indices continuously

I am trying to delete the odd positions starting from 1 continuously and to get the last remaining element;
e.g.:
n=6;
1 2 3 4 5 6
first: removing odd indices will get (2 4 6);
second: removing odd indices will get (4) which is the answer...
here is my code:
import java.util.HashMap;
public class Odd_Deletions {
public static void oddDeletions(HashMap<Integer, Integer> hm) {
int j = 1;
for (int i = 1; i < hm.size(); i++) {
if (hm.get(i) % 2 != 0) {
continue;
} else {
hm.put(j, i);
j++;
}
}
//System.out.println(hm);
while (true) {
if (hm.size() == 1) {
System.out.println(hm);
break;
} else
oddDeletions(hm);
}
}
public static void main(String args[]) {
int n = 6;
HashMap<Integer, Integer> hm = new HashMap<>();
for (int i = 1; i <= n; i++) {
hm.put(i, i);
}
//System.out.println(hm);
oddDeletions(hm);
}
}
why I am getting StackOverflow Error and what is wrong with this logic?
can anyone fix it?
Thanks and regards;
Perhaps the HashMap is not the right class to use here. Anyway, as #Welbog pointed out, you never remove anything from your table. Also, why use recursion?
Try something like this:
while (hm.size() > 1) {
int j = 1;
int last = hm.size();
for (int i = 1; i <= last; i++) {
int value = hm.remove(i);
if (i % 2 == 0) {
hm.put(j, value);
j++;
}
}
}
There are 3 possible solutions.
(1) I don't know why you need to apply that "removal process" on the HashMap with that logic, anyway a possible solution could be the following one. But use it only if you need to apply to a Map where you need to remove its entries by, for some reasons, applying that logic on the Map keys.
public class RemovingOddIndexes {
public static void main(String[] args) {
// initialize
int n = 6;
HashMap<Integer, Integer> hm = new HashMap<>();
for (int i = 1; i <= n; i++) {
hm.put(i, i);
}
//
oddDeletions(hm);
// print result
hm.forEach((k, v) -> System.out.println(String.format("%s:%s, ", k, v)));
}
public static void oddDeletions(HashMap<Integer, Integer> hm) {
while (hm.size() > 1) {
hm.keySet()
.stream()
.sorted()
.forEach(new Consumer<Integer>() {
int i = 1;
#Override
public void accept(Integer n) {
if (i % 2 == 1)
hm.remove(n);
++i;
}
});
}
}
}
(2) Otherwise use a simple LinkedList that you can skim recursively. I prefer to use a LinkedList over an ArrayList because the alg need to remove elements at every iteration, till the last one. And the remove operation on a LinkedList performs better.
public class RemovingOddIndexes {
public static void main(String[] args) {
// initialize
int n = 6;
List<Integer> list = new LinkedList<>();
for (int i = 1; i <= n; i++) {
list.add(i);
}
//
oddDeletions(list);
// print result
list.forEach(i -> System.out.println(String.format("%s, ", i)));
}
public static void oddDeletions(List<Integer> list) {
while (list.size() > 1) {
int i = 1;
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
it.next();
if (i++ % 2 == 1) {
it.remove();
}
}
}
}
}
(3) Last option, the fastest way possible
int lastOdd = 1 << (int)(Math.log(n) / Math.log(2))

Java Top-Down Merge Sort - Stackoverflow Error

I am trying to implement the top-down merge sort algorithm in Java, using the pseudocode from Wikipedia.
My problem is that my code sometimes throws a StackOverflowError, but not always. I have checked that my code matches the pseudocode several times and cannot find what is wrong with it.
Here is my Java code:
import java.util.ArrayList;
import java.util.Random;
public class Main {
public static void main(String[] args) {
Random r = new Random();
ArrayList<Integer> numbers = new ArrayList<Integer>();
for (int i = 1; i <= 15; i++) {
numbers.add(r.nextInt(100));
}
numbers = mergeSort(numbers);
System.out.println(numbers);
}
public static ArrayList<Integer> mergeSort(ArrayList<Integer> m) {
if (m.size() <= 1) {
return m;
}
ArrayList<Integer> left = new ArrayList<Integer>();
ArrayList<Integer> right = new ArrayList<Integer>();
for (Integer x : m) {
if (m.indexOf(x) < (m.size()) / 2)
left.add(x);
else {
right.add(x);
}
}
left = mergeSort(left);
right = mergeSort(right);
return merge(left, right);
}
private static ArrayList<Integer> merge(ArrayList<Integer> l, ArrayList<Integer> r) {
ArrayList<Integer> result = new ArrayList<Integer>();
while (l.size() > 0 && r.size() > 0) {
if (l.get(0) <= r.get(0)) {
result.add(l.get(0));
l.remove(0);
}
else {
result.add(r.get(0));
r.remove(0);
}
}
while (l.size() > 0) {
result.add(l.get(0));
l.remove(0);
}
while (r.size() > 0) {
result.add(r.get(0));
r.remove(0);
}
return result;
}
}
Your algorithm encounters issues when there are duplicate elements, as indexOf will only return the index of the first one. Use a index-based for loop instead. Demo
for (int i = 0; i < m.size(); i++) {
if (i < (m.size()) / 2)
left.add(m.get(i));
else {
right.add(m.get(i));
}
}
In the mergeSort method need to change the for loop little bit and try again.
for (int i=0;i< m.size()/2;i++)
left.add(m.get(i));
for (int i=m.size()/2;i< m.size();i++)
right.add(m.get(i));

Multithreaded code runs worse or roughly as fast as singlethreaded

I am trying to solve the N Queen problem using multiple threads. However, the single threaded version of it runs either faster or roughly the same as the multithreaded one.
In essence, I use a queue which all the threads share. They pop states from the queue and expand them and add then them to the queue. I have tried playing around with the number of threads but to no avail, the more threads I add after around 8 the performance degenerates. The algorithm is correct in that the output is the same in both versions.
Any ideas?
Here's the code:
public class Queens {
//Thread
static class Runner implements Runnable {
private BlockingQueue<Configuration> queue;
private final AtomicInteger total;
public Runner(BlockingQueue<Configuration> q, AtomicInteger total) {
this.queue = q;
this.total = total;
}
public void run() {
while(!queue.isEmpty()) {
Configuration currentConfiguration = null;
try {
currentConfiguration = queue.take();
}
catch(InterruptedException e) {
}
if(currentConfiguration.done()) {
//currentConfiguration.printConfiguration();
total.incrementAndGet();
System.out.println("Solution");
continue;
}
for(int i = 0; i < currentConfiguration.getSize(); i++) {
if(safe(currentConfiguration, i, currentConfiguration.getColumn())) {
Configuration childConfig = new Configuration(currentConfiguration.getColumn() + 1,
currentConfiguration.getBoard());
childConfig.place(i, currentConfiguration.getColumn());
queue.add(childConfig);
}
}
}
}
//Returns true if we can place a queen on that row and column.
private boolean safe(Configuration current, int row, int col) {
for (int i = 0; i < col; i++)
if (current.getBoard()[row][i] == 1)
return false;
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--)
if (current.getBoard()[i][j] == 1)
return false;
for (int i = row, j = col; j >= 0 && i < current.getSize(); i++, j--)
if (current.getBoard()[i][j] == 1)
return false;
return true;
}
}
//Board configuration class.
static class Configuration {
private int column;
private int[][] board;
private int size;
public Configuration(int column, int[][] b) {
this.column = column;
this.board = new int[b.length][b.length];
this.size = b.length;
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
board[i][j] = b[i][j];
}
}
}
public int getSize() {
return size;
}
public int getColumn() {
return column;
}
public int[][] getBoard() {
return board;
}
public boolean done() {
if(column == size)
return true;
return false;
}
public void place(int row, int column) {
board[row][column] = 1;
}
//Method prints the current configuration.
public synchronized void printConfiguration() {
synchronized(Configuration.class) {
System.out.println(Thread.currentThread().getName());
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Configuration x = new Configuration(0, new int[13][13]);
int threads = 10;
AtomicInteger totalSolutions = new AtomicInteger(0);
List<Thread> mythreads = new ArrayList<Thread>();
BlockingQueue<Configuration> q = new LinkedBlockingDeque<>();
//Initially the board is empty
q.put(x);
long startTime = System.currentTimeMillis();
//Run 10 threads
for(int i = 0; i < threads; i++) {
Thread newthread = new Thread(new Runner(q, totalSolutions));
newthread.start();
mythreads.add(newthread);
}
for(Thread t : mythreads) {
try {
t.join();
}
catch(Exception e) {};
}
System.out.println(totalSolutions.get());
long endTime = System.currentTimeMillis();
System.out.println("Time: " + (endTime - startTime));
}
}
This was too long for a comment so I have to write it as an answer, apology on that.
In run method I've added the following like:
System.out.println(Thread.currentThread().getName() + " taking " + currentConfiguration.toString() + " out of " + queue.size() + " elem");
When running a single thread program it looks like this:
Thread-0 taking jobs.DeleteMe$Configuration#279b9032 out of 925326 elem
Thread-0 taking jobs.DeleteMe$Configuration#15ced747 out of 925327 elem
Thread-0 taking jobs.DeleteMe$Configuration#42689f59 out of 925328 elem
Thread-0 taking jobs.DeleteMe$Configuration#29aeeda2 out of 925329 elem
When running 10 threads the log looks like:
Thread-6 taking jobs.DeleteMe$Configuration#2775c7e7 out of 39393 elem
Thread-7 taking jobs.DeleteMe$Configuration#4e0ae08b out of 39308 elem
Thread-6 taking jobs.DeleteMe$Configuration#5eb0ba9 out of 39404 elem
Thread-9 taking jobs.DeleteMe$Configuration#12321211 out of 39401 elem
Thread-0 taking jobs.DeleteMe$Configuration#13a07923 out of 39383 elem
Thread-9 taking jobs.DeleteMe$Configuration#442cf86a out of 39415 elem
Thread-0 taking jobs.DeleteMe$Configuration#49366e2a out of 39420 elem
Thread-8 taking jobs.DeleteMe$Configuration#1c4bcfa5 out of 39378 elem
So it seems there is nothing preventing multiple threads to work.
Since your code uses one resource intensively, which is memory.
So I guess the reason is that memory cache is used more efficiently when there is a single thread running instead of multiple threads. It means that single thread access usually Configuration which is already in CPU cache, while when running multithreaded there are more misses.
See:
Is multi-thread memory access faster than single threaded memory access?
On the sidenote, it would probably be efficient to take a configuration which was the most recently added, BlockingQueue takes the first configuration, it would probably be more efficient to use LinkedBlockingDeque.
So I tried with LinkedBlockingDeque, with 10 threads, it runs for
Time: 3753
with 1 thread:
Time: 3352
(it's 3x speedup for me than the version with LinkedBlockingQueue).
Source:
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* #author mladen
*/
public class DeleteMe {
//Thread
static class Runner implements Runnable {
private LinkedBlockingDeque<Configuration> queue;
private final AtomicInteger total;
public Runner(LinkedBlockingDeque<Configuration> q, AtomicInteger total) {
this.queue = q;
this.total = total;
}
public void run() {
while (!queue.isEmpty()) {
Configuration currentConfiguration = null;
//try {
currentConfiguration = queue.removeLast();
//System.out.println(Thread.currentThread().getName() + " taking " + currentConfiguration.toString() + " out of " + queue.size() + " elem");
// } catch (InterruptedException e) {
//
// }
if (currentConfiguration.done()) {
//currentConfiguration.printConfiguration();
total.incrementAndGet();
System.out.println("Solution");
continue;
}
for (int i = 0; i < currentConfiguration.getSize(); i++) {
if (safe(currentConfiguration, i, currentConfiguration.getColumn())) {
Configuration childConfig = new Configuration(currentConfiguration.getColumn() + 1,
currentConfiguration.getBoard());
childConfig.place(i, currentConfiguration.getColumn());
queue.add(childConfig);
}
}
}
}
//Returns true if we can place a queen on that row and column.
private boolean safe(Configuration current, int row, int col) {
for (int i = 0; i < col; i++) {
if (current.getBoard()[row][i] == 1) {
return false;
}
}
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (current.getBoard()[i][j] == 1) {
return false;
}
}
for (int i = row, j = col; j >= 0 && i < current.getSize(); i++, j--) {
if (current.getBoard()[i][j] == 1) {
return false;
}
}
return true;
}
}
//Board configuration class.
static class Configuration {
private int column;
private int[][] board;
private int size;
public Configuration(int column, int[][] b) {
this.column = column;
this.board = new int[b.length][b.length];
this.size = b.length;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
board[i][j] = b[i][j];
}
}
}
public int getSize() {
return size;
}
public int getColumn() {
return column;
}
public int[][] getBoard() {
return board;
}
public boolean done() {
if (column == size) {
return true;
}
return false;
}
public void place(int row, int column) {
board[row][column] = 1;
}
//Method prints the current configuration.
public synchronized void printConfiguration() {
synchronized (Configuration.class) {
System.out.println(Thread.currentThread().getName());
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Configuration x = new Configuration(0, new int[13][13]);
int threads = 1;
AtomicInteger totalSolutions = new AtomicInteger(0);
List<Thread> mythreads = new ArrayList<Thread>();
LinkedBlockingDeque<Configuration> q = new LinkedBlockingDeque<>();
//Initially the board is empty
q.put(x);
long startTime = System.currentTimeMillis();
//Run 10 threads
for (int i = 0; i < threads; i++) {
Thread newthread = new Thread(new Runner(q, totalSolutions));
newthread.start();
mythreads.add(newthread);
}
for (Thread t : mythreads) {
try {
t.join();
} catch (Exception e) {
};
}
System.out.println(totalSolutions.get());
long endTime = System.currentTimeMillis();
System.out.println("Time: " + (endTime - startTime));
}
}
The synchronization overhead is massive here. Try doing more work without fetching from the queue all the time.
Also, between the isEmpty call and the take call the queue can become empty. Avoid this race condition by using poll and checking for null result.
The memory overhead can be mitigated by going depth-first instead of breadth-first.
Code follows:
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class Queens {
//Thread
static class Runner implements Runnable {
private BlockingQueue<Configuration> queue;
private final AtomicInteger total;
private boolean local;
public Runner(BlockingQueue<Configuration> q, AtomicInteger total) {
this.queue = q;
this.total = total;
}
public void run() {
while(true) {
Configuration currentConfiguration = null;
try {
currentConfiguration = queue.poll(50, TimeUnit.MILLISECONDS);
}
catch(InterruptedException e) {
}
if(!local && queue.size() > 1000) local = true;
if(currentConfiguration == null){
break;
}
recurse(currentConfiguration);
}
System.out.println("DONE");
}
public void recurse(Configuration c){
if(c.done()){
total.incrementAndGet();
return;
}
for(int i = 0; i < c.getSize(); i++) {
if(safe(c, i, c.getColumn())) {
c.place(i, c.getColumn());
c.setColumn(c.getColumn() + 1);
if(local){
recurse(c);
}else{
queue.add(c.clone());
}
c.setColumn(c.getColumn() - 1);
c.clear(i, c.getColumn());
}
}
}
//Returns true if we can place a queen on that row and column.
private boolean safe(Configuration current, int row, int col) {
for (int i = 0; i < col; i++)
if (current.getBoard()[row][i] == 1)
return false;
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--)
if (current.getBoard()[i][j] == 1)
return false;
for (int i = row, j = col; j >= 0 && i < current.getSize(); i++, j--)
if (current.getBoard()[i][j] == 1)
return false;
return true;
}
}
//Board configuration class.
static class Configuration {
private int column;
private int[][] board;
private int size;
public Configuration(int column, int[][] b) {
this.column = column;
this.board = new int[b.length][b.length];
this.size = b.length;
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
board[i][j] = b[i][j];
}
}
}
public Configuration clone(){
return new Configuration(column, board);
}
public int getSize() {
return size;
}
public int getColumn() {
return column;
}
public void setColumn( int v) {
column = v;
}
public int[][] getBoard() {
return board;
}
public boolean done() {
if(column == size)
return true;
return false;
}
public void place(int row, int column) {
board[row][column] = 1;
}
public void clear(int row, int column){
board[row][column] = 0;
}
//Method prints the current configuration.
public synchronized void printConfiguration() {
synchronized(Configuration.class) {
System.out.println(Thread.currentThread().getName());
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
final int size = 14;
Configuration x = new Configuration(0, new int[size][size]);
int threads = 8;
AtomicInteger totalSolutions = new AtomicInteger(0);
List<Thread> mythreads = new ArrayList<Thread>();
BlockingQueue<Configuration> q = new LinkedBlockingDeque<>();
//Initially the board is empty
q.put(x);
long startTime = System.currentTimeMillis();
//Run 10 threads
for(int i = 0; i < threads; i++) {
Thread newthread = new Thread(new Runner(q, totalSolutions));
newthread.start();
mythreads.add(newthread);
}
for(Thread t : mythreads) {
try {
t.join();
}
catch(Exception e) {};
}
System.out.println(totalSolutions.get());
long endTime = System.currentTimeMillis();
System.out.println("Time: " + (endTime - startTime));
}
}

Bar demonstration of Shaker sort sorts all bars at once -Java

I found this code here in the accepted answer: Java swing repainting while computing: animating sorting algorithm
And I've been trying to modify it so it works for shaker sort but my code sorts the whole thing all at once.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collections;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ShakerSortAnimate extends JPanel {
private static final int NUM_OF_ITEMS = 20;
private static final int DIM_W = 400;
private static final int DIM_H = 400;
private static final int HORIZON = 350;
private static final int VERT_INC = 15;
private static final int HOR_INC = DIM_W / NUM_OF_ITEMS;
private JButton startButton;
private Timer timer = null;
private JButton resetButton;
Integer[] list;
int currentIndex = NUM_OF_ITEMS - 1;
public ShakerSortAnimate() {
list = initList();
timer = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (isSortingDone()) {
((Timer) e.getSource()).stop();
startButton.setEnabled(false);
} else {
sortOnlyOneItem();
}
repaint();
}
});
//button to run the program
startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
//resets screen
resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
list = initList();
currentIndex = NUM_OF_ITEMS - 1;
repaint();
startButton.setEnabled(true);
}
});
add(startButton);
add(resetButton);
}
//boolean checks when array is sorted
public boolean isSortingDone() {
return currentIndex == 0;
}
//initializes the array
public Integer[] initList() {
Integer[] nums = new Integer[NUM_OF_ITEMS];
for (int i = 1; i <= nums.length; i++) {
nums[i - 1] = i;
}
Collections.shuffle(Arrays.asList(nums)); //shuffles array
return nums;
}
//draws each bar
public void drawItem(Graphics g, int item, int index) {
int height = item * VERT_INC;
int y = HORIZON - height;
int x = index * HOR_INC;
g.fillRect(x, y, HOR_INC, height);
}
//My shaker sort code
public void sortOnlyOneItem()
{
boolean swapped = true;
int start = 0;
int end = currentIndex;
while (swapped==true)
{
swapped = false;
for (int i = start; i < end; ++i)
{
if (list[i] > list[i + 1])
{
int temp = list[i];
list[i] = list[i+1];
list[i+1] = temp;
swapped = true;
}
}
if (swapped==false)
break;
swapped = false;
end = end-1;
for (int i = end; i >=start; i--)
{
if (list[i] > list[i+1])
{
int temp = list[i];
list[i] = list[i+1];
list[i+1] = temp;
swapped = true;
}
}
start = start + 1;
}
currentIndex--; //currentIndex is updated each time shaker sort runs
}
//draws all bars
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < list.length; i++) {
drawItem(g, list[i], i);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(DIM_W, DIM_H);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Sort");
frame.add(new ShakerSortAnimate());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I do realize that my Shaker Sort code has to do it for each comparison, not the entire thing but honestly, I don't even know how to begin to code that. If anyone of you here knows how to code each comparison in shaker sort, can you help me out?
Btw, I posted the entire thing so you can try running this as well.
Thanks in advance!
So, you need this...
public void sortOnlyOneItem()
{
boolean swapped = true;
int start = 0;
int end = currentIndex;
while (swapped==true)
{
swapped = false;
for (int i = start; i < end; ++i)
{
if (list[i] > list[i + 1])
{
int temp = list[i];
list[i] = list[i+1];
list[i+1] = temp;
swapped = true;
}
}
if (swapped==false)
break;
swapped = false;
end = end-1;
for (int i = end; i >=start; i--)
{
if (list[i] > list[i+1])
{
int temp = list[i];
list[i] = list[i+1];
list[i+1] = temp;
swapped = true;
}
}
start = start + 1;
}
currentIndex--; //currentIndex is updated each time shaker sort runs
}
To only run ONCE per call. It's not doing that right now because if the while-loop, so, we need to get rid of that.
In doing so, the second loop should only be run if swapped is true AND the currentIndex should only be decremented if swapped is still true
Which brings us to something like...
public void sortOnlyOneItem() {
boolean swapped = true;
int start = 0;
int end = currentIndex;
for (int i = start; i < end; ++i) {
if (list[i] > list[i + 1]) {
int temp = list[i];
list[i] = list[i + 1];
list[i + 1] = temp;
swapped = true;
}
}
if (swapped) {
swapped = false;
end = end - 1;
for (int i = end; i >= start; i--) {
if (list[i] > list[i + 1]) {
int temp = list[i];
list[i] = list[i + 1];
list[i + 1] = temp;
swapped = true;
}
}
}
if (swapped) {
currentIndex--; //currentIndex is updated each time shaker sort runs
}
}
Which still isn't quite right, as the two for-loops can make multiple changes.
Instead, we need a iteration which will only make, at most, two changes, one at the start and one at the end
Which, might, look something like...
protected void swap(int a, int b) {
int tmp = list[a];
list[a] = list[b];
list[b] = tmp;
}
int endIndex = NUM_OF_ITEMS - 1;
//My shaker sort code
public void sortOnlyOneItem() {
int startIndex = 0;
while (startIndex < NUM_OF_ITEMS - 1 && list[startIndex] < list[startIndex + 1]) {
startIndex++;
}
if (startIndex < NUM_OF_ITEMS - 1 && list[startIndex] > list[startIndex + 1]) {
swap(startIndex, startIndex + 1);
int end = endIndex;
while (end > 0 && list[end - 1] < list[end]) {
end--;
}
if (end > 0 && list[end - 1] > list[end]) {
swap(end - 1, end);
} else {
endIndex--;
}
} else {
endIndex = 0;
}
}
Now, this basically looks for the two indices which might be changeable (at the start and end) and swaps them if possible. When you can iterate from the start to the end without making a change, the sort is finished.
Now, I make no claims over if this is accurate or not, only that it does the best effort to mimic the algorithm you supplied

MergeSort Implementation IndexOutOfBounds Java

import java.util.ArrayList;
import java.util.Random;
public class Merge {
private static ArrayList<Integer> newArrayList;
public static ArrayList<Integer> generateArray(int n){
newArrayList = new ArrayList<Integer>(n);
Random rand = new Random();
for (int i = 0; i<n; i++){
newArrayList.add(rand.nextInt(n + 1));
}
return newArrayList;
}
public static ArrayList<Integer> mergeSort(ArrayList<Integer> x){
if (x.size()>1){
ArrayList<Integer> ArrayList1 = new ArrayList<Integer>(x.size()/2);
ArrayList<Integer> ArrayList2 = new ArrayList<Integer>(x.size()-(x.size()/2));
for (int i = 0; i<newArrayList.size()/2; i++){
ArrayList1.set(i, newArrayList.get(i));
}
for (int i = (newArrayList.size()/2); i<((newArrayList.size()/2)+(newArrayList.size()-newArrayList.size()/2)); i++){
ArrayList2.set(i-(newArrayList.size()/2), newArrayList.get(i));
}
//ArrayList1 = mergeSort(ArrayList1);
//ArrayList2 = mergeSort(ArrayList2);
int j = 0;
int k = 0;
int a = 0;
while(ArrayList1.size() != j && ArrayList2.size() != k){
if (ArrayList1.get(j) < ArrayList2.get(k)){
x.set(a, ArrayList1.get(j));
a++;
j++;
} else {
x.set(a, ArrayList2.get(k));
a++;
k++;
}
}
while (ArrayList1.size()!=j){
x.set(a, ArrayList1.get(j));
a++;
j++;
}
while (ArrayList2.size()!=k){
x.set(a, ArrayList2.get(k));
a++;
k++;
}
}
return x;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Integer> new1;
//ArrayList<Integer> new2;
//ArrayList<Integer> new3;
new1 = generateArray(10);
//new2 = generateArray(100);
//new3 = generateArray(1000);
System.out.println(new1);
mergeSort(new1);
System.out.println(new1);
}
}
I am attempting to implement a mergeSort method but I keep getting the following error:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.set(ArrayList.java:337)
at Merge.mergeSort(Merge.java:23)
at Merge.main(Merge.java:73)
Any ideas?
You are attempting to set a position that doesn't exist yet in your ArrayList called ArrayList1. You've set the initial capacity to x.size() / 2, but there's nothing in it yet.
It looks like you are attempting to set each position, starting with position 0, so just add the elements instead. Replace
for (int i = 0; i<newArrayList.size()/2; i++){
ArrayList1.set(i, newArrayList.get(i));
}
with
for (int i = 0; i<newArrayList.size()/2; i++){
ArrayList1.add(newArrayList.get(i));
}
And you'll need to make similar changes to the for loop after that, which populates ArrayList2.

Categories