Quick Sort algorithm not working properly - java

I have created a code for quick sorting the only problem is that sometimes it gives out the sorted array and sometimes it doesn't. Any idea as to why it would do that? The first part of always works obviously.. the part where it shows the array TO BE sorted but the next part shows up occasionally after I run it a lot of time.
This is part of my code:
public static final int max = 10;
public static void main(String[] args) {
int[] toSortArray = new int[max];
for (int i = 0; i < max; i++) {
toSortArray[i] = (int) (Math.random() * 100);
}
System.out.println("The array to be sorted is:");
for (int i = 0; i < max; i++) {
System.out.print(" | " + toSortArray[i]);
}
System.out.println(" | ");
// Beginning of the algorithm
quicksortHelper(toSortArray, 0, max - 1);
// End of the algorithm
System.out.println("The sorted array is: ");
for (int i = 0; i < max; i++) {
System.out.print(" | " + toSortArray[i]);
}
System.out.println(" | ");
}
private static void quicksortHelper(int[] toSortArray, int first, int last) {
if (first < last) {
int splitpoint = partition(toSortArray, first, last);
quicksortHelper(toSortArray, first, splitpoint - 1);
quicksortHelper(toSortArray, splitpoint + 1, last);
}
}
private static int partition(int[] toSortArray, int first, int last) {
int pivot = toSortArray[first];
int leftmark = first + 1;
int rightmark = last;
boolean done = true;
while (done) {
while (leftmark <= rightmark && toSortArray[leftmark] < pivot) {
leftmark++;
}
while (leftmark <= rightmark && toSortArray[rightmark] > pivot) {
rightmark--;
}
if (leftmark > rightmark) {
done = false;
} else {
int temp = toSortArray[leftmark];
toSortArray[leftmark] = toSortArray[rightmark];
toSortArray[rightmark] = temp;
}
}
int temp = toSortArray[rightmark];
toSortArray[rightmark] = toSortArray[first];
toSortArray[first] = temp;
return rightmark;
}

This is a program that I have written from your code and it works great
class QuickSort{
public static final int max = 10;
public static void main(String[] args) {
int[] toSortArray = new int[max];
for (int i = 0; i < max; i++) {
toSortArray[i] = (int) (Math.random() * 100);
}
System.out.println("The array to be sorted is:");
for (int i = 0; i < max; i++) {
System.out.print(" | " + toSortArray[i]);
}
System.out.println(" | ");
// Beginning of the algorithm
quicksortHelper(toSortArray, 0, max - 1);
// End of the algorithm
System.out.println("The sorted array is: ");
for (int i = 0; i < max; i++) {
System.out.print(" | " + toSortArray[i]);
}
System.out.println(" | ");
}
private static void quicksortHelper(int[] toSortArray, int first, int last) {
if (first < last) {
int splitpoint = partition(toSortArray, first, last);
quicksortHelper(toSortArray, first, splitpoint - 1);
quicksortHelper(toSortArray, splitpoint + 1, last);
}
}
private static int partition(int[] array, int first, int last) {
int temp;
// Always assumes pivot index is first
int pivot = array[first];
// Swap Pivot and Last
array[first] = array[last];
array[last] = pivot;
int mark = first;
for(int i=first;i<last;i++){
if(array[i] <= pivot){
temp = array[mark];
array[mark] = array[i];
array[i] = temp;
mark++;
}
}
temp = array[last];
array[mark] = array[last];
array[last] = temp;
return mark;
}
}

Try changing either
while (leftmark <= rightmark && toSortArray[leftmark] < pivot) {
leftmark++;
}
to
while (leftmark <= rightmark && toSortArray[leftmark] <= pivot) {
leftmark++;
}
or,
while (leftmark <= rightmark && toSortArray[rightmark] > pivot) {
rightmark--;
}
to
while (leftmark <= rightmark && toSortArray[rightmark] >= pivot) {
rightmark--;
}
(That is, change the < to <= or > to >=.)
This will ensure that it doesn't quit when it comes to a non-unique value.

Related

