QuickSort with Random and median - java

I am working on an assignment with QuickSort to show how fast the algorithm when using different methods for getting the Pivot like random or median of three. so far when using random or median I get different outputs and none of them is sorted, I couldn't figure out what my mistakes are. I went every where on the internet. Can someone looks at it and tell me what I'm doing wrong here?
Here is the QuickSort code:
import java.util.*;
public class QuickSort {
public static void main(String[] args) {
int[] arr = {5, -32, 12, 43, 88, 19, 113, 62, -11, 2};
System.out.println(Arrays.toString(arr));
quickSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr) {
quickSort1(arr, 0, arr.length -1);
}
private static void quickSort1(int[] list, int first, int last) {
if (first < last) {
int pivotLocation = partition(list, first, last);
quickSort1(list, first, pivotLocation - 1);
quickSort1(list, pivotLocation + 1, last);
}
}
private static int partition(int[] list, int first, int last) {
int pivot;
int smallIndex;
Random rand = new Random();
int num = rand.nextInt(list.length);
swap(list, first, (first + last) / 2);
pivot = list[first];
//pivot = medianOfThree(list, first, last);
//pivot = list[num];
smallIndex = first;
for (int index = first + 1; index <= last; index++) {
if (list[index] < pivot) {
smallIndex++;
swap(list, smallIndex, index); // Should we limit to if(smallIndex != index)
}
}
swap(list, first, smallIndex);
return smallIndex;
}
private static void swap(int[] list, int first, int second) {
int temp;
temp = list[first];
list[first] = list[second];
list[second] = temp;
}
private static int medianOfThree(int[] arr, int first, int last) {
int f = arr[first], l = arr[last], m = arr[(last + first)/2];
if(l <= f && l >= m || l >= f && l <= m)
return l;
else if (m <= f && m >= l || m >= f && m <= l)
return m;
return f;
}
}
I tried using while() it was faster but I have to test the speed of the sort with looping 100+ times which gave mejava.lang.StackOverflowError.
Any piece of advice will be helpful.
Edit:
I have fixed the median method and the random, thanks for the help.
I was working on the while loop and I figured how to make it work and sort properly. The problem now is, whenever I try to make large array to test the speed of the sorting it gets stack and I'm not sure (by large I mean 10,000 elements).
I call the class from another program but it's still not working as expected.
here is the partition method, the class is the same:
private static int partition(int[] list, int first, int last) {
Random rand = new Random();
int pivot = 0;
int num = first + rand.nextInt(last - first + 1);// generates random index
pivot = medianOfThree(list, first, last); //finding median of three numbers
//pivot = list[first]; //using the first data as pivot
//pivot = list[num]; //Random index value is used as pivot
int leftPointer= first ;
int rightPointer = last ;
//swap(list, last, (first+last)/2);
while(true) {
while (list[leftPointer] < pivot)
leftPointer++;
while (rightPointer > 0 && list[rightPointer] > pivot)
rightPointer--;
if(leftPointer >=rightPointer)
break;
swap(list, leftPointer, rightPointer);
//count++;
//System.out.println(Arrays.toString(list)+ "switch"+ count );
}
//System.out.println(Arrays.toString(list));
//swap(list, last, leftPointer);
//System.out.println(leftPointer);
return leftPointer;
}
Edit:
this is the Test code I'm using to test sorting efficiency and the QuickSort using whileloop is still not working as it should, am I doing something wrong?
Test code:
import java.util.*;
public class Test {
public static final int ARRAYSIZE = 50000; // Test array element count
public static final int ELEMENTSIZE = 10000; // Test array element size
public static final int LOOPS = 1000;
public static void main(String[] args) {
long t1=0,t2=0,t3=0;
long c1=0,c2=0; // Counters
for(int test = 1; test <= LOOPS; test++) {
System.out.print(test + "..");
Random rand = new Random();
int[] arr1 = new int[ARRAYSIZE];
for(int i = 0; i < ARRAYSIZE; i++) // Generate a random array with ARRAYSIZE elements
arr1[i] = rand.nextInt(ELEMENTSIZE);
int[] arr2 = Arrays.copyOf(arr1, arr1.length); // Use an exact array copy for each sorting test
int[] arr3 = Arrays.copyOf(arr1, arr1.length);
t1 = System.currentTimeMillis();
QuickSort.quickSort(arr1); //Run & Time Quick Sort
t2 = System.currentTimeMillis();
Arrays.sort(arr3); //Run & Time Arrays.sort
t3 = System.currentTimeMillis();
c1 += t2-t1;
c2+=t3-t2;
}
System.out.println();
System.out.println("Quick Sort took: " + c1/LOOPS + " milliseconds");
System.out.println("Arrays.sort took: " + c2/LOOPS + " milliseconds");
}
/* ADD YOUR CODE HERE */
}

