QuickSort Error Using First element as pivot - java

I have the following questions regarding my implementation of the code for the QuickSort Algorithm using the first element as the pivot always.
I have 2 sample files for my work and it seems that it does not work when given certain input. There appears to be a StackOverflowError on my recursion.
Is there something wrong with my code? Or is there something I'm missing out?
Input that work will be random integers x10000.
Input that will have error will be number 10000 - 1 in a decreasing manner.
Both inputs are via text files seperated by \n.
public void quickSortOne(Integer [] arr)
{
int first = 0;
int last = arr.length-1;
quickSort1(arr, first, last);
}
public void quickSort1(Integer [] arr, int first, int last)
{
if (arr == null || arr.length == 0)
return;
if (first >= last)
return;
//pick the pivot as first
//int middle = first + (last - first) / 2;
int pivot = arr[first];
//make left < pivot and right > pivot
int i = first, j = last;
while (i <= j) {
while (arr[i] < pivot) {
i++;
q1Comparison++;
}
while (arr[j] > pivot) {
j--;
q1Comparison++;
}
if (i <= j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
q1DataMove++;
}
}
//recursively sort two sub parts
if (first < j)
quickSort1(arr, first, j);
if (last > i)
quickSort1(arr, i, last);
}

You are running out of thread stack size due to default limit set by its OS. Especially for windows its very less (64KB).
Try running your app using below setting ->
java -Xss:512k myApp
You may also increase it to 1M or higher if needed. Here is the link to more info. Search for "Xss" on this page. ->
http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/optionX.html
Hope this helps!

Related

Why does this algorithm not sort the last index correctly?

