I am having problems with my merge sort code. Each time I run it I encounter a problem with a IndexOutOfBounds Exception, but I can't seem to figure out why... this is the code produced by our professor (who has been known to make mistakes)... anyone spot the problem
public static <T extends Comparable<T>> void mergeSort(T[] array, int first, int last)
{
if(first<last)
{
int mid = (first+last)/2;
mergeSort(array, first, mid);
mergeSort(array, mid+1, last);
merge(array, first, mid, last);
}
}
public static <T extends Comparable<T>> void mergeSort(T[] array, int last)
{
int first = 0;
if(first<last)
{
int mid = (first+last)/2;
mergeSort(array, first, mid);
mergeSort(array, mid+1, last);
merge(array, first, mid, last);
}
}
public static <T extends Comparable<T>> void merge(T[] array, int first, int mid, int last)
{
int maxSize = array.length;
T[] tempA = (T[]) new Comparable[maxSize];
int first1 = first;
int last1 = mid;
int first2 = mid+1;
int last2 = last;
int index = first1;
while((first1<=last1) && (first2<=last2))
{
if(array[first1].compareTo(array[first2])<0)
{
tempA[index] = array[first1];
first1++;
}
else
{
tempA[index] = array[first2];
first2++;
}
index++;
}
while(first1<=last1)
{
tempA[index]=array[first1];
first1++;
index++;
}
while(first2<=last2)
{
tempA[index]=array[first2];
first2++;
index++;
}
for(index=first; index<=last;++index)
{
array[index]=tempA[index];
}
}
Reading your code, its seems that the last variable is used as an index in your code.
That's why you can't pass it as a size to your mergeSort method, you have to pass array.length - 1.
array.length is the size of the array
array.length - 1 is the last index of the array
Related
I need to write a algorithm to sort a collection, more than 10, 000, 000 elements.
So I write a forkjoin quick sort...
But when the input become bigger, the code collapses.
Firstly, I use the test cases is a random list, implements can handle.
Then, I just try some extremely cases, just as a ordered numbers. Code fails.
I check the code, but have no idea of why.
This is code below:
public class ForkJoinSort {
private static int THRESHOLD = 1000;
private static ForkJoinPool pool = new ForkJoinPool();
public static <T extends Comparable<T>> void quickSortFJ(List<T> rawList) {
pool.invoke(new QuickSort<>(rawList));
}
static class QuickSort<T extends Comparable<T>> extends RecursiveAction {
List<T> rawList;
int lo;
int hi;
QuickSort(List<T> rawList) {
this.rawList = rawList;
this.lo = 0;
this.hi = rawList.size() - 1;
}
QuickSort(List<T> rawList, int lo, int hi) {
this.rawList = rawList;
this.lo = lo;
this.hi = hi;
}
#Override
protected void compute() {
if (hi > lo && hi - lo >= THRESHOLD) {
int pivot = partition(rawList, lo, hi);
invokeAll(new QuickSort<>(rawList, lo, pivot - 1),
new QuickSort<>(rawList, pivot + 1, hi));
} else {
quickSort(rawList, lo, hi);
}
}
}
private static <T extends Comparable<T>> int partition(List<T> rawList, int lo, int hi) {
T key = rawList.get(hi);
int index = lo;
for (int i=lo; i<hi; i++) {
if (rawList.get(i).compareTo(key) > 0) {
swap(rawList, index, i);
index ++;
}
}
swap(rawList, index, hi);
return index;
}
private static <T extends Comparable<T>> void swap(List<T> rawList, int left, int right) {
if (left != right) {
T temp = rawList.get(left);
rawList.set(left, rawList.get(right));
rawList.set(right, temp);
}
}
public static <T extends Comparable<T>> void quickSort(List<T> rawList, int lo, int hi) {
if (lo < hi) {
int pivot = partition(rawList, lo, hi);
quickSort(rawList, lo, pivot-1);
quickSort(rawList, pivot+1, hi);
}
}
}
Test case failed:
List<Long> longTwoList = new ArrayList<>();
for (long i=0; i!=17000; i++) {
longTwoList.add(i);
}
ForkJoinSort.quickSortFJ(longTwoList);//failed
ForkJoinSort.quickSort(longTwoList, 0, longTwoList.size()-1);//falied
Quite confused with this problem. Thank you for replying.
I tried and wrote a code for Quicksort with middle element as pivot.
I was successful in writing one.
But Pivot has the property that:
Elements on its left are lesser than pivot and greater on its right.
I was not able to achieve this in my following code.
private static void QuickSortAlgorithm(int[] a, int i, int n)
{
if(i<n)
{
int part = partition(a,i,n);
QuickSortAlgorithm(a, i, part-1);
QuickSortAlgorithm(a, part, n);
}
}
private static int partition(int[] a, int i, int n)
{
int pivot = (i+n)/2;
int left = i;
int right = n;
while(left<=right)
{
while(a[left]<a[pivot]){
left++;
}
while(a[right]>a[pivot])
{
right--;
}
if(left<=right)
{
swap(a,left,right);
left++;
right--;
}
}
return left;
}
Main Method:
int a[]={5,7,3,9,1};
int n = a.length;
QuickSortAlgorithm(a,0,n-1);
System.out.println(Arrays.toString(a));
My doubt is:
I am sending left as my partitioned index.
But, when I am recursively calling QuickSortAlgorithm()
I am sending i to part-1 and part to n;
What should I send as partition index so that
I could call something like this: So that pivot property is satisfied?
QuickSortAlgorithm(a, i, part-1);
QuickSortAlgorithm(a, part+1, n);
Thank you:)
you have to send pivot value in first stack call inclusive and pivot+1 as lower index for second stack call.
You also have to put value of left as i+1 then your code will give an correct output
You have to change the return value to left+1 in partition method.
Try this program:
import java.io.*;
public class QuickSort {
public int partion(int[] a, int l, int h) {
int middle = (h+l)/2;
//System.out.println(middle);
int pivot = a[middle];
int i = l;
int j = h;
while (i <= j) {
while (a[i] < pivot) i++;
while (a[j] > pivot) j--;
if (i <= j) {
swap(a, i, j);
i++;
j--;
}
}
// swap(a,i,j);
System.out.println((i+j)/2);
return i-1;
}
public void quick(int[] a, int l, int h) {
if (l<h) {
int pi = partion(a, l, h);
System.out.println(pi);
if (l < pi - 1)
quick(a, l, pi+1);
if (pi < h)
quick(a, pi+1, h);
}
}
public void swap(int[] a, int l, int h){
int temp=a[l];
a[l]=a[h];
a[h]=temp;
}
public static void main(String[] args) {
int[] a = {10,80,30,90,40,50,70};
int l=0;
int h=a.length-1;
QuickSort q =new QuickSort();
q.quick(a,0,h);
System.out.println(" Sorted Array : ");
for(int e :a){
System.out.print(e+" , ");
}
}
}
You can choose the leftmost element in the array or you can choose any random element to be your pivot.
Check out the wikipedia page on quicksort for more details about choosing pivot
I've been banging my head on the table on this one.
I need to create an n sized array that is optimized for QuickSort Partition. It will be used to demonstrate the growth of QuickSort's best case. I know that for best case, QuickSort must select a pivot that divides the array in half for every recursive call.
I cannot think of a way to create an n-sized optimized array to test. Any help would be greatly appreciated.
Here is the algorithm in Java.
public class QuickSort {
private int length;
private void quickSort(int[] a, int p, int r) {
if (p < r) {
int q = partition(a, p, r);
quickSort(a, p, q - 1);
quickSort(a, q + 1, r);
}
}
private int partition(int[] a, int p, int r) {
int x = a[r];
int i = p - 1;
for (int j = p; j < r; j++) {
if (a[j] <= x) {
i++;
exchange(a, i, j);
}
}
exchange(a, i + 1, r);
return i + 1;
}
public void exchange(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
QuickSort(int[] a) {
if (a == null || a.length == 0) {
return;
}
length = a.length;
quickSort(a, 0, length - 1);
}
}
I know this is an old question, but I had the same question and finally developed a solution. I'm not a Java programmer, so don't blame me for Java code issues, please. I assumed that the quicksort algorithm always takes the first item as a pivot when partitioning.
public class QuickSortBestCase
{
public static void generate(int[] arr, int begin, int end)
{
int count = end - begin;
if(count < 3)
return;
//Find a middle element index
//This will be the pivot element for the part of the array [begin; end)
int middle = begin + (count - 1) / 2;
//Make the left part best-case first: [begin; middle)
generate(arr, begin, middle);
//Swap the pivot and the start element
swap(arr, begin, middle);
//Make the right part best-case, too: (middle; end)
generate(arr, ++middle, end);
}
private static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
private static void fillArray(int[] arr)
{
for(int i = 0; i != arr.length; ++i)
arr[i] = i + 1;
}
private static void printArray(int[] arr)
{
for(int item : arr)
System.out.print(item + " ");
}
public static void main(String[] args)
{
if(args.length == 0)
return;
int intCount = Integer.parseInt(args[0]);
int[] arr = new int[intCount];
//We basically do what quicksort does in reverse
//1. Fill the array with sorted values from 1 to arr.length
fillArray(arr);
//2. Recursively generate the best-case array for quicksort
generate(arr, 0, arr.length);
printArray(arr);
}
}
This program produces the same output for the array of 15 items, as described here: An example of Best Case Scenario for Quick Sort. And in case someone needs a solution in C++:
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case_sorted(RandomIterator begin, RandomIterator end)
{
auto count = std::distance(begin, end);
if (count < 3)
return;
auto middle_index = (count - 1) / 2;
auto middle = begin + middle_index;
//Make the left part best-case first
generate_quicksort_best_case_sorted(begin, middle);
//Swap the pivot and the start element
std::iter_swap(begin, middle);
//Make the right part best-case, too
generate_quicksort_best_case_sorted(++middle, end);
}
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case(RandomIterator begin, RandomIterator end)
{
{
auto current = begin;
RandomIterator::value_type value = 1;
while (current != end)
*current++ = value++;
}
generate_quicksort_best_case_sorted(begin, end);
}
I am trying to modify a Quicksort program that used the first element as pivot to a Quicksort that uses the median of three (median of first, last and middle element) as pivot. My implementation thus far is however giving me ArrayIndexOutOfBoundsException(s) when testing it.
I guess I am missing something here, but I just can't figure out where I'm wrong. Any help and advice is highly appreciated.
public class Sorts {
private static void swap(int[] array, int index1, int index2) {
// Precondition: index1 and index2 are >= 0 and < SIZE.
//
// Swaps the integers at locations index1 and index2 of the values array.
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
private static int medianOfThree(int[] array, int first, int last) {
int mid = array[(first+last)/2];
if (array[first] > array[mid]) {
swap(array, first, mid);
}
if (array[first] > array[last]) {
swap(array, first, last);
}
if (array[mid] > array[last]) {
swap(array, mid, last);
}
swap(array, mid, last-1);
return array[last-1];
}
private static int partition(int[] array, int first, int last, int median) {
int pivot = array[last-1];
int saveF = last-1;
boolean onCorrectSide;
first++;
do {
onCorrectSide = true;
while (onCorrectSide) { // move first toward last
if (array[first] > pivot) {
onCorrectSide = false;
}
else {
first++;
onCorrectSide = (first <= last);
}
}
onCorrectSide = (first <= last);
while (onCorrectSide) { // move last toward first
if (array[last] <= pivot) {
onCorrectSide = false;
}
else {
last--;
onCorrectSide = (first <= last);
}
}
if (first < last) {
swap(array, first, last);
first++;
last--;
}
} while (first <= last);
swap(array, saveF, last);
return last;
}
private static void quickSort(int[] array, int first, int last) {
if (first < last) {
int pivot;
int median = medianOfThree(array, first, last);
pivot = partition(array, first, last, median);
// values[first]..values[splitPoint - 1] <= pivot
// values[splitPoint] = pivot
// values[splitPoint+1]..values[last] > pivot
quickSort(array, first, pivot - 1);
quickSort(array, pivot + 1, last);
}
}
public static void quickSort(int[] array) {
quickSort(array, 0, array.length-1);
}
}
you are not using the variable in the right way:
int mid = array[first+last/2];
gives you the value in mid of the array, but not the offset (index) of the array.
But you are using mid, as index variable in your calls of the methods:
swap(array, first, mid);
I am implementing a quicksort algorithm and have succesfully partitioned the input array around a pivot. The problem is, I am confused in how to recursively sort the 1st part and 2nd part of the array (i.e specifying the range) using the same input array.
Below is my implementation
class QuickSort {
int i;
int l = 0;
public void quicksort(int A[], int n) {
if (n == 1) {
return;
} else {
partition(A, 0, n);
//----Confused as from this point
quicksort(A, A[i]);
//Recursively sort both parts of the array
}
}
public int partition(int A[], int l, int r) {
int p = A[l];//Choose pivot
i = l + 1;
//Partition around A through P
for (int j = i; j < r; j++) {
if (A[j] < p) {
swap(A, i, j);
++i;
}
}
swap(A, l, i - 1 );
return i;
}
public void swap(int A[], int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public void display(int A[]){
for (int i = 0; i < A.length; i ++){
System.out.print(A[i] + " ");
}
}
}
class QuickSortApp{
public static void main(String args[]){
QuickSort quick = new QuickSort();
int A[] = {6,2,7,8,4,3,5};
quick.quicksort(A, A.length);
quick.display(A);
}
}
Please, I would also appreciate being corrected on any other inefficencies in my algorithm. Thanks
Change your quicksort() signature to quicksort(int[] A, int begin, int end)
Since, you actually did the sorting inside partition(). What I would do is this:
if (end-begin <= 1) {
return;
} else {
int pivot = partition(A, begin, end);
quicksort(A, begin, pivot);
quicksort(A, pivot, end);
}
Create a wrapper for the quicksort call with the signature you have which calls another one like quicksort(A, i, j) and your call from the wrapper will be quicksort(A, 0, n).