I modified quick sort to make it multithread.
I expected it to work , coz the original algorithm was working.
After partitioning, for the recursive calls to left and right of pivot .. I am creating a new thread.
public class QuickSort extends Thread{
private int[] arr;
private int left;
private int right;
public QuickSort(int[] arr){
this.arr= arr;
this.left=0;
this.right=arr.length -1;
this.start();
}
public QuickSort(int[] arr, int left , int right){
this.arr= arr;
this.left=left;
this.right=right;
this.start();
}
int partition( int left, int right)
{
int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
};
return i;
}
void quickSort(int left, int right) {
int index = partition(left, right);
if (left < index - 1)
new QuickSort(arr, left , index -1);
if (index < right)
new QuickSort(arr ,index, right);
}
public void run(){
quickSort(left , right);
}
public static void main(String arg[])
{
int[] s = {100,99,98,97,96,95,94,93,92,91};
new QuickSort(s);
for(int i: s)
System.out.println(i);
}
}
Your first problem is that you aren't waiting for any thread to exit, so you are printing the data while the threads are still running. You need some Thread.join() calls.
I'm not saying there aren't other problems ... Your sort fails if there are already sorted elements, e.g. if you add 89,90 to your test array.
For one thing, you're never waiting for any of the threads to finish. So by the time you go to print out the array who knows how much work has been done.
You'll need to somehow join() the threads you've spun up (or come up with some other mechanism to figure out they're done).
Related
This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 4 years ago.
Im trying to make a Quicksort but it always showing up the Error ArrayIndexOutOfBoundsException.
public class Quicksort
{
void sort(int[] arr)
{
_quicksort(arr, 0, arr.length - 1);
}
private void _quicksort(int[] arr, int left, int right)
{
int pivot = (left + right)/2;
int l = left;
int r = right;
while (l <= r)
{
while (arr[l] < pivot)
{
l++;
}
while (arr[r] > pivot)
{
r--;
}
if(l <= r)
{
int temp = l;
l = r;
r = temp;
l++;
r++;
}
}
if(left < r)
{
_quicksort(arr, left, r);
}
if(l < right)
{
_quicksort(arr, l, right);
}
}
}
Does someone know why it doesnt run? It always gives a Error.
The Error message is
java.lang.ArrayIndexOutOfBoundsException: -1
at Quicksort._quicksort(Quicksort.java:18)
at Quicksort._quicksort(Quicksort.java:33)
at Quicksort.sort(Quicksort.java:5)
Error Message
It seems like there are a couple of issues with your code. I've listed them below:
The variable pivot stores the index of the pivot element and not the actual value. So, you can't use pivot for comaparison as you have done in the 2 nested while loops. You need arr[pivot] instead of pivot there.
Imagine arr looks like {1, 1, 1, 3, 2, 2, 2}. Here, pivot will be equal to 3 i.e. arr[pivot] will be equal to 3. Now, after both the nested while loops terminate, l will be equal to 3 and r will remain equal to 6. You then swap arr[l] and arr[r] and increment both l and r. Since l is still less than equal to r, the outer while loop runs for a second time and you'll get an ArrayIndexOutOfBoundsExecption when the control reaches the second nested while loop. This happens because you're trying to access arr[7] (Out of Bounds).
Here's my code:
class Quicksort
{
void sort(int[] arr)
{
myQuicksort(arr, 0, arr.length - 1);
}
private void myQuicksort(int[] arr, int l, int r) {
if (l >= r) {
return;
}
int pivotIndex = (l + r) / 2;
swap (arr, r, pivotIndex);
int pivotValue = arr[r];
int swapIndex = 0;
int currentIndex = 0;
while (currentIndex != r) {
if (arr[currentIndex] < pivotValue) {
swap(arr, currentIndex, swapIndex);
swapIndex++;
}
currentIndex++;
}
swap(arr, r, swapIndex);
myQuicksort(arr, l, swapIndex - 1);
myQuicksort(arr, swapIndex + 1, r);
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
public class Main{
public static void main(String[] args) {
Quicksort quicksort = new Quicksort();
int[] arr = {3, 7, 1, 0, 4};
quicksort.sort(arr);
for (int i : arr) {
System.out.println(i);
}
}
}
You should read up on Quicksort. But here are the main points:
Choose a random pivot element and swap it with the last element. This makes the implementation much simpler.
Loop over the input array and keep a track of a swapIndex such that everything before the swapIndex is less than the pivotValue and everything from the swapIndex till the currentIndex is greater than (or equal) the pivotValue.
After the loop runs out, swap the element at swapIndex with the pivot. This inserts the pivot in its correct position.
The pivot divides the array into 2 subarrays. Call myQuicksort on these 2 subarrays.
I have a task where I need to sort an array by quicksort algorithm. Size of array and amount of threads can be custom. Also I've have to merge threads like on picture: here
As I understood I need to split an array by amount of proccessors and sorted it.
class Quicksort implements Callable<int[]>{
int[] arr;
Quicksort(int[] array){
this.arr = array;
}
#Override
public int[] call() throws Exception {
sort(arr,0,arr.length-1);
long threadId = Thread.currentThread().getId();
return arr;
}
/* This function takes last element as pivot,
places the pivot element at its correct
position in sorted array, and places all
smaller (smaller than pivot) to left of
pivot and all greater elements to right
of pivot */
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low-1); // index of smaller element
for (int j=low; j<high; j++)
{
// If current element is smaller than or
// equal to pivot
if (arr[j] <= pivot)
{
i++;
// swap arr[i] and arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// swap arr[i+1] and arr[high] (or pivot)
int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp;
return i+1;
}
/* The main function that implements QuickSort()
arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void sort(int arr[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[pi] is
now at right place */
int pi = partition(arr, low, high);
// Recursively sort elements before
// partition and after partition
sort(arr, low, pi-1);
sort(arr, pi+1, high);
}
}
In Main class I'm using ExecutorService to do sorting stuff
public static void main(String args[]) {
List<int[]> chunckedList = Utils.covertFrom2DToList(chuncked);
try {
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Quicksort> callableList = new ArrayList<>();
for (int[] chunck : chunckedList) {
callableList.add(new Quicksort(chunck));
}
List<Future<int[]>> futureObjects = executorService.invokeAll(callableList);
executorService.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But I have no idea how to merge it in threads.
Could you give me a hint or advice how to implement it. Thanks!
I'm implementing a recursive quicksort however I'm receiving stackoverflow and not sure where the bug lies :(
I'm sorting 1 million ints from 10-50.
I works for sizes less than 1 million like 100 thousand etc.
public Quicksort(int NUM_TESTS, int NUM_ELEMENTS){
num_tests = NUM_TESTS;
num_elements = NUM_ELEMENTS;
}
private void start(){
for (int i = 0; i < num_tests; i++){
int[] d1 = dataGeneration(num_elements);
qSortRecursive(d1,0,d1.length-1);
}
}
public static void main(String args[]){
Quicksort q = new Quicksort(1,1000000);
q.start();
}
private int[] dataGeneration(int n) {
int[] d1 = new int[n];
for (int i = 0; i < n; i++){
d1[i] = (int)(Math.random() * ((50 - 10) + 1) + 10);
}
return d1;
}
private void qSortRecursive(int[] data, int left, int right){
if(left < right){
int pivot = partition(data,left,right);
qSortRecursive(data,left,pivot-1);
qSortRecursive(data,pivot+1,right);
}
}
private int partition(int[] data, int left, int right){
int pivot = left ;
left++;
while (left <= right){
while (left <= right && data[left] <= data[pivot]) {
left++;
}
while (left <= right && data[right] >= data[pivot]){
right--;
}
if (left < right){
swap(data,left,right);
left++;
right--;
}
}
if (data[right] <= data[pivot]){
if (data[right] != data[pivot]){
swap(data,right,pivot);
}
pivot = right;
}
return pivot;
}
private void swap(int[] data, int i, int j){
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
private void qSortRecursive(int[] data, int left, int right){
while (left < right){
int pivot = partition(data,left,right);
if (pivot - left < right - pivot){
qSortRecursive(data, left, pivot - 1);
left = pivot + 1;
} else {
qSortRecursive(data, pivot + 1, right);
right = pivot - 1;
}
}
Performing a tail call by reducing number of recursion solved my problem, thanks for help everyone :)
You can try to rewrite the algorithm without recursion. Well, you remove recursion by adding your own stack and in that case you can have available the entire memory, not just size of stack.
Something like: http://alienryderflex.com/quicksort/
Firstly (as the question title implies) I'm not looking for why the bellow partitioning method doesn't work, rather a modification to it so that it will work for the following input:
int[] a = {1,2,8,4,5,7};
Here's the partition method along with some other stuff:
static int[] swap (int[] a,int i,int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
return a;
}
static int partition (int[] a,int l,int r){
int i = l;
int j = r;
int v = a[l];
while (true) {
while (a[i] < v) {
if (i == r) break;
i++;
}
while (a[j] > v) {
if (j == l) break;
j--;
}
if (i >= j) break;
a = swap(a,i,j);
}
a = swap(a, l, j);
return j;
}
void sort(int[] a,int l,int r){
int j = partition(a, l, r);
sort(a, l, j-1);
sort(a, j+1, r);
}
public static void main(String[] args) {
int[] a = {1,2,8,4,5,7};
System.out.println(partition(a,0,5));
}
Output:
0
The output is the index of the pivot returned from the partition method. 0, as the index of the pivot, makes sense in terms of the definition, i.e. everything left of the pivot is smaller and everything right of the pivot is larger, but clearly runs into a problem in sort namely:
sort(a, l, j-1);
where you have the right pointer being negative (j-1 = 0-1 = -1). My question again being is there a modification to the above method(s) that will maintain the definition (everything left of the pivot is smaller and everything right of the pivot is larger) and not run into the problem in sort.
The missing part is the line
if ( l >= r ) return;
in the beginning of the sort method. This is actually the recursion stop step so it is necessary to have it anyway to prevent endless recursion. But besides that, it also solves your problem, because if you call sort(0,-1) then -1 is less than 0, so it prevents further processing of that index.
I am trying to implement In-Place Quicksort, with the last element as my pivot. Attached below is my code
public static void main(String[] args){
int[] input = {3,2,4,6,10,1,9,7,5};
quickSort(input, 0, input.length-1);
}
public static void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static int partition(int arr[], int left, int right) {
int pivot = arr[right];
int high = right-1;
while(left < high){
while(arr[left] < pivot){
left++;
}
while(arr[high] > pivot){
high--;
}
swap(arr,left, high);
left++;
high--;
}
swap(arr, left, pivot);
System.out.println(Arrays.toString(arr));
return left;
}
public static void quickSort(int arr[], int left, int right) {
int index = partition(arr, left, right);
quickSort(arr, left, index - 1);
quickSort(arr, index, right);
}
For some reason, my code is giving me an IndexOutOfBounds Exception, and it does not accurately sort the array. I am not sure why I am getting this error.
If I understand correctly, we should make the last element our pivot. Then, we iterate the left pointer right, until we find an element greater than the pivot. After that, we do the same from the right side (keep moving left), until we find an element smaller than the pivot. Then we swap these elements and continue doing the same thing.
Finally, when the left/right pointer are the same, we swap the center value with our pivot.
Is this the correct way of thinking about it? And if so, what errors does my code have? Any help would be appreciated
A few errors:
Add left < high checks to your inner loops. You should check it every time you modify left or right.
Check arr[high] >= pivot not arr[high] > pivot.
swap(arr, left, pivot); is wrong. You should swap left with pivot using positions, not values. It should be swap(arr, left, right);.
You should check left < right in your quicksort method.
When you fix these errors, your code should look like this:
public static void main(String[] args){
int[] input = {3,2,4,6,10,1,9,7,5};
quickSort(input, 0, input.length-1);
}
public static void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static int partition(int arr[], int left, int right) {
int pivot = arr[right];
int high = right;
while(left < high){
while(left < high && arr[left] < pivot){
left++;
}
while(left < high && arr[high] >= pivot){
high--;
}
swap(arr,left, high);
}
swap(arr, left, right);
System.out.println( Arrays.toString(arr));
return left;
}
public static void quickSort(int arr[], int left, int right) {
if( left < right)
{
int index = partition(arr, left, right);
quickSort(arr, left, index - 1);
quickSort(arr, index, right);
}
}
Trace through this code on the assumption that the final array element is the smallest element. The loop to adjust high will continuously decrement high because each other array element is bigger than the pivot, so eventually high will drop off the front of the array, leading to your out of bounds access.
To fix this, add in another check in that loop to ensure you haven't had high and left cross. You may then need to add in some extra logic afterwards to handle that as a special case.