Finding sorted subarrays in array

I am working on sorting algorithms and I am trying to improve mergeSort by locating already sorted subArrays.
public static void mergeSort(int[] array)
{
if(array == null)
{
return;
}
if(array.length > 1)
{
int mid = array.length / 2;
// left
int[] left = new int[mid];
for(int i = 0; i < mid; i++)
{
left[i] = array[i];
}
//right
int[] right = new int[array.length - mid];
for(int i = mid; i < array.length; i++)
{
right[i - mid] = array[i];
}
//recursively calls
mergeSort(left);
mergeSort(right);
int i = 0;
int j = 0;
int k = 0;
// left and right merged
while(i < left.length && j < right.length)
{
if(left[i] < right[j])
{
array[k] = left[i];
i++;
}
else
{
array[k] = right[j];
j++;
}
k++;
}
// left overs
while(i < left.length)
{
array[k] = left[i];
i++;
k++;
}
while(j < right.length)
{
array[k] = right[j];
j++;
k++;
}
}
}
What you are looking for is called natural merge sort. Before you start with sorting the dataset you will do one run to identify all the presorted data. The mergesort itself stays the same.
I found some example code for you at: happycoders
package eu.happycoders.sort.method.mergesort;
import eu.happycoders.sort.method.Counters;
import eu.happycoders.sort.method.SortAlgorithm;
/**
* Natural merge sort implementation for performance tests.
*
* #author Sven Woltmann
*/
public class NaturalMergeSort implements SortAlgorithm {
#Override
public void sort(int[] elements) {
int numElements = elements.length;
int[] tmp = new int[numElements];
int[] starts = new int[numElements + 1];
// Step 1: identify runs
int runCount = 0;
starts[0] = 0;
for (int i = 1; i <= numElements; i++) {
if (i == numElements || elements[i] < elements[i - 1]) {
starts[++runCount] = i;
}
}
// Step 2: merge runs, until only 1 run is left
int[] from = elements;
int[] to = tmp;
while (runCount > 1) {
int newRunCount = 0;
// Merge two runs each
for (int i = 0; i < runCount - 1; i += 2) {
merge(from, to, starts[i], starts[i + 1], starts[i + 2]);
starts[newRunCount++] = starts[i];
}
// Odd number of runs? Copy the last one
if (runCount % 2 == 1) {
int lastStart = starts[runCount - 1];
System.arraycopy(from, lastStart, to, lastStart,
numElements - lastStart);
starts[newRunCount++] = lastStart;
}
// Prepare for next round...
starts[newRunCount] = numElements;
runCount = newRunCount;
// Swap "from" and "to" arrays
int[] help = from;
from = to;
to = help;
}
// If final run is not in "elements", copy it there
if (from != elements) {
System.arraycopy(from, 0, elements, 0, numElements);
}
}
private void merge(int[] source, int[] target, int startLeft,
int startRight, int endRight) {
int leftPos = startLeft;
int rightPos = startRight;
int targetPos = startLeft;
// As long as both arrays contain elements...
while (leftPos < startRight && rightPos < endRight) {
// Which one is smaller?
int leftValue = source[leftPos];
int rightValue = source[rightPos];
if (leftValue <= rightValue) {
target[targetPos++] = leftValue;
leftPos++;
} else {
target[targetPos++] = rightValue;
rightPos++;
}
}
// Copy the rest
while (leftPos < startRight) {
target[targetPos++] = source[leftPos++];
}
while (rightPos < endRight) {
target[targetPos++] = source[rightPos++];
}
}
#Override
public void sort(int[] elements, Counters counters) {
// Not implemented
}
}

Finding contiguous array

