So I had a .csv file of around 250 unsorted names that I have put into an array of Strings. My professor wants me to sort the array alphabetically and print them out. When I print them, they are somewhat in alphabetical order but not perfectly. For example, there is the odd Y name within the Ts, or a P name in the Ns. My methods must be flawed in some way! Here they are:
private static void swapper(String[] members, int i, int j) {
String temp = members[i];
members[i] = members[j];
members[j] = temp;
}
private static int partitioner(String[] members, int low, int high) {
int pivot = low;
int leftWall = low;
for(int i = low + 1; i < high; i++) {
if(members[i].compareToIgnoreCase(members[pivot]) < 0) {
swapper(members, i, leftWall);
leftWall++;
}
}
if (members[pivot].compareToIgnoreCase(members[leftWall]) < 0) {
swapper(members, pivot, leftWall);
}
return leftWall;
}
private static void quickSort(String[] members, int low, int high) {
if (low < high) {
int pivotLocation = partitioner(members, low, high);
quickSort(members, low, pivotLocation);
quickSort(members, pivotLocation + 1, high);
}
}
Thank you for your time!
I'm trying to count minimum swaps(only consecutive swaps) in an array sorted by mergesort. It works for some cases but this case doesn't work for example: http://puu.sh/kC9mg/65e055807f.png. The first number is how many numbers it should sort, then you enter the numbers. In that case it should print 1 because the number of minimum consecutive swaps is 1 in this case which will swap 4 and 3.
This is the code I have:
public class MergeSort {
private int[] numbers;
private int[] helper;
private int number;
private long swapCounter = 0;
public MergeSort(int[] inputNumbers)
{
numbers = inputNumbers;
number = inputNumbers.length;
helper = new int[number];
mergesort(0, number-1);
}
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 - 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);
}
}
private void merge(int low, int middle, int high) { // Merge it
long internCounter = 0;
for (int i = low; i <= high; i++) { // Copy both parts into the helper array
helper[i] = numbers[i];
}
int i = low;
int j = middle + 1;
int k = low;
while (i <= middle && j <= high) { // Copy the smallest values from either the left or the right side back to the original array
if (helper[i] < helper[j]) {
numbers[k] = helper[i];
i++;
internCounter++;
} else {
numbers[k] = helper[j];
j++;
swapCounter += internCounter;
}
k++;
}
while (i <= middle) { // Copy the rest of the left side of the array into the target array
numbers[k] = helper[i];
k++;
i++;
swapCounter += internCounter;
}
}
public long getCounter() // Get the counter
{
return this.swapCounter;
}
}
And this is my main class:
import java.util.Scanner;
public class Fr {
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
int numberOfStudents;
int[] inputNumbers2;
numberOfStudents = input.nextInt();
inputNumbers2 = new int[numberOfStudents];
for(int i = 0; i < numberOfStudents; i++)
{
inputNumbers2[i] = input.nextInt();
}
MergeSort ms = new MergeSort(inputNumbers2);
System.out.println(ms.getCounter());
input.close();
}
}
Do anyone have any thoughts what could be wrong?
I don't think you need the intern counter at all. Just count how many positions you swap an element when taking an element from the high half:
public class MergeSort {
private int[] numbers;
private int[] helper;
private int number;
private long swapCounter = 0;
public MergeSort(int[] inputNumbers)
{
numbers = inputNumbers;
number = inputNumbers.length;
helper = new int[number];
mergesort(0, number-1);
}
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 - 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);
}
}
private void merge(int low, int middle, int high) { // Merge it
for (int i = low; i <= high; i++) { // Copy both parts into the helper array
helper[i] = numbers[i];
}
int i = low;
int j = middle + 1;
int k = low;
while (i <= middle && j <= high) { // Copy the smallest values from either the left or the right side back to the original array
if (helper[i] < helper[j]) {
numbers[k] = helper[i];
i++;
} else {
numbers[k] = helper[j];
swapCounter += (j-k);
j++;
}
k++;
}
while (i <= middle) { // Copy the rest of the left side of the array into the target array
numbers[k] = helper[i];
k++;
i++;
}
}
public long getCounter() // Get the counter
{
return this.swapCounter;
}
}
i've seen many quicksort algorithms and I'm wondering what the difference between these two are and if there are any more, perhaps simpler ones. Apart from the fact that one is for ints and the other for chars..
This is the first:
public class MyQuickSort {
private int array[];
private int length;
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
length = inputArr.length;
quickSort(0, length - 1);
}
private void quickSort(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)
quickSort(lowerIndex, j);
if (i < higherIndex)
quickSort(i, higherIndex);
}
private void exchangeNumbers(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void main(String a[]){
MyQuickSort sorter = new MyQuickSort();
int[] input = {24,2,45,20,56,75,2,56,99,53,12};
sorter.sort(input);
for(int i:input){
System.out.print(i);
System.out.print(" ");
}
}
}
And the second:
class Quicksort{
static void qsort(char items[]){
qs(items, 0, items.length-1);
}
//a recursive version of Quicksort for characters
private static void qs(char items[], int left, int right){
int i, j;
char x, y;
i = left; j = right;
x = items[(left+right)/2];
do{
while((items[i] < x) && (i < right)) i++;
while((x < items[j]) && (j > left)) j--;
if(i <= j){
y = items[i];
items[i] = items[j];
items[j] = y;
i++; j--;
}
} while(i <= j);
if(left < j) qs(items, left, j);
if(i < right) qs(items, i, right);
}
}
public class QSDemo {
public static void main(String[] args) {
char a[] = { 'd', 'x', 'a', 'r', 'p', 'j', 'i' };
int i;
System.out.println("Original array: ");
for(i = 0; i < a.length; i++)
System.out.print(a[i]);
System.out.println();
//now, sort the array
Quicksort.qsort(a);
System.out.println("Sorted array: ");
for(i = 0; i < a.length; i++)
System.out.print(a[i]);
}
}
How good quicksort performs depends mainly on the choice of pivots. If you choose them perfectly you have O(n log n) which is also the average case, but the worst case is O(n^2). So the implementation with the best strategy for choosing pivots will outperform the others for big arrays, but it might be an overhead for small arrays. What is a good strategy for choosing pivots? It depends on the problem and the data you expect. So to ask this would be similar to ask which is the "best" programming language and the answer is: it depends on the problem. If you are looking for really generalized approach then there are strategies that reduce the probability of poor pivot choices but they don't guarantee it. Or hybrids like Introsort.
I am working on a program that uses quick sort to sort an array to display the running time. This program selects the median of three random numbers as the pivot. However, I am not sure if I am doing something wrong because every time I run this program I get the following errors:
"java.lang.StackOverflowError",
at java.util.Random.nextInt(Unknown Source)
at SortingItems.quickSort(SortingItems.java:31)
at SortingItems.quickSort(SortingItems.java:69) " I get this specific message multiple times"
This is the code:
import java.util.Random;
public class SortingItems {
static int x = 1000;
static int array [] = new int[x];
public static void main(String[] args) {
long time;
input(x, array);
time = System.nanoTime();
sort(array);
System.out.println("Running time in ascending order " + (System.nanoTime() - time));
}
public static void sort(int[] array) {
quickSort(array, 0, array.length - 1);
}
public static void quickSort(int[] array, int low, int high) {
if (array == null || array.length == 0)
return;
if (low >= high)
return;
// Generating random numbers from 0 to the last element of the array
Random f = new Random();
int first = f.nextInt(array.length - 1);
Random s = new Random();
int second = s.nextInt(array.length - 1);
Random t = new Random();
int third = t.nextInt(array.length - 1);
// Selecting the pivot
int pivot = Math.max(Math.min(array[first], array[second]),
Math.min(Math.max(array[first],array[second]), array[third]));
int i = low;
int j = high;
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
}
if (low < j)
quickSort(array, low, j);
if (high > i)
quickSort(array, i, high);
}
// Input in ascending order
public static int[] input(int x, int[] array) {
for (int k = 0; k < x; k++) {
array[k] = k;
}
return array;
}
}
The problem seems to be with how the median is being selected here. The pivots should be chosen from between the current high and low positions and not the entire array.
Note that your test-input is in ascending order. Now, as you select three random values from the entire array of size 1000 for pivoting, when it comes to the smaller recursive cases, the arrays tend to be lopsided with a very high probability. This means that another level of recursion would be called with the same input parameters. In the long run, this is likely to cause a stack overflow with a high probability.
The following change should fix your issue:
// Generating random numbers from low to high
Random f = new Random();
int first = f.nextInt(high-low) + low;
Random s = new Random();
int second = s.nextInt(high-low) + low;
Random t = new Random();
int third = t.nextInt(high-low) + low;
I am trying to make a merge sort method, but it keeps on giving the wrong sorts. Where do I have change to make it actually sort the array? What part of the code has to be different? Thank you for your time.
public static void mergeSort(int[] array, int left, int lHigh, int right, int rHigh) {
int elements = (rHigh - lHigh +1) ;
int[] temp = new int[elements];
int num = left;
while ((left <= lHigh) && (right <= rHigh)){
if (a[left] <= array[right]) {
temp[num] = array[left];
left++;
}
else {
temp[num] = array[right];
right++;
}
num++;
}
while (left <= right){
temp[num] = array[left]; // I'm getting an exception here, and is it because of the num???
left += 1;
num += 1;
}
while (right <= rHigh) {
temp[num] = array[right];
right += 1;
num += 1;
}
for (int i=0; i < elements; i++){
array[rHigh] = temp[rHigh];
rHigh -= 1;
}
EDIT: now the mergeSort doesn't really sort the numbers, can someone tell me where it specifically is? especially when I print the "Testing merge sort" part.
First of all, I'm assuming this is academic rather than practical, since you're not using a built in sort function. That being said, here's some help to get you moving in the right direction:
Usually, one can think of a merge sort as two different methods: a merge() function that merges two sorted lists into one sorted list, and mergeSort() which recursively breaks the list into single element lists. Since a single element list is sorted already, you then merge all the lists together into one big sorted list.
Here's some off-hand pseudo-code:
merge(A, B):
C = empty list
While A and B are not empty:
If the first element of A is smaller than the first element of B:
Remove first element of A.
Add it to the end of C.
Otherwise:
Remove first element of B.
Add it to the end of C.
If A or B still contains elements, add them to the end of C.
mergeSort(A):
if length of A is 1:
return A
Split A into two lists, L and R.
Q = merge(mergeSort(L), mergeSort(R))
return Q
Maybe that'll help clear up where you want to go.
If not, there's always MergeSort at wikipedia.
Additional:
To help you out, here are some comments inline in your code.
public static void mergeSort(int[] array, int left, int lHigh, int right, int rHigh) {
// what do lHigh and rHigh represent?
int elements = (rHigh - lHigh +1) ;
int[] temp = new int[elements];
int num = left;
// what does this while loop do **conceptually**?
while ((left <= lHigh) && (right <= rHigh)){
if (a[left] <= a[right]) {
// where is 'pos' declared or defined?
temp[pos] = a[left];
// where is leftLow declared or defined? Did you mean 'left' instead?
leftLow ++;
}
else {
temp[num] = a[right];
right ++;
}
num++;
}
// what does this while loop do **conceptually**?
while (left <= right){
// At this point, what is the value of 'num'?
temp[num] = a[left];
left += 1;
num += 1;
}
while (right <= rHigh) {
temp[num] = a[right];
right += 1;
num += 1;
}
// Maybe you meant a[i] = temp[i]?
for (int i=0; i < elements; i++){
// what happens if rHigh is less than elements at this point? Could
// rHigh ever become negative? This would be a runtime error if it did
a[rHigh] = temp[rHigh];
rHigh -= 1;
}
I'm purposefully being vague so you think about the algorithm. Try inserting your own comments into the code. If you can write what is conceptually happening, then you may not need Stack Overflow :)
My thoughts here are that you are not implementing this correctly. This is because it looks like you're only touching the elements of the array only once (or close to only once). This means you have a worst case scenario of O(N) Sorting generally takes at least O(N * log N) and from what I know, the simpler versions of merge sort are actually O(N^2).
More:
In the most simplistic implementation of merge sort, I would expect to see some sort of recursion in the mergeSort() method. This is because merge sort is generally defined recursively. There are ways to do this iteratively using for and while loops, but I definitely don't recommend it as a learning tool until you get it recursively.
Honestly, I suggest taking either my pseudo-code or the pseudo-code you may find in a wikipedia article to implement this and start over with your code. If you do that and it doesn't work correctly still, post it here and we'll help you work out the kinks.
Cheers!
And finally:
// Precondition: array[left..lHigh] is sorted and array[right...rHigh] is sorted.
// Postcondition: array[left..rHigh] contains the same elements of the above parts, sorted.
public static void mergeSort(int[] array, int left, int lHigh, int right, int rHigh) {
// temp[] needs to be as large as the number of elements you're sorting (not half!)
//int elements = (rHigh - lHigh +1) ;
int elements = rHigh - left;
int[] temp = new int[elements];
// this is your index into the temp array
int num = left;
// now you need to create indices into your two lists
int iL = left;
int iR = right;
// Pseudo code... when you code this, make use of iR, iL, and num!
while( temp is not full ) {
if( left side is all used up ) {
copy rest of right side in.
make sure that at the end of this temp is full so the
while loop quits.
}
else if ( right side is all used up) {
copy rest of left side in.
make sure that at the end of this temp is full so the
while loop quits.
}
else if (array[iL] < array[iR]) { ... }
else if (array[iL] >= array[iR]) { ... }
}
}
public class MergeSort {
public static void main(String[] args) {
int[] arr = {5, 4, 7, 2, 3, 1, 6, 2};
print(arr);
new MergeSort().sort(arr, 0, arr.length - 1);
}
private void sort(int[] arr, int lo, int hi) {
if (lo < hi) {
int mid = (lo + hi) / 2;
sort(arr, lo, mid); // recursive call to divide the sub-list
sort(arr, mid + 1, hi); // recursive call to divide the sub-list
merge(arr, lo, mid, hi); // merge the sorted sub-lists.
print(arr);
}
}
private void merge(int[] arr, int lo, int mid, int hi) {
// allocate enough space so that the extra 'sentinel' value
// can be added. Each of the 'left' and 'right' sub-lists are pre-sorted.
// This function only merges them into a sorted list.
int[] left = new int[(mid - lo) + 2];
int[] right = new int[hi - mid + 1];
// create the left and right sub-list for merging into original list.
System.arraycopy(arr, lo, left, 0, left.length - 1);
System.arraycopy(arr, mid + 1, right, 0, left.length - 1);
// giving a sentinal value to marking the end of the sub-list.
// Note: The list to be sorted is assumed to contain numbers less than 100.
left[left.length - 1] = 100;
right[right.length - 1] = 100;
int i = 0;
int j = 0;
// loop to merge the sorted sequence from the 2 sub-lists(left and right)
// into the main list.
for (; lo <= hi; lo++) {
if (left[i] <= right[j]) {
arr[lo] = left[i];
i++;
} else {
arr[lo] = right[j];
j++;
}
}
}
// print the array to console.
private static void print(int[] arr) {
System.out.println();
for (int i : arr) {
System.out.print(i + ", ");
}
}
}
Here's another!
private static int[] mergeSort(int[] input){
if (input.length == 1)
return input;
int length = input.length/2;
int[] left = new int[length];
int[] right = new int[input.length - length];
for (int i = 0; i < length; i++)
left[i] = input[i];
for (int i = length; i < input.length; i++)
right[i-length] = input[i];
return merge(mergeSort(left),mergeSort(right));
}
private static int[] merge(int[] left, int[] right){
int[] merged = new int[left.length+right.length];
int lengthLeft = left.length;
int lengthRight = right.length;
while (lengthLeft > 0 && lengthRight > 0){
if (left[left.length - lengthLeft] < right[right.length - lengthRight]){
merged[merged.length -lengthLeft-lengthRight] = left[left.length - lengthLeft];
lengthLeft--;
}else{
merged[merged.length - lengthLeft-lengthRight] = right[right.length - lengthRight];
lengthRight--;
}
}
while (lengthLeft > 0){
merged[merged.length - lengthLeft] = left[left.length-lengthLeft];
lengthLeft--;
}
while (lengthRight > 0){
merged[merged.length - lengthRight] = right[right.length-lengthRight];
lengthRight--;
}
return merged;
}
static void mergeSort(int arr[],int p, int r) {
if(p<r) {
System.out.println("Pass "+k++);
int q = (p+r)/2;
mergeSort(arr,p,q);
mergeSort(arr,q+1,r);
//System.out.println(p+" "+q+" "+r);
merge(arr,p,q,r);
}
}
static void merge(int arr[],int p,int q,int r) {
int temp1[],temp2[];
//lower limit array
temp1 = new int[q-p+1];
//upper limit array
temp2 = new int[r-q];
for(int i=0 ; i< (q-p+1); i++){
temp1[i] = arr[p+i];
}
for(int j=0; j< (r-q); j++){
temp2[j] = arr[q+j+1];
}
int i = 0,j=0;
for(int k=p;k<=r;k++){
// This logic eliminates the so called sentinel card logic mentioned in Coreman
if(i!= temp1.length
&& (j==temp2.length || temp1[i] < temp2[j])
) {
arr[k] = temp1[i];
// System.out.println(temp1[i]);
i++;
}
else {
//System.out.println(temp2[j]);
arr[k] = temp2[j];
j++;
}
}
}
>
Merge Sort Using Sentinel
This codes works perfectly fine.
public void mergeSort(int a[], int low, int high) {
if (low < high) {
int mid = (low + high) / 2;
mergeSort(a, low, mid);
mergeSort(a, mid + 1, high);
merge(a, low, mid, high);
}
}
public void merge(int a[], int low, int mid, int high) {
int n1 = mid - low + 1;// length of an array a1
int n2 = high - mid; // length of an array a2
int a1[] = new int[n1 + 1];
int a2[] = new int[n2 + 1];
int lowRange = low;
for (int i = 0; i < n1; i++) {
a1[i] = a[lowRange];
lowRange++;
}
for (int j = 0; j < n2; j++) {
a2[j] = a[mid + j + 1];
}
a1[n1] = Integer.MAX_VALUE; // inserting sentinel at the end of array a1
a2[n2] = Integer.MAX_VALUE; // inserting sentinel at the end of array a2
int i = 0;
int j = 0;
int k = low;
for (k = low; k <= high; k++) {
if (a1[i] >= a2[j]) {
a[k] = a2[j];
j++;
} else {
a[k] = a1[i];
i++;
}
}
if (a2.length >= a1.length) {
for (int ab = k; ab < a2.length; ab++) {
a[k] = a2[ab];
k++;
}
} else if (a1.length >= a2.length) {
for (int ab = k; ab < a1.length; ab++) {
a[k] = a1[ab];
k++;
}
}
}
Here's another alternative:
public class MergeSort {
public static void merge(int[]a,int[] aux, int f, int m, int l) {
for (int k = f; k <= l; k++) {
aux[k] = a[k];
}
int i = f, j = m+1;
for (int k = f; k <= l; k++) {
if(i>m) a[k]=aux[j++];
else if (j>l) a[k]=aux[i++];
else if(aux[j] > aux[i]) a[k]=aux[j++];
else a[k]=aux[i++];
}
}
public static void sort(int[]a,int[] aux, int f, int l) {
if (l<=f) return;
int m = f + (l-f)/2;
sort(a, aux, f, m);
sort(a, aux, m+1, l);
merge(a, aux, f, m, l);
}
public static int[] sort(int[]a) {
int[] aux = new int[a.length];
sort(a, aux, 0, a.length-1);
return a;
}
}
Here is a simple merge sort algorithm in Java:
Good Tip: Always use int middle = low + (high-low)/2 instead of int middle = (low + high)/2.
public static int[] mergesort(int[] arr) {
int lowindex = 0;
int highindex = arr.length-1;
mergesort(arr, lowindex, highindex);
return arr;
}
private static void mergesort(int[] arr, int low, int high) {
if (low == high) {
return;
} else {
int midIndex = low + (high-low)/2;
mergesort(arr, low, midIndex);
mergesort(arr, midIndex + 1, high);
merge(arr, low, midIndex, high);
}
}
private static void merge(int[] arr, int low, int mid, int high) {
int[] left = new int[mid-low+2];
for (int i = low; i <= mid; i++) {
left[i-low] = arr[i];
}
left[mid-low+1] = Integer.MAX_VALUE;
int[] right = new int[high-mid+1];
for (int i = mid+1; i <= high; i++) {
right[i-mid-1] = arr[i];
}
right[high - mid] = Integer.MAX_VALUE;
int i = 0;
int j = 0;
for (int k = low; k <= high; k++) {
if (left[i] <= right[j]) {
arr[k] = left[i];
i++;
} else {
arr[k] = right[j];
j++;
}
}
}
package com.sortalgo;
import java.util.Arrays;
public class MyMSort {
private static void merge(int[] array, int[] result, int low, int mid, int high) {
int k =low, i=low; int j=mid+1;
while(i<=mid && j<=high) {
if(array[i]<= array[j]) {
result[k++]=array[i++];
}else {
result[k++]=array[j++];
}
}
while(i<=mid) {
result[k++]=array[i++];
}
while(j<=high) {
result[k++]=array[j++];
}
for(i=low;i<=high;i++) {
array[i]=result[i];
}
}
private static void mergeSort(int[] array, int[] result, int low, int high) {
if(high == low) {
return ;
}
int mid = (low + high)/2;
mergeSort(array,result, low, mid );
mergeSort(array,result, mid+1, high );
merge(array, result, low, mid, high);
}
public static void main(String[] args) {
int[] array = {8,4,3,12,25,6,13,10};
int[] result = new int[array.length];
mergeSort(array, result, 0, array.length-1 );
for(int i=0; i<=array.length-1;i++) {
System.out.println(array[i]);
}
}
}