I spotted at least two mistakes, there are probably others. For the selection of a random element you should use something like:
int num = first + rand.nextInt(last - first + 1);
For the median of three the middle element is:
int m = arr[(last + first)/2];
I suggest you run the program with a debugger and convince yourself after each step that the correct thing was done.

I have found the problem with the code, Whenever it compare the exact same Value, it keeps switching and compare them again... so I made a condition to break the loop whenever that occurs.
I used :
if(leftPointer >=rightPointer || list[leftPointer]== list[rightPointer])
break;
else
swap(list, leftPointer, rightPointer);
instead of:
if(leftPointer >=rightPointer)
break;
else
swap(list, leftPointer, rightPointer);
The sort works fine.
-Thanks

Related

Why is my random array sorting in 0.001 seconds?

I'm making a program that compares the times of 4 different types of sorts. Each sort uses a sorted array, a reverse sorted array, and a randomly filled array. The times for the sorted and reverse sorted look correct, but the randomly filled always returns <0.01, no matter the input size. My main looks like this:
System.out.println("---------LEFT PIVOT----------\n");
for (int i = 0; i < 4; i++) {
int[][] a = makearrays((int) (_SIZE * Math.pow(2, i)));
System.out.println("SIZE: " + _SIZE * Math.pow(2, i));
for (int k = 0; k < 3; k++) {
long start = System.currentTimeMillis();
Sort.quicksort(a[k], 0, a[k].length - 1);
long end = System.currentTimeMillis();
long time = end - start;
System.out.println("Time for " + types[k] + ": " + (time / 1000.0) + " seconds.");
System.out.println();
}
}
Where a[0] is the sorted, a[1] is the reverse sorted, and a[2] is the random sorted. Here's a sample of the output:
Time for SORTED ARRAY: 1.212 seconds.
Time for REVERSE SORTED ARRAY: 5.226 seconds.
Time for RANDOM ARRAY: 0.008 seconds.
On another run, it outputs this:
Time for SORTED ARRAY: 1.19 seconds.
Time for REVERSE SORTED ARRAY: 4.053 seconds.
Time for RANDOM ARRAY: 0.009 seconds.
I printed the arrays before and after each sort, and can confirm the random array is completely random before the sort, and sorted after. Does anyone have any idea why it would be printing such a small time? Thanks.
Edit:
In that example, I used the following:
int _SIZE = 100000;
Here's how the arrays are generated:
public static int[][] makearrays(int size) {
Random r = new Random();
int[][] a = new int[3][size];
for (int i = 0; i < size; i++) {
a[0][i] = i;
a[1][i] = size - i - 1;
a[2][i] = r.nextInt(size);
}
return a;
}
And this is what my quicksort looks like:
public static void quicksort(int[] arr, int l, int r) {
if (l < r) {
int s = partition(arr, l, r);
quicksort(arr, l, s-1);
quicksort(arr, s+1, r);
}
}
public static int partition(int[] arr, int l, int r) {
int p=arr[l],i=l+1;
for (int j =l+1;j<=r;j++) {
if (arr[j]<p) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
}
}
int temp = arr[l];
arr[l] = arr[i-1];
arr[i-1] = temp;
return i-1;
}

How can I use this for loop to correctly print the closest K integers to X?

