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).
Related
I have an implementation of the mergesort algorithm. How do I calculate the height of the tree?
So far I can get the number of recursive calls, but not the height of the tree:
static int swaps=0;
static long comparisons=0;
static int recursionsdepth=0;
public static int[] sort(int[] array) {
recursionsdepth++;
if (array.length > 1) {
int middle = (int)(array.length / 2);
int[] left = new int[middle];
for (int i = 0; i <= left.length - 1; i++) {
left[i] = array[i];
}
int[] right = new int[array.length - middle];
for (int i = middle; i <= array.length - 1; i++) {
right[i - middle] = array[i];
}
left = sort(left);
right = sort(right);
return merge(left, right);
}
else
{
recursionsdepth--;
return array;
}
}
For {1,5,7,9} the recursive calls are 3 ( 1 for {1,5,7,9} ,1 for {1,5} and 1 for {7,9}), but the height of the tree is 2.
Merge Sort repeatedly divides the array into two equal (almost) parts as long as the array size is greater than 1. It doesn't care about the initial state of the array, i.e. it would do so even if the array is already sorted.
Now, there is only one way to do so for any given array of length n. And therefore, the height of the merge-sort tree will be constant with respect to n. That is the height will be ceil(log n) where base is 2. You don't need to actually run your program to find this out.
Since the OP is hell-bent on calculating the height while actually running the sorting code, here it is:
Pass an additional variable to the sort function that would store the depth of the current node. And use a global variable to store the maximum depth that has been achieved until now. Below code is slight modification of the one posted in the question:
static int swaps=0;
static long comparisons=0;
static int recursionsdepth=0;
public static int[] sort(int[] array, int depth) { // at first call depth = 0
recursiondepth = Math.max(recursiondepth, depth);
if (array.length > 1) {
int middle = (int)(array.length / 2);
int[] left = new int[middle];
for (int i = 0; i <= left.length - 1; i++) {
left[i] = array[i];
}
int[] right = new int[array.length - middle];
for (int i = middle; i <= array.length - 1; i++) {
right[i - middle] = array[i];
}
left = sort(left, depth+1);
right = sort(right, depth+1);
return merge(left, right);
}
else
{
return array;
}
}
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 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
public static void sort(int[] a){
if (a.length>1){
int pivot=a[a.length-1];
int left=0;
int right=a.length-1;
while(left<=right){
while(a[left]<pivot)
left++;
while(a[right]>pivot)
right--;
if(left<=right){
int tmp=a[right];
a[right]=a[left];
a[left]=tmp;
left++;
right--;
}
}
int[] tmp1=new int[right];
for(int i=0;i<tmp1.length;i++)
tmp1[i]=a[i];
int[] tmp2=new int[a.length-right-1];
for(int i=left;i<a.length;i++)
tmp2[i-left]=a[i];
sort(tmp1);
sort(tmp2);
}
}
Im trying to write a quicksort algorithm with one function and it doesn't work. Any help is aprrecitated. Thanks
EDIT: I solved it thanks everyone for your input.
I think the problem is that at the end you are not using the tmp1 and tmp2 to conform the new array a... Here is a way to do it without creating others arrays:
public static void sort(int[] a, int left, int right){
if (left < right){
int pivot = a[right];
int pos = left - 1;
for (int i = left; i < right; i++)
if (a[i] <= pivot)
Swap(a, ++pos, i);
Swap(a, pos + 1, right);
sort(a, left, pos);
sort(a, pos + 1, right);
}
}
public static void Swap(int[] a, int i, int j){
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
The first call of sort must be sort(a, 0, a.length - 1)
I hope this helps you
Your sort method seems extremely compared to most int sort methods. Here is a quick and easy one.
public static void sort(int[] intArray){
int n = intArray.length;
int temp = 0;
for(int i=0; i < n; i++){
for(int j=1; j < (n-i); j++){
if(intArray[j-1] > intArray[j]){
temp = intArray[j-1];
intArray[j-1] = intArray[j];
intArray[j] = temp;
}
}
}
}
This is just a bubble sort. I don't see the point of the recursion. There a bunch of other types of sorts but for a short array length this is the easiest (IMO). Look up some other ones, its kinda cool what they do (Sorting algorithm).
To get to your question....
Like #RobinCurbelo said, you didn't use temp1 and temp2 correctly. Your idea is there but I think you were thinking too much into what you needed to do.
I'm trying to understand recursion and how to turn my currently iterative insertion sort into a recursive one.
What would I need to do to my code to make it recursive?
I think I need a base case so it doesn't become an infinite loop.
I'm not sure I entirely understand recursion. Maybe you can make it clearer for me?
I've done a lot of reading but I still don't know where to start.
Here is my code:
public class InsertionSort
{
public static void main(String a[])
{
int i;
int array[] =
{ 8, 33, 12, 99, 0, 17 };
System.out.println("Values of Array before the sort: ");
for (i = 0; i < array.length; i++)
{
System.out.print(array[i] + " ");
}
insertion_srt(array, array.length);
System.out.println("");
System.out.println("Values of Array after the sort: ");
for (i = 0; i < array.length; i++)
{
System.out.print(array[i] + " ");
}
}
public static void insertion_srt(int array[], int n)
{
for (int i = 1; i < n; i++)
{
int j = i;
int B = array[i];
while ((j > 0) && (array[j - 1] > B))
{
array[j] = array[j - 1];
j--;
}
array[j] = B;
}
}
}
This is great approach I personally likes. It does use three methods but they're very simple to understand. Think of the insertionOut as the outer for loop and the insertionIn as the inner nested for loop
public static void insertionRecursive(int[] a){
if(a.length > 0){ // base case
insertionOut(a, 1, a.length);
}
}
private static void insertionOut(int[] a, int i, int length){ //outer loop
if(i < length){ // iterates from 1 to the length
int temp = a[i]; // temp value
int k = i;
insertionIn(a, k, temp);
insertionOut(a, i + 1, length); // iterates through the loop
}
}
private static void insertionIn(int[] a, int k, int temp){ // inner loop
if(k > 0 && a[k - 1] > temp){
//this does a basic swap
a[k] = temp;
a[k] = a[k - 1];
a[k - 1] = temp;
insertionIn(a, k - 1, temp); // iterates through the loop
}
}
Transforming the outer for loop is kind of trivial. To overcome the while loop you need a little recursive helper function. You have to call the function in your main as insertion_srt(array, 0, array.length):
public static void insertion_srt(int array[], int beg_index, int n) {
if(beg_index >= n-1)
return;
int i = beg_index + 1;
int j = i;
int B = array[i];
j=helper(array, j, B);
array[j] = B;
insertion_srt(array, beg_index + 1, n);
}
private static int helper(int[] array, int j, int B) {
if(j <= 0 || array[j-1] <= B)
return j;
array[j] = array[j - 1];
return helper(array, j-1, B);
}
A good way to understand how recursion works is to understand the concept of Divide and conquer algorithm. This technique is a basis of efficient algorithms for all kinds of problems.
The idea behind it is to divide a problem into smaller subproblems that can all be solved in the same way:
Divide into 2 (or more) subproblems.
Solve each subproblem recursively.
Combine the results.
Insertion sort is not the best example of a divide and conquer algorithm, but it can still be approached this way. You can divide the problem into 2 subproblems:
last element
everything else
This way you will obtain so called tail recursion. All loops are relatively easy to transform into tail recursions.
public static void insertion_srt(int array[], int n, int j) {
if (j < n) {
int i;
int temp = array[j];
for (i=j; i > 0 && array[i-1] > temp; i--) array[i] = array[i-1];
array[i] = temp;
insertion_srt(array,n, j+1);
}
}
Try this simple recursive approach:
public static void insertionSort(int[] array, int index) {
if(array.length == index + 1) return;
insertionSort(array, index + 1);
// insert array[index] into the array
}