I am trying to get an output of [4,6,6,7] with length 4 where arr[i] <= arr[i+1] where it is non-decreasing and it is contiguous. I know what i have to do but i dont know how to do it. my code prints out [3,4,6,6,7]. I am just having trouble on the contiguous part, any help? im not allowed to use extra arrays.
public static void ascentLength(int arr[], int size) {
int length = 0;
int index = 0;
int count = 1;
for (int i = 0; i < size-1; i++) {
index = i;
if (arr[0] <= arr[i+1] && count >0) {
System.out.println(arr[i]+ " index:" + index);
length++;
count++;
}
if (arr[0] >= arr[i+1]) {
}
}
System.out.println("length: " + length);
}
/* Driver program to test above function */
public static void main(String[] args) {
int arr[] = {5, 3, 6, 4, 6, 6, 7, 5};
int n = arr.length;
ascentLength(arr, n);
}
Here is my solution, it would be easier, if you could work with List, but this works for arrays:
public static void ascentLength(int arr[], int size) {
if(size == 1) System.out.println("length: 1");
// variables keeping longest values
int longestStartingIndex = 0;
int longestLength = 1;
// variables keeping current values
int currentStartingIndex = 0;
int currentCount = 1;
for (int i = 1; i < size; i++) {
if (arr[i-1] <= arr[i]) {
currentCount++;
} else {
// check if current count is the longest
if(currentCount > longestLength) {
longestLength = currentCount;
longestStartingIndex = currentStartingIndex;
}
currentStartingIndex = i;
currentCount = 1;
}
}
if(currentCount > longestLength) {
longestLength = currentCount;
longestStartingIndex = currentStartingIndex;
}
}

Quicksort by length of String in Array