public static int[] sortArray(int[] arr) {
Arrays.sort(arr);
return arr;
}
public static int findElement(int[] arr, int x) {
int start = 0;
int end = arr.length;
int mid = 0;
while (start <= end) {
mid = (start + end)/2;
if (arr[mid] == x) {
return x;
}
else if (x <= arr[mid]) {
end = mid - 1;
}
else {
start = mid + 1;
}
}
return mid;
}
public static void printKclosest(int arr[], int x, int k)
{
int element = findElement(arr, x);
int count = 0;
for (int i = 0; i < arr.length; i++) {
int difference = Math.abs(arr[i] - element);
while (count < k) {
if (difference > 0) {
System.out.println(arr[i]);
count++;
}
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
int[] array = {-1, 3, 5, 2, 1, 7};
sortArray(array);
System.out.println(Arrays.toString(array));
printKclosest(array, 2, 3);
}
}
for find the k nearest elements, i was thinking I could use a for loop to go through each element in the array and subtract from the element that's X and print the number of k elements that have the smallest difference, but the output I'm getting is -1 k amount of times.
function findElement returns x value if x exists but index of potential place for x if it does not present in array.
So in the second case your comparison int difference = Math.abs(arr[i] - element); has no sense
How to overcome: change in findElement
int end = arr.length - 1;
return x;
to
return mid;
and
difference = Math.abs(arr[i] - arr[element]);
But approach to get k closest numbers is completely wrong. Suggestion:
Set L index to element and R index to element+1
Compare abs differences for L and R. Output smaller. If smaller is for R, decrement L, otherwise increment R. Repeat k times (don't forget about array range)
In addition to MBo's great suggestion for outputting the k closest elements using L and R pointers, you could also solve this without sorting the array in O(n log k) time by iterating over the array once and keeping the chosen elements in a heap, each time removing the farthest (k+1)th element.

Quickselect that runs in O(n) in Java?

So I'm implement a quickselect algorithm that chooses a good pivot each time. What it does is divide the array into groups of 5, sorts each groups and finds the median. It then takes the medians of each group, groups those values up and then finds the median of medians. Here's what I have:
private static int pickCleverPivot(int left, int right, int[] A){
int index = 0;
int n = right-left;
if (n <= 5) {
Arrays.sort(A);
index = n/2;
return index;
}
int numofMedians = (int) Math.ceil(n/5);
int[] medians = new int[numofMedians];
int[] groups = new int[5];
for(int i = 0; i < numofMedians; i++) {
if (i != numofMedians - 1){
for (int j = 0; j < 5; j++){
groups[j] = A[(i*5)+j];
}
medians[i] = findMedian(groups, 5);
} else {
int numOfRemainders = n % 5;
int[] remainder = new int[numOfRemainders];
for (int j = 0; j < numOfRemainders; j++){
remainder[j] = A[(i*5)+j];
}
medians[i] = findMedian(groups, 5);
}
}
return pickCleverPivot(left, left+(numofMedians), medians);
}
public static int findMedian(int[] A, int n){
Arrays.sort(A);
if (n % 2 == 0) {
return (A[n/2] + A[n/2 - 1]) / 2;
}
return A[n/2];
}
private static int partition(int left, int right, int[] array, int pIndex){
//move pivot to last index of the array
swap(array,pIndex,right);
int p=array[right];
int l=left;
int r=right-1;
while(l<=r){
while(l<=r && array[l]<=p){
l++;
}
while(l<=r && array[r]>=p){
r--;
}
if (l<r){
swap(array,l,r);
}
}
swap(array,l,right);
return l;
}
private static void swap(int[]array, int a, int b){
int tmp = array[a];
array[a] = array[b];
array[b] = tmp;
}
So it works like it's supposed to but now I'm wondering if it's possible to get it to run in linear O(n) time. I'm currently comparing this code to just choosing a random pivot. On smaller arrays this code runs faster but on larger arrays, choosing a random pivot is faster. So is it actually possible to make this run in O(n) time or is that just in theory and if it's not possible for it to run that fast then is this method running as fast as it could.

Testing Sort Array Methods

I'm writing a program that tests if a sort function sorts a program properly. I have to have it test the quick sort and merge sort methods. Also it must ask the user which method they would like to test and make an array of random objects. Why won't my program run properly? It just spits out the same array for the quick sort and it randomly re arranges them for the merge sort. Is the problem my sorting methods or my tester method? Someone please help.
import java.util.Random;
import java.util.Scanner;
public class sortArrays {
public static void main (String[] args)
{
Random gen = new Random();
int[] a = new int[20];
Scanner reader = new Scanner(System.in);
String choice;
int left = a[0];
int right = a[19];
int[] buffer = new int [a.length];
for (int i = 0; i < a.length; i++)
a[i] = gen.nextInt(100);
printArray(a);
System.out.println("Type quick to test the quick sort method.");
System.out.println("Type merge to test the merge sort method.");
choice = reader.nextLine();
if (choice.equals("quick"))
quickSort(a, left, right);
else if (choice.equals("merge"))
mergeSort(a, buffer, 0, 9, 19);
printArray(a);
}
private static void printArray(int[] a)
{
for(int i : a)
System.out.print(i + " ");
System.out.println("");
}
private static void quickSort (int[] a, int left, int right)
{
if (left >= right) return;
int i = left;
int j = right;
int pivotValue = a[(left + right) / 2];
while (i < j)
{
while (a[i] < pivotValue) i++;
while (pivotValue < a[j]) j--;
if (i <= j)
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
quickSort(a, left, j);
quickSort(a, i, right);
}
private static void mergeSort(int[] a, int[] copyBuffer, int low, int middle, int high)
{
int i1 = low, i2 = middle + 1;
for(int i = low; i <= high; i++)
{
if(i1 > middle)
copyBuffer [i] = a[i2++];
else if(i2 > high)
copyBuffer[i] = a[i1++];
else if(a[i1] < a[i2])
copyBuffer[i] = a[i1++];
else
copyBuffer[i] = a[i2++];
}
for(int i = low; i <= high; i++)
a[i] = copyBuffer[i];
}
}
Well, your printArray() looks OK, but one thing stands out right away:
The initial parameters you are passing to quickSort() are incorrect. You have:
int[] a = new int[20];
...
int left = a[0];
int right = a[19];
...
quickSort(a, left, right);
You are initializing left and right to 0, and thus you end up calling quickSort(a, 0, 0) (not what you want). You probably mean to do this instead, as left and right hold the index:
int left = 0;
int right = 19;
Or simply:
quickSort(a, 0, 19);
As for your mergeSort(), the implementation is simply incomplete. It appears you have implemented the "merge" operation (an essential piece of the algorithm), but not the "merge sort" overall algorithm. You may want to check out Mergesort in Java (for examples) or Merge Sort (for general overview).
By the way, you may wish to specify a.length - 1 instead of 19, that way you can change the size of a without having to modify other code (same would go for the 9 you pass to mergeSort(), but that is moot as you will see it is unnecessary once you implement the algorithm fully).

Issue with Recursive Randomized pivot sort

I'm having a bit of a problem writing a recursive function that sorts an array in java recursively . Right now it appears as though I have an infinite loop, and I can't seem to figure out where.
The primary function "rec_piv" searches from index1 to the pivot point and sorts the first half, then switches from the pivot point to the length of the array and sorts the second half. All of the comparisons are recorded by an int. [The array is of random size from 2 to 2014]
Thanks very much in advance!
public class Recursive_pivot {
private Random random_size = new Random();
private int size = random_size.nextInt(1024) + 2;
public int[] a = new int[size];
private Random elements = new Random();
/* variable for rec_piv */
public int temp=0;
public int temp2=0;
private Random rand_pivot = new Random();
private int pivot = rand_pivot.nextInt(size) + 2;
private int first_half =a[0+1];
private int second_half=a[pivot+1];
private int first_index=0; //first half of the array
private int second_index=pivot; //second half of the array
//The pivot is randomly chosen.
public int comparisons =0; //count the number of comparisons.
public void fill(){
for (int q=0; q<a.length; q++) {
/* filling the array */
a[q] = elements.nextInt(100 ) + 1;
}
}
public void rec_piv(int first_index, int second_index) {
if(first_index < pivot) {
if(first_half > a[first_index]) {
comparisons++;
temp = a[first_index];
a[first_index] = a[first_half];
a[first_half] = temp;
}
rec_piv(first_index+1, second_index);
}
if(second_index < a.length) {
if(second_half > a[second_index]) {
comparisons++;
temp2 = a[second_index];
a[second_index] = a[second_half];
a[second_half] = temp2;
}
rec_piv(first_index, second_index+1);
}
} //end of rec_piv
}//end of class.
You are trying to do a QSort here is a simple version of it.
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
{
int pivot = array[start];
while (k > i)
{
while (array[i] <= pivot && i <= end && k > i)
i++;
while (array[k] > pivot && k >= start && k >= i)
k--;
if (k > i)
swap(array, i, k);
}
swap(array, start, k);
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
}
from this site.
http://www.mycstutorials.com/articles/sorting/quicksort

Categories