I want to compare count of operations of the sorting algorithms Merge Sort and Selection Sort, but I have some problems figuring out which operations to count and which not..
Here are my implementations. I think I'm counting the operations of Selection Sort in the right way, but I don't know about Merge Sort:
Selection Sort:
public class SelectionSort {
private int exchanges, comparisons;
public void selectionSort(int[] x) {
for (int i=0; i<x.length-1; i++) {
for (int j=i+1; j<x.length; j++) {
if (x[i] > x[j])
{
//... Exchange elements
int temp = x[i];
x[i] = x[j];
x[j] = temp;
exchanges++;
}
comparisons++;
}
}
System.out.println("SelSort_Exchanges: "+exchanges);
System.out.println("SelSort_Comparisons: "+comparisons);
System.out.println("SelSort_Operations: "+(exchanges+comparisons));
}
}
If I put in an array of 10 int I get:
SelSort_Comparisons: 45
SelSort_Exchanges: 27
SelSort_Operations: 72
Seems right to me, but now for Merge Sort:
public class Mergesort {
private int[] numbers;
private int[] helper;
private int number;
private int comparisons, exchanges;
public void sort(int[] values) {
this.numbers = values;
number = values.length;
this.helper = new int[number];
mergesort(0, number - 1);
System.out.println("MerSort_Comparisons "+comparisons);
System.out.println("MerSort_Exchanges "+exchanges);
System.out.println("MerSort_Operations "+(comparisons+exchanges));
System.out.println();
}
private void mergesort(int low, int high) {
// Check if low is smaller then high, if not then the array is sorted
if (low < high)
{
// Get the index of the element which is in the middle
int middle = (low + high) / 2;
// Sort the left side of the array
mergesort(low, middle);
// Sort the right side of the array
mergesort(middle + 1, high);
// Combine them both
merge(low, middle, high);
}
}
private void merge(int low, int middle, int high) {
// Copy both parts into the helper array
for (int i = low; i <= high; i++) {
helper[i] = numbers[i];
exchanges++;
}
int i = low;
int j = middle + 1;
int k = low;
// Copy the smallest values from either the left or the right side back
// to the original array
while (i <= middle && j <= high) {
if (helper[i] <= helper[j]) {
numbers[k] = helper[i];
i++;
exchanges++;
} else {
numbers[k] = helper[j];
j++;
exchanges++;
}
k++;
comparisons++;
}
// Copy the rest of the left side of the array into the target array
while (i <= middle) {
numbers[k] = helper[i];
exchanges++;
k++;
i++;
}
}
}
now I get
MerSort_Comparisons 22
MerSort_Exchanges 61
MerSort_Operations 83
as a result but I don't know if its right. Result of Comparisons seems right to me, but if I take an array of 20 for example it doesnt seem right anymore.
Could anyone help me with this and tell me where exactly I have to put my comparison and exchange increments?
thanks in advance! :)
Simplest way would be to create two methods, Compare and Swap, and increase counter inside of them. Whatever sorting algorithm you implement, it should only interact with the array using these methods.
Also, this page can help you analyze different sorting algorithms visually.
Related
I need to implement the following in java.
Input: an array of integers
Output: Rearrange the array to have the following:
Suppose the first element in the original array has the value x
In the new array, suppose that x is in position I, that is data[I] = x. Then, data[j] <= x for all x and for all j > I. This means that all the values to the "left" of x are less than or equal to x and all the values to the "right" are larger than x.
An example is as follows: Suppose the array has the elements in this initial order: 4,3,9,2,7,6,5. After applying your algorithm, you should get: 3,2,4,5,9,7,6. That is, the leftmost element, 4, is positioned in the resulting array so that all elements less than 4 (2 and 3) are to its left (in no particular order), and all elements larger than 4 are to its right (in no particular order).
There is no space requirement for the algorithm, only that the problem is solved in O(n) time.
I have implemented a bucket sort, but am having some difficulties with the code.
public class Problem4
{
public static void partition(int[] A)
{
int x = A[0];
int l = A.length;
int[] bucket = int [];
for(int i=0; i<bucket.length; i++){
bucket[i]=0;
}
for (int i=0; i<l; i++){
bucket[x[i]]++;
}
int outPos=0;
for(int i=0; i<bucket.length; i++){
for(int j=0; j<bucket[i]; j++){
x[outPos++]=i;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] A = {4,3,9,2,7,6,5};
System.out.println("Before partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
partition(A);
System.out.println("After partition:");
System.out.println("Before partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
}
}
The lines:
int[] bucket = int[],
bucket[x[i]]++;, and
x[outpost++] = i;
are causing me troubles. I am getting the error
The type of expression must be an array type but is resolved to an int.
The problem stems from that first line where I am trying to create a new array called bucket. I would appreciate any suggestions! Thanks!
I don't think you need to resort to a bucket sort. Instead you can simply walk through the array, placing elements that are less than the split value at the front and elements that are greater at the back. We can use two variables, front and back to keep track of the insert position at the front and back of the array. Starting at position 1 in the array, if the value is less than the split value we place at front and increment front and the current index. If the value is greater we swap it with the value at back and decrement back, but we keep the current index.
Here's some code to illustrate:
public static void main(String[] args)
{
int[] A = {4,3,9,2,7,6,5};
sort(A);
System.out.println(Arrays.toString(A));
}
public static void sort(int[] arr)
{
int split = arr[0];
int front = 0;
int back = arr.length-1;
for(int i=1; front != back; )
{
if(arr[i] <= split)
{
arr[front] = arr[i];
front += 1;
i++;
}
else
{
swap(arr, i, back);
back -= 1;
}
}
arr[front] = split;
}
public static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
Output:
[3, 2, 4, 7, 6, 5, 9]
Another approach you can use is to use the standard partition algorithm of QuickSort.
I have modified your code and the following code
public class Problem4
{
/* This function takes last element as pivot,
places the pivot element at its correct
position in sorted array, and places all
smaller (smaller than pivot) to left of
pivot and all greater elements to right
of pivot */
public static int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low-1); // index of smaller element
for (int j=low; j<high; j++)
{
// If current element is smaller than or
// equal to pivot
if (arr[j] <= pivot)
{
i++;
// swap arr[i] and arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// swap arr[i+1] and arr[high] (or pivot)
int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp;
return i+1;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] A = {4,3,9,2,7,6,5};
System.out.println("Before partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
// swap and call the standard partition algo of QuickSort
// on last element pivot. swap arr[low] and arr[high]
int low = 0;
int high = A.length-1;
int temp = A[low];
A[low] = A[high];
A[high] = temp;
partition(A, low, high);
System.out.println("\nAfter partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
}
}
Outputs
Before partition:
4 3 9 2 7 6 5
After partition:
3 2 4 5 7 6 9
Hope it helps!
For school I have to write a quicksort for an Array of strings. I think my partition is good but I keep getting error with the recursion.
public static int partition(String[] input, int max) {
// pivot is dividing point
// I keeps track of lesser values
// count is just a counter
// Pivots in place
int pivot = 0;
int i = 1;
int count = 1;
while (count <= max) {
if (input[count].compareTo(input[pivot]) < 0) {
input[i] = input[count];
i = i + 1;
}
if (count == max) {
input[i] = input[pivot];
input[pivot] = input[i];
}
count++;
}
return pivot;
}
public static void qSort(String[] input) {
int index = partition(input, input.length - 1);
int count = 0;
if (count < index - 1) {
partition(input, index - 1);
}
if (index + 1 < count && count < input.length) {
partition(input, input.length - 1);
}
count++;
}
Your implementation has a lot of mistakes. First of all, you're always choosing the pivot to be the element at index 0 of the array. The idea of quicksort is that you choose some pivot, partition the array around it, then recursively apply quicksort on both partitions around the chosen pivot. How do you identify the start and end of the partitions you'll call quicksort recursively on? You need to pass those as arguments to your partition method as others have mentioned in the comments, same thing for the quicksort method itself.
public void swap (String [] array, int i, int j) {
String tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static int partition (String [] array, int low, int high) {
String pivot = array[low];
int index = low+1;
for (int i = low+1; i <= high; i++) {
if (pivot.compareTo(array[i]) > 0) {
swap(array, i, index);
index++;
}
}
swap(array, low, index-1);
return index-1;
}
public static void qsort(String [] array, int low, int high) {
if (low < high) {
int p = partition(array, low, high);
qsort(array, low, p);
qsort(array, p+1, high);
}
}
Obviously this isn't the best way to choose the pivot as some arrays will make the algorithm perform very poorly. A better method would be to use a random pivot each time.
I have the below merge sort code in my application. I am very confused on how the recursive method gets called again after it comes out of the if block when the if condition is not met.
I debugged my code, but I am still not getting it. The sort method that calls mergesort(0, number - 1) starts first at mergesort(0, 5). low is less than high, middle is 2, so mergesort(0, 2) is run next. This goes on until we have mergesort(0, 0) in which case low is not less than high,
so it comes out of the if block. But when I debug, the method returns, and it starts again after mergesort(0, 0) case. How does the call happen again?
public class MergeSort {
private int[] numbers;
private int[] helper;
private int number;
public int[] sort(int[] values) {
this.numbers = values;
number = values.length;
this.helper = new int[number];
return mergesort(0, number - 1);
}
private int[] mergesort(int low, int high) {
// check if low is smaller then high, if not then the array is sorted
if (low < high) {
// Get the index of the element which is in the middle
int middle = low + (high - low) / 2;
// Sort the left side of the array
mergesort(low, middle);
// Sort the right side of the array
mergesort(middle + 1, high);
// Combine them both
merge(low, middle, high);
}
return numbers;
}
private int[] merge(int low, int middle, int high) {
// Copy both parts into the helper array
for (int i = low; i <= high; i++) {
helper[i] = numbers[i];
}
int i = low;
int j = middle + 1;
int k = low;
// Copy the smallest values from either the left or the right side back
// to the original array
while (i <= middle && j <= high) {
if (helper[i] <= helper[j]) {
numbers[k] = helper[i];
i++;
} else {
numbers[k] = helper[j];
j++;
}
k++;
}
// Copy the rest of the left side of the array into the target array
while (i <= middle) {
numbers[k] = helper[i];
k++;
i++;
}
return numbers;
}
}
This is because the mergesort method calls itself twice. You can print out the stack to see what happens.
For example, when call mergesort(0,1), the method will call mergesort(0,0) first and then mergesort(1,1).
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).
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
}