I have strings scanned from the user. Next step is to sort array by the length of text, I don't know what I'm doing wrong, sometimes it's working.
public static void quickSort(String[] subtitles, int start, int end) {
int i = start;
int j = end;
if (j - i >= 1) {
String pivot = subtitles[i];
while (j > 1) {
while (subtitles[i].compareTo(pivot) <= 0 && i < end && j > i)
i++;
while (subtitles[j].compareTo(pivot) >= 0 && j > start && j >= i)
j--;
if (j > i)
swap(subtitles, i, j);
}
swap(subtitles, start, j);
quickSort(subtitles, start, j - 1);
quickSort(subtitles, j + 1, end);
} else
return;
}
public static void swap(String[] a, int i, int j) {
String tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int amountStrings = 3;
String[] subtitles = new String[amountStrings];
System.out.println("insert ");
for (int i = 0; i < amountStrings; i++) {
subtitles[i] = scan.next();
}
System.out.println("--------");
quickSort(subtitles, 0, subtitles.length - 1);
for (int i = 0; i < subtitles.length; i++) {
System.out.print(subtitles[i] + " ");
}
Incorrect:
In:
asdzxc asd zxc
Out:
asd asdzxc zxc
Correct:
In:
sdf sdfsfwer s
Out:
s sdf sdfsfwer
Ok, I reviewed your code and made two new methods. One sorts the array alphabetically and one sorts by counting the number of letters in each word of the array. It is up to you what methods fits you well.
Tested and working.
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Subtitles {
public static void sortAlfabetical(String x[]) {
int j;
boolean found = true; // will determine when the sort is finished
String temp;
while (found) {
found = false;
for (j = 0; j < x.length - 1; j++) {
if (x[j].compareToIgnoreCase(x[j + 1]) > 0) { // ascending sort
temp = x[j];
x[j] = x[j + 1]; // swap
x[j + 1] = temp;
found = true;
}
}
}
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + " ");
}
}
public static void compare(String[] arrayOne) {
Arrays.sort(arrayOne, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
for (String s : arrayOne) {
System.out.print(s + " ");
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int amountStrings = 3;
String[] subtitles = new String[amountStrings];
System.out.println("insert ");
for (int i = 0; i < amountStrings; i++) {
subtitles[i] = scan.next();
}
System.out.println("--------");
System.out.print("Sorting alphabetical: ");
sortAlfabetical(subtitles);
System.out.println();
System.out.println("===========================");
System.out.print("Sorting by word length: ");
compare(subtitles);
}
}

Where are comparisons in java sorting methods?

Question: Where are comparisons being made in each separate sorting method?
Also if you know please tell me which method count numbers are wrong and where to place my counters instead.trying to understand where and how many times sorting methods make comparisons.
Method A B
Selection 4950 4950
Bubble 99 9900
Insertion 99 5049
Merge 712 1028
Shell 413 649
Quick 543 1041
Okay so to explain some parts, basically Array A is an array from 1-100 in ascending order. So this should be the minimum number of comparisons.
Array B is 100-1 in descending order. So I believe it should be the maximum number of comparisons. Array C is just randomly generated numbers, so it changes every time.
I feel like my selection and bubble sorts were counted correctly. Feel free to let me know where comparisons are being made that I haven't counted, or if I'm counting wrong comparisons.
Side note: Made some global variable to count the methods that were recursive in multiple sections.
class Sorting
{
static int[] X = new int[100];
static int mergecount = 0;
static int quickcount = 0;
public static void selectionSort(int list[])
{
int count = 0;
int position = 0, n = list.length;
for(int j = 0; j < n-1; j++)
{
position = j;
for(int k = j+1; k < n; k++)
{
count++;
if(list[k] < list[position])
position = k;
}
Swap(list, j, position);
}
System.out.println("counter" + count);
}
public static void Swap(int list[], int j, int k)
{
int temp = list[j];
list[j] = list[k];
list[k] = temp;
}
public static void bubbleSort(int list[])
{
int count = 0;
boolean changed = false;
do
{
changed = false;
for(int j = 0; j < list.length - 1; j++)
{
count++;
if(list[j] > list[j + 1])
{
Swap(list, j, j+1);
changed = true;
}
}
} while(changed);
System.out.println("counter" + count);
}
public static void insertionSort(int list[])
{
int count = 0;
for(int p = 1; p < list.length; p++)
{
int temp = list[p];
int j = p;
count++;
for( ; j > 0 && temp < list[j - 1]; j = j-1)
{
list[j] = list[j - 1];
count++;
}
list[j] = temp;
}
System.out.println("counter" + count);
}
public static void mergeSort(int list[])
{
mergeSort(list, 0, list.length - 1);
System.out.println("counter" + mergecount);
}
public static void mergeSort(int list[], int first, int last)
{
if(first < last)
{
int mid = (first + last) / 2;
mergeSort(list, first, mid);
mergeSort(list, mid + 1, last);
Merge(list, first, mid, last);
}
}
public static void Merge(int list[], int first, int mid, int last)
{
int count = 0;
int first1 = first, last1 = mid;
int first2 = mid + 1, last2 = last;
int temp[] = new int[list.length];
int index = first1;
while(first1 <= last1 && first2 <= last2)
{
if(list[first1] < list[first2])
{
temp[index] = list[first1++];
mergecount++;
}
else
temp[index] = list[first2++];
index++;
mergecount++;
}
while(first1 <= last1)
temp[index++] = list[first1++];
while(first2 <= last2)
temp[index++] = list[first2++];
for(index = first; index <= last; index++)
list[index] = temp[index];
}
public static void shellSort(int list[])
{
int count = 0;
int n = list.length;
for(int gap = n / 2; gap > 0; gap = gap == 2 ? 1: (int) (gap/2.2))
for(int i = gap; i < n; i++)
{
int temp = list[i];
int j = i;
count++;
for( ; j >= gap && (temp < (list[j - gap])); j -= gap)
{
list[j] = list[j - gap];
count++;
}
list[j] = temp;
}
System.out.println("counter" + count);
}
public static void quickSort(int start, int finish, int list[])
{
int count = 0;
int left = start, right = finish, pivot, temp;
pivot = list[(start + finish) / 2];
do
{
while(list[left] < pivot)
{
left++;
quickcount++;
}
while(pivot < list[right])
{
right--;
quickcount++;
}
if(left <= right)
{
temp = list[left];
list[left++] = list[right];
list[right--] = temp;
quickcount++;
}
} while(left < right);
if(start < right)
quickSort(start, right, list);
if(left < finish)
quickSort(left, finish, list);
}
public static void copy(int list[])
{
for(int i = 0; i < list.length; i++)
X[i] = list[i];
}
public static void restore(int list[])
{
for(int i = 0; i < list.length; i++)
list[i] = X[i];
}
public static void displayArray(int list[])
{
for(int k = 0; k < list.length; k++)
System.out.print(list[k] + " ");
System.out.println();
}
public static void main(String args[])
{
int[] A = new int[100];
for(int i = 0; i < A.length; i++)
A[i] = i + 1;
int[] B = new int[100];
int q = 100;
for(int i = 0; i < B.length; i++)
B[i] = q--;
int[] C = new int[100];
for(int i = 0; i < C.length; i++)
C[i] = (int)(Math.random() * 100 + 1);
displayArray(A);
copy(A);
selectionSort(A);
displayArray(A);
restore(A);
}
Note that QuickSort performance is greatly influenced by your choice of the pivot. With both of your test arrays sorted (ascending / descending) and because you are picking pivot as array[length/2] you are actually always picking the best pivot. So your test case B won't generate maximum number of comparisons for quicksort. If you were picking array[0] as pivot you'd get maximum number of comparisons for test case A and B.
The easiest way to count comparisons is to use a compare function and do it in there.
static int compareCount = 0;
int compareInt(int a, int b) {
compareCount++;
return a - b; // if 0 they are equal, if negative a is smaller, if positive b is smaller
}
Now just use compareInt in all your algorithms and you'll get an accurate count. You'll have to reset compareCount between each run though.

quick sorting an array of integer arrays

I need to sort an array of integer arrays for a homework problem in one of my classes. I seem to get a StackOverFlowError almost every time. My array is list2[10][10]. My quick sort is separated into 3 methods. quickSort1(int, int) is the main function, partition compares a new partition, and swap simply swaps the integer arrays at list2[i] and list2[j]. the compare(int a, int b) method returns 1 if list2[a] is smaller than list2[b] - 1 if b is smaller than a and 100 if they are equal.
I'm not sure my quick sort is implemented correctly but I know swap and compare work exactly how I say they do. I have a hunch that it mostly recurs forever when I get the StackOverFlowError.
public static int partition(int low, int high)
{
int i = low, j = high;
int pivot = (low+high)/2;
System.out.println(i + " " + j + " " + pivot);
while (i <= j) {
while (compare(i, pivot) > 0)
i++;
while (compare(pivot, j) > 0)
j--;
if (i < j) {
swap(i,j);
i++;
j--;
}
if (i == pivot && i == j-1)
{
return i;
}
if (j == pivot && j-1 == i)
{
return i;
}
}
return i;
}
public static void quickSort1(int low, int high) {
System.out.println("Recursion: " + recursions);
int i = partition(low, high);
System.out.println(i);
if (low < i -1)
{
recursions++;
quickSort1(low, i -1);
}
if (i < high-1)
{
recursions++;
quickSort1(i, high);
}
}
public static void swap( int i, int j)
{
int[] temp = new int[n];
for(int k = 0; k < n; k++) {
temp[k] = list2[i][k];
}
for(int k = 0; k < n; k++) {
list2[i][k] = list2[j][k];
}
for(int k = 0; k < n; k++) {
list2[j][k] = temp[k];
}
}
I don't think these lines are necessary inside the loop while(i <= j):
if (i == pivot && i == j-1)
{
return i;
}
if (j == pivot && j-1 == i)
{
return i;
}
Try removing them from your code.
import java.util.Arrays;
import java.util.Scanner;
public class apples {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter the number of the values");
int num = input.nextInt();
int a[] = new int [num];
System.out.println("Enter the nambers now");
for(int i=0; i<a.length; i++){
a[i] = input.nextInt();
}
Arrays.sort(a);
int min =a[0];
System.out.println("The minmum value is "+min);
int max= a[a.length-1];
System.out.println("The maxemum value is "+max);
int d = max-min;
System.out.println("the difrentc between the max and the min is "+ d);
System.out.println("The Arrays R \t");
for(int g=0; g<=a.length;g++){
int m = a[g];
System.out.println(m);
}
}
}

Categories