I am supposed to write a version of the selection sort algorithm that moves the smallest number to the front of the array while simultaneously moving the largest number to the end of the array. I understand that it is basically working from both ends in so there are two sorted sub arrays, however my code seems to misplace the last number in the array. My code:
public static void dualSelectionSort(int[]a) {
for(int i=0; i<a.length-1;i++) {
int min=i;
int max=(a.length-1)-i;
for (int j=i+1;j<a.length-i;j++) {
if(a[j]<a[min]) {
min=j;
}
if(a[j]>a[max]) {
max=j;
}
}
int temp1=a[min];
int temp2=a[max];
a[min]=a[i];
a[max]=a[(a.length-1)-i];
a[i]=temp1;
a[(a.length-1)-i]=temp2;
}
}
If given the input [5,4,3,2,1], it outputs [1,2,5,3,4] instead of [1,2,3,4,5].
What am I missing?
The problem is in the inner loop.
It is starting from i+1.
So the code for comparing max is actually comparing a[1] to a[4].
you can change it as
for (int j=i;j<a.length-i;j++)
Also as you can read in comment there can be a case where with the above change the code will still not work.
This will happen because i == max and so the existing swap approach will not work.
For example:
assume array =[6,4,5],inner loop max =0,min=1.Existing swap will make it [4,6,6].
Hence,swap should be handled differently.
if(i==max) {
swap(a,max,a.length-1-i);
swap(a,min,i);
}else {
swap(a,min,i);
swap(a,max,(a.length-1)-i);
}
The complete code is as below:
public static void dualSelectionSort(int[]a) {
for(int i=0; i<a.length-1;i++) {
int min=i;
int max=(a.length-1)-i;
for (int j=i;j<a.length-i;j++) {
if(a[j]<a[min]) {
min=j;
}
if(a[j]>a[max]) {
max=j;
}
}
if(i==max) {
swap(a,max,a.length-1-i);
swap(a,min,i);
}else {
swap(a,min,i);
swap(a,max,(a.length-1)-i);
}
}
}
public static void swap(int[] a,int i,int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
In each iteration of the outer loop, you start with the first index (i) as the initial minimum index and the last index (a.length-1-i) as the initial maximum index. Then you compare both of these indices to all the indices in the range i+1 to a.length-i-1. But if the first index (i) actually contain the max value, you never compare it to a[max], so a[max] will never contain the correct value in the end of the inner loop.
Here's a suggested fix:
public static void dualSelectionSort(int[]a) {
for(int i = 0; i < a.length - i - 1; i++) {
if (a[i] > a[(a.length - 1) - i]) {
int temp = a[i];
a[i] = a[(a.length - 1) - i];
a[(a.length - 1) - i] = temp;
}
int min = i;
int max = (a.length - 1) - i;
for (int j = i + 1; j < (a.length -1 ) - i; j++) {
if(a[j] < a[min]) {
min = j;
}
if(a[j] > a[max]) {
max = j;
}
}
int temp1 = a[min];
int temp2 = a[max];
a[min] = a[i];
a[max] = a[(a.length - 1) - i];
a[i] = temp1;
a[(a.length - 1) - i] = temp2;
}
}
The three things I changed:
The outer loop can end much sooner than you end it - once i >= a.length-i-1 - since in each iteration you find the minimum and maximum value, so you reduce your remaining unsorted array by 2.
When initializing the min and max indices, make sure min index actually contains a value smaller the max index. If a[i] > a[(a.length-1)-i], swap them before setting min to i and max to (a.length-1)-i.
The inner loop should iterate j from i+1 to (a.length-1)-i-1.

Early min on quicksort in java

I have a problem I can't -quite- wrap my head around. I'm racing quicksort vs heapsort on one million integers. Each of the sorting algorithms divides the list into 32 threaded sub-sections and then sorts those, finally merging each sorted subsection back into a coherent whole (using more threads).
Rather than sorting the whole sub-array using quicksort and then pushing the whole thing out to the mergers, I'm trying to find a way to find the min value(s) using quicksort and push that before the whole section has been sorted. Since I don't actually have enough cores to concurrently run all my threads I expect the performance impact to be negligible, but I'd like to test that theory.
Time on my machine with 4 cores is about 14 seconds plus or minus two for both heapsort and quicksort. Speed seems to depend on which algorithm I run first, even though I'm shuffling after the sort.
Here's my quicksort code right now:
//code borrowed from http://stackoverflow.com/questions/19124752/non-
//recursive-quicksort
public synchronized void qSort(PipedOutputStream pout, int start, int sz) {
Deque<int[]> stack = new ArrayDeque<int[]>();
int first = start;
int last = start + sz - 1;
if(first >= arr.length || last >= arr.length){
System.out.printf("\nSorting error: parameters out of bounds! Start %d, end %d \n", start, last);
return;
}
stack.push(new int[] {first, last});
while(!stack.isEmpty()) {
qsortStep(arr, stack);
}
try { out = new ObjectOutputStream ( pout ); }
catch (IOException e ) { e.printStackTrace(); }
while ( size >= 1 ) {
try {
// System.out.printf("sort is writing %d to pipe.\n", v );
out.writeObject( arr[start] );
out.flush( );
start++; size--;
} catch(IOException e ) { e.printStackTrace(); }
}
}
private synchronized void qsortStep(T[] list, Deque<int[]> stack) {
if(stack.isEmpty())
return;
int temp[] = stack.pop();
int first = temp[0];
int last = temp[1];
int boundLo = first;
int boundHi = last;
//Pivot can be optimized to median of quintiles to mitigate O(n^2) on sorted arrays.
int pivot = last;
/*int sz = last - first;
int pivots[] = {first, first+sz/5, first+2*sz/5, first+4*sz/5, last};
for(int i = 0; i < 5; i++)
for(int j = 4; j > i; j--)
if(arr[pivots[i]].compareTo(arr[pivots[j]]) > 0)
swap(pivots, i, j);*/
pivot = last;
while(first < last) {
//possible opportunity here for early min
if(list[first].compareTo(list[pivot]) >= 0) {
last--;
if(first != last)
swap(list, first, last);
swap(list, last, pivot);
pivot--;
}
else first++;
}
if(boundLo < (pivot - 1))
stack.add(new int[] {boundLo, pivot - 1});
if(boundHi > (pivot + 1))
stack.add(new int[] {pivot + 1, boundHi});
}

big difference in time between two Implementation of quick Sort

I have two implementation of quick sort the first one uses a median of (fist ,middle , last ) as pivot and the second uses the middle element as pivot
the first Implementation :
public class quickMedian {
public void sort(int array[])
// pre: array is full, all elements are non-null integers
// post: the array is sorted in ascending order
{
quickSort(array, 0, array.length - 1); // quicksort all the elements in the array
}
public void quickSort(int array[], int start, int end)
{
int i = start; // index of left-to-right scan
int k = end; // index of right-to-left scan
if (end - start >= 1) // check that there are at least two elements to sort
{
if (array[start+(end-start)/2]>array[end]){
swap(array,start+(end-start)/2, end);
}
if (array[start]>array[end]){
swap(array,start, end);
}
if (array[start+(end-start)/2]>array[start]){
swap(array, start+(end-start)/2, start);
}
int pivot = array[start]; // set the pivot as the first element in the partition
while (k > i) // while the scan indices from left and right have not met,
{
while (array[i] <= pivot && i <= end && k > i) // from the left, look for the first
i++; // element greater than the pivot
while (array[k] > pivot && k >= start && k >= i) // from the right, look for the first
k--; // element not greater than the pivot
if (k > i) // if the left seekindex is still smaller than
swap(array, i, k); // the right index, swap the corresponding elements
}
swap(array, start, k); // after the indices have crossed, swap the last element in // the left partition with the pivot
quickSort(array, start, k - 1); // quicksort the left partition
quickSort(array, k + 1, end); // quicksort the right partition
}
else // if there is only one element in the partition, do not do any sorting
{
return; // the array is sorted, so exit
}
}
public void swap(int array[], int index1, int index2)
// pre: array is full and index1, index2 < array.length
// post: the values at indices 1 and 2 have been swapped
{
int temp = array[index1]; // store the first value in a temp
array[index1] = array[index2]; // copy the value of the second into the first
array[index2] = temp; // copy the value of the temp into the second
}
}
The second Implementation :
public class quickSort {
private int array[];
private int length;
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
length = inputArr.length;
quickSorter(0, length - 1);
}
private void quickSorter(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
// calculate pivot number, I am taking pivot as middle index number
int pivot = array[lowerIndex+(higherIndex-lowerIndex)/2];
// Divide into two arrays
while (i <= j) {
/**
* In each iteration, we will identify a number from left side which
* is greater then the pivot value, and also we will identify a number
* from right side which is less then the pivot value. Once the search
* is done, then we exchange both numbers.
*/
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchangeNumbers(i, j);
//move index to next position on both sides
i++;
j--;
}
}
// call quickSort() method recursively
if (lowerIndex < j)
quickSorter(lowerIndex, j);
if (i < higherIndex)
quickSorter(i, higherIndex);
}
private void exchangeNumbers(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
To obtain the median we need to do extra steps on each recursion which may increase the time a little bit (if the array is totally random) .
I am testing these two classes on an array of size N=10,000,000 randomly generated and I have done the test many times the first Implementation takes around 30 seconds and the second takes around 4 seconds
so this is obviously not caused by the extra overhead to get the median of three numbers .
There must be something wrong with the first implementation, what is it ?
here is the testing code :
public static void main(String[] args) {
File number = new File ("f.txt");
final int size = 10000000;
try{
// quickSort s = new quickSort();
quickMedian s = new quickMedian();
writeTofile(number, size);
int [] arr1 =readFromFile(number, size);
long a=System.currentTimeMillis();
s.sort(arr1);
long b=System.currentTimeMillis();
System.out.println("quickSort: "+(double)(b-a)/1000);
}catch (Exception ex){ex.printStackTrace();}
}

Using quicksort on a string array

I'm a programming student and rather than post the whole assignment I'll just ask for help solving what I've tried for hours now to understand. I'm tasked with sorting an array of strings using the quicksort method. Everything else I've been tasked with as part of this problem is fine but when I tested the sorting method by printing out the String Array, it's completely jumbled up without any seeming rhyme or reason. Please help me pinpoint the error in my code, or the several glaring errors I've overlooked. The array of strings provided is this list of 65 names: http://pastebin.com/jRrgeV1E and the method's code is below:
private static void quickSort(String[] a, int start, int end)
{
// index for the "left-to-right scan"
int i = start;
// index for the "right-to-left scan"
int j = end;
// only examine arrays of 2 or more elements.
if (j - i >= 1)
{
// The pivot point of the sort method is arbitrarily set to the first element int the array.
String pivot = a[i];
// only scan between the two indexes, until they meet.
while (j > i)
{
// from the left, if the current element is lexicographically less than the (original)
// first element in the String array, move on. Stop advancing the counter when we reach
// the right or an element that is lexicographically greater than the pivot String.
while (a[i].compareTo(pivot) < 0 && i <= end && j > i){
i++;
}
// from the right, if the current element is lexicographically greater than the (original)
// first element in the String array, move on. Stop advancing the counter when we reach
// the left or an element that is lexicographically less than the pivot String.
while (a[j].compareTo(pivot) > 0 && j >= start && j >= i){
j--;
}
// check the two elements in the center, the last comparison before the scans cross.
if (j > i)
swap(a, i, j);
}
// At this point, the two scans have crossed each other in the center of the array and stop.
// The left partition and right partition contain the right groups of numbers but are not
// sorted themselves. The following recursive code sorts the left and right partitions.
// Swap the pivot point with the last element of the left partition.
swap(a, start, j);
// sort left partition
quickSort(a, start, j - 1);
// sort right partition
quickSort(a, j + 1, end);
}
}
/**
* This method facilitates the quickSort method's need to swap two elements, Towers of Hanoi style.
*/
private static void swap(String[] a, int i, int j)
{
String temp = a[i];
a[i] = a[j];
a[j] = temp;
}
Ok, i was mistaken that it would work and found your tiny mistake.
Take a look at wikipedias pseudo code
You will notice that your conditions in the while loop are causing the error
if you change (a[i].compareTo(pivot) < 0 && i <= end && j > i) and (a[j].compareTo(pivot) > 0 && j >= start && j >= i) to
(a[i].compareTo(pivot) <= 0 && i < end && j > i) and (a[j].compareTo(pivot) >= 0 && j > start && j >= i).
Thought this would help for those who seek for a string sorting algorithm based on quick sorting method.
public class StringQuickSort {
String names[];
int length;
public static void main(String[] args) {
StringQuickSort sorter = new StringQuickSort();
String words[] = {"zz", "aa", "cc", "hh", "bb", "ee", "ll"}; // the strings need to be sorted are put inside this array
sorter.sort(words);
for (String i : words) {
System.out.print(i);
System.out.print(" ");
}
}
void sort(String array[]) {
if (array == null || array.length == 0) {
return;
}
this.names = array;
this.length = array.length;
quickSort(0, length - 1);
}
void quickSort(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
String pivot = this.names[lowerIndex + (higherIndex - lowerIndex) / 2];
while (i <= j) {
while (this.names[i].compareToIgnoreCase(pivot) < 0) {
i++;
}
while (this.names[j].compareToIgnoreCase(pivot) > 0) {
j--;
}
if (i <= j) {
exchangeNames(i, j);
i++;
j--;
}
}
//call quickSort recursively
if (lowerIndex < j) {
quickSort(lowerIndex, j);
}
if (i < higherIndex) {
quickSort(i, higherIndex);
}
}
void exchangeNames(int i, int j) {
String temp = this.names[i];
this.names[i] = this.names[j];
this.names[j] = temp;
}
}

finding 1D peak of a given array

I am writing the code for peak finding algorithm for a 1D array. I have read this post Peak finding algorithm. This is exactly what I am trying to do, there is discussion about time complexity but nothing of sort of pseudocode. The problem:
Given an array [a,b,c,d,e,f,g] where a to g are numbers, b is a peak if and only if a<=b and b>=c.
Example: given an array {1,2,3,4,5,19,25,20}, index 6 should be returned.
The edge cases should give:
{100,4,3,1,19,20} -- index 0
{1,3,5,19,20} -- index 4
I have implemented in Java. my current run-time is O(n). I am wondering if this could be improved
public static int naive(int[] arr){
int l=arr.length;
if (arr[0]>=arr[1]) {
return 0;
}
if (arr[l-1]>arr[l-2]){
return l-1;
}
for (int i=1; i < arr.length-1;i++){
if (arr[i] >= arr[i-1] && arr[i] >= arr[i+1] ){
return i;
}
}
return -1;
}
The following function is probably a tiny bit more efficient than yours. Note that this will find a local maximum.
public static int findLocalMaximum(int[] arr){
int i = 0;
while(i + 1 < arr.length && arr[i+1] >= arr[i]) {
++i;
}
return i;
}
Edit: The following function finds peaks as defined in the question. Note that I removed the boundary check in the while loop, as the loop will only be reached if arr[l-2] > arr[l-1], an so the condition in the while loop will be false and l-2 will be returned.
public static int findPeak(int[] arr){
int l = arr.length;
if(arr[0] >= arr[1]) {
return 0;
}
if(arr[l-1] >= arr[l-2]) {
return l-1;
}
int i = 1;
while(arr[i+1] > arr[i]) {
++i;
}
return i;
}
If I may propose my solution:
public static int findPeak(int[] array, int start, int end) {
int index = start + (end - start) / 2;
if (index - 1 >= 0 && array[index] < array[index - 1]) {
return findPeak(array, start, index - 1);
} else if (index + 1 <= array.length - 1 && array[index] < array[index + 1]) {
return findPeak(array, index + 1, end);
} else {
return array[index];
}
}
I think it is simpler to handle edge cases directly in the if statements. I also tested with a couple of inputs and it seems to work.
A binary search-like algorithm should work. That employs divide and conquer strategy. since you are interested in single peak, the best you can do is O(log n). But if you want to find all peaks, it will be O(n) atleast.
Here is the divide-and conquer algorithm:
public static int peak1D(int[] arr, int start, int end){
//edge cases
if (end-start==1){
if (start==0)
return start;
else
return end;
}
int i = start+end>>>1;
if (arr[i]<arr[i-1])
return peak1D(arr,start,i);
if (arr[i]<arr[i+1]){
return peak1D(arr, i, end);
}
else
return i;
}
I tested with a couple of inputs and it seems to work. my handling of edge cases is not great. though it is simple reasoning
Assume Array is global for simplicity you can pass it if you want.
private static int getPeak1D(int start,int end)
{
int x = (start+end)/2;
if( (x == 0 && array[x] >= array[x+1]) ||
(x == array.length-1 && array[x]>=array[x-1]) ||
(x>0 && x< array.length-1 && array[x] >= array[x-1] && array[x] >= array[x+1]))
return x;
if(x+1 < array.length && array[x] < array[x+1])
temp = getPeak1D(x+1,end);
if(temp > -1)
return temp;
if(x-1 > -1 && array[x] < array[x-1])
return getPeak1D(0,x-1);
else
return -1;
}
The First if check first edge, second edge, and inner part for peaks.
if no peaks are found, if array[x+1] > array[x], The Second if will go to the right half of the array. we store it in temp (i have it as global) we dont return it because in case both array[x+1] and array[x-1] are both bigger than array[x] but the right side didn't find any peaks you should go to the third if to check the left side
Check this for the logic behind it
https://courses.csail.mit.edu/6.006/spring11/rec/rec02.pdf

Categories

Resources