Merge Sort - Sorting String Array with Int Array - java

For this project, I'm given an array of strings and an array of ints. int[1] is the ranking for string[1]. I need to sort the int array in order from 1 to n using mergesort, which I've done below. But I also need to switch the positions of the string array when the int array gets moved so they are both sorted, if that makes sense? I can't figure out what's wrong with my coding or even if my idea will actually work, but I keep getting an array index out of bounds error on stringSorted[k] = stringRight[j] and I can't figure out if there's a way to fix this. Essentially, when an int was added to the sortedInt array, I also added that element to the sorted String array. Thank you for any help, and let me know if something doesn't make sense
private static int sortAndCount(int intToSort[]){
int inversionsLeft;
int inversionsRight;
int inversionsMerged;
if(intToSort.length == 1){
return 0;
}
int m = intToSort.length/2;
int[] intLeft = new int[m];
stringLeft = new String[m];
int[] intRight = new int[intToSort.length-m];
stringRight = new String[intToSort.length-m];
for (int i=0; i < m; i++){
intLeft[i] = intToSort[i];
stringLeft[i] = stringToSort[i];
}
for (int i = 0;i < intRight.length; i++){
intRight[i] = intToSort[m+i];
stringRight[i] = stringToSort[m+i];
}
inversionsLeft = sortAndCount(intLeft);
inversionsRight = sortAndCount(intRight);
intSorted = new int[intToSort.length];
stringSorted = new String[stringToSort.length];
inversionsMerged = mergeAndCount(intLeft, intRight);
return(inversionsLeft + inversionsRight + inversionsMerged);
}
private static int mergeAndCount(int[] intLeft, int[] intRight){
int count = 0;
int i = 0;
int j = 0;
int k = 0;
while(i < intLeft.length && j < intRight.length){
if(intLeft[i] < intRight[j]){
intSorted[k] = intLeft[i];
stringSorted[k] = stringLeft[i];
i++;
}
else{
intSorted[k] = intRight[j];
stringSorted[k] = stringRight[j];
count += intLeft.length - i + 1;
j++;
}
k++;
}
while (i < intLeft.length)
{
intSorted[k] = intLeft[i];
stringSorted[k] = stringLeft[i];
k++;
i++;
}
while (j < intRight.length)
{
intSorted[k] = intRight[j];
stringSorted[k] = stringRight[j];
j++;
k++;
}
return count;
}
}

int[] intLeft = new int[m];
stringLeft = new String[m];
int[] intRight = new int[intToSort.length-m];
stringRight = new String[intToSort.length-m];
You'll notice here that for the int arrays you are creating new variables, for the string you are replacing the outer. This is making your string arrays smaller with each recursive call whereas your int arrays are passed to each method.
By the time you get to calling mergeAndCount, stringLeft and stringRight are very small whereas the appropriately sized intLeft and intRight are passed as arguments.

Related

How do i fix my interpretation of this run-length encoding algorithm?

For school, i have to build myself a method in java that compresses an array using RLE(run-length encoding). I can't find a solution online because my teacher wants me to solve the problem myself. I, unfortunately, cannot do this for i am a busy man with some busy plans.
RLE turns this: {1,1,1,1,2,2,3,3,6,6,6,7,8,8,8}
into this: {4,1,2,2,2,3,3,6,1,7,3,8}
it basically makes a new array that follows this formula {# of this value, this value, # of this value, this value, cont...} there are 4 1's so {4,1} you get my drift.
Here is what i tried to do(forgive me for my crappy code, i am merely a high school student):
public class tester{
public static void main(String[] args){
int[] potato = {1,1,1,2,2,4,4,4,6,6,6,6};
printArray(compress(potato));
}
public static void printArray(int[] arr){
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
}
public static int[] compress(int[] a) {
//figure out how many different numbers there are.
int diffNums = 1;
for(int i = 0; i < a.length; i++){
if(i != a.length-1 && a[i] != a[i+1]){
diffNums++;
}
}
//make compressed array at the correct length.
int[] compressed = new int[diffNums * 2];
//figure out what each number is.
int[] nums = new int[diffNums];
nums[0] = a[0];
int spot = 0;
for(int i = 0; i < a.length; i++){
if(i != a.length-1 && a[i] != a[i+1]){
nums[spot] = a[i+1];
}
}
//figure out quantity of each number.
int[] quantities = new int[diffNums];
int spot2 = 0;
int spotcur = 0;
for(int i = 0; i < diffNums; i++){
int quant = 0;
while(a[spotcur] == a[spot2]){
quant++;
spotcur++;
}
spot2 = spotcur;
quantities[i] = quant;
}
//add them together and return compressed array
int spotter = 0;
for(int i = 0; i < diffNums; i++){
compressed[spotter] = quantities[i];
spotter++;
compressed[spotter] = nums[i];
spotter++;
}
return compressed;
}
}
Does anyone know how i can fix this crappy code? i am stuck on it
I think this problem could be solved with a lot less code. You could use an outer/inner loop construct something like the following:
public static int[] compress(int[] a) {
List<Integer> encoded = new ArrayList<>();
for (int i=0; i<a.length; i++) {
int num = a[i];
int count = 1;
for (int j=i+1; j<a.length; j++) {
int nextNum = a[j];
if (nextNum != num)
break;
count++;
i++;
}
encoded.add(count);
encoded.add(num);
}
return encoded.stream().mapToInt(i->i).toArray();
}
Also, the Arrays class contains a useful toString method already defined.
System.out.println(Arrays.toString(compress(potato)));

Merge sort 3 way java

I have to make a 3 way merge sort of an array. the array length is a in a power of 3, i.e. 3,9,27 etc. So I can use only one split function and not "left","mid","right".
Would like to get an answer how to repair it and why does not it work.
I have written the code, however don't know how to get it to work.
Here it is:
EDITED THE CODE, STILL DOES NOT WORK
public class Ex3 {
public static void main(String[] args) { //main function
Scanner in = new Scanner(System.in); //scanner
int size = in.nextInt();
int[] arr = new int[size];
for (int i = 0; i<arr.length; i++){
arr[i] = in.nextInt();
}
in.close();
arr = merge3sort (arr); //send to the function to merge
for (int i = 0; i<arr.length; i++){ //printer
System.out.print(arr[i]+ " ");
}
}
static int[] split(int[] m, int thirdNum) { //split function that splits to 3 arrays
int third[] = new int[m.length/3];
int third1[]=new int[m.length/3];
int third2[]=new int[m.length/3];
for(int i = 0; i<=m.length/3; i++)
third[i]=m[i];
for(int i=0; i<=m.length/3;i++)
third1[i]=m[i+thirdNum];
for(int i=0; i<=m.length/3;i++)
third2[i]=m[i+2*thirdNum];
return merge(third,third1,third2);
//return null;
}
static int minOf3(int[] a3) { //function that finds out how what is the index of the smallest number
int num0 = a3[0];
int num1 = a3[1];
int num2 = a3[2];
int idx = 0;
if(num0<num1 && num1<num2)
idx=0;
if(num1<num0 && num0<num2)
idx=1;
else
idx=2;
return idx;
}
static int[] merge(int[] th0, int[] th1, int[] th2) { //function that sorts the numbers between 3 arrays
int len0=th0.length;
int len1=th1.length;
int len2=th2.length;
int[] united = new int[len0+len1+len2];
int ind = 0; int i0=0; int i1=0; int i2=0;
while(i0<len0 && i1<len1 && i2<len2){
if(th0[i0]<th1[i1]){
if(th0[i0]<th2[i2]){
united[ind]=th0[i0];
i0=i0+1;
}//end inner if
else{
united[ind]=th2[i2];
i2=i2+1;
}//end inner else
}//end outer if
else{
united[ind]=th1[i1];
i1=i1+1;
}//end outer else
ind=ind+1;
}//end while
for (int i = i0; i < len0; i = i + 1) {
united[ind] = th0[i];
ind = ind + 1;
}
for (int i = i1; i < len1; i = i + 1) {
united[ind] = th1[i];
ind = ind + 1;
}for (int i = i2; i < len2; i = i + 1) {
united[ind] = th2[i];
ind = ind + 1;
}
return united;
}
static int[] merge3sort(int[] m) { //function that glues all together
if (m.length == 1) {
return m;
}
else{
return merge(merge3sort(split(m,m.length/3)),merge3sort(split(m,m.length/3)),merge3sort(split(m,m.length/3))); }
}
I get the following exception:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at ololosh1.Ex3.split(Ex3.java:27)
at ololosh1.Ex3.merge3sort(Ex3.java:98)
at ololosh1.Ex3.main(Ex3.java:15)
Look at this part of your code:
for(int i = 0; i<=m.length/3; i++)
third[i]=m[i];
for(int i=0; i<=m.length/3;i++)
third1[i]=m[i+thirdNum];
for(int i=0; i<=m.length/3;i++)
third2[i]=m[i+2*thirdNum];
Arrays are indexed from 0 to length-1. Each third* array has length m.length/3. Therefore their index can only go up to m.length/3 - 1. Yet you are indexing up to and including m.length/3.
Once you get your application working correctly, you really should clean it up. There is a lot of redundancy. For example, you are using the expression m.length/3 multiple times in method split() but you are also passing that same value to it as an argument.

two quick fix issues - Merge Sort

I have created my version of the merge sort algorithm in java code. My issues are these: when I run the code as is, I get a NullPointerExecpetion in the main on line 27 (see commented line). And I know there is way to make the method calls and instantiate newArray without them being static but Im not quite sure how.. can someone help fix these? I am still relatively new to java so be nice :)
Main:
import java.util.Random;
public class MergeSort_main
{
public static void main(String[] args)
{
int[] originalArray = new int[1000];
Random rand = new Random();
for (int i = 0; i < originalArray.length; i++)
{
int randNum = rand.nextInt(1000)+1;
originalArray[i] = randNum;
}
for(int i = 0; i < originalArray.length; i++)
{
System.out.println(i+"." + originalArray[i]);
}
System.out.println("---------------------End Random Array-------\n");
MergeSortAlgorithm.mergeSortAlg(originalArray);
int[] sortedArray = MergeSortAlgorithm.getSortedArray();
for(int i = 0; i < sortedArray.length; i++) //NULL POINTER EXCEPTION HERE
{
System.out.println(i+ "." + sortedArray[i]);
}
}
}
Algorithm Class:
public class MergeSortAlgorithm
{
private static int[] newArray;
public static void mergeSortAlg(int[] randomNums)
{
int size = randomNums.length;
if (size < 2)
{
return; //if the array can not be split up further, stop attempting to split.
}
int half = size / 2;
int firstHalfNums = half;
int secondHalfNums = size - half;
int[] firstArray = new int[firstHalfNums];
int[] secondArray = new int[secondHalfNums];
for (int i = 0; i < half; i++)
{
firstArray[i] = randomNums[i];
}
for (int i = half; i < size; i++)
{
secondArray[i - half] = randomNums[i];
}
mergeSortAlg(firstArray);
mergeSortAlg(secondArray);
merge(firstArray, secondArray, randomNums);
}
public static void merge(int[] firstArray, int[] secondArray, int[] newArray)
{
int firstHalfNums = firstArray.length;
int secondHalfNums = secondArray.length;
int i = 0; //iterator for firstArray
int j = 0; //iterator for second array
int k = 0; //interator for randomNums array
while (i < firstHalfNums && j < secondHalfNums)
{
if (firstArray[i] <= secondArray[j])
{
newArray[k] = firstArray[i];
i++;
k++;
}
else
{
newArray[k] = secondArray[j];
k++;
j++;
}
}
while (i < firstHalfNums)
{
newArray[k] = firstArray[i];
k++;
i++;
}
while (j < firstHalfNums)
{
newArray[k] = secondArray[j];
k++;
j++;
}
}
public static int[] getSortedArray()
{
return newArray;
}
}
Basically, the only problem with your code is that you don't initialize newArray with any values, resulting in a null.
You are also redefining newArray at the top of your merge function .
The problem is that newArray[] is never instantiated i.e. newArray reference is pointing to null. And, no change is made in the newArray so value or reference returned to main is null. And, then you are performing sortedArray.length where sorted array having a null value.
You have to make newArray[] point to randomNums[].

Output of my merge sort algorithm is not sorted

Below is my code for the merge sort algorithm in java. It takes a string and an int array because I need to sort a string array with the int array. This implementation also counts inversions. My issue is that it's counting inversions fine, but when I print out the arrays themselves, it hasn't been changed at all.
the main method is me testing a 6 long array and printing out the inversions and arrays. when i run this test i get the following printed out.
4
1, 3, 4, 6, 2, 5
1, 3, 4, 6, 2, 5
public class Test {
private static int[] intSorted;
private static String[] stringSorted;
public static void main(String[] args) {
//Creates new string to sort
String[] string3 = {"1","3","4","6","2","5"};
//Creates new int to sort
int[] intt3 = {1,3,4,6,2,5};
//Calls sortAndCount on int and prints the number of inversions
System.out.println(sortAndCount(intt3, string3));
//Turns the int array into a string to print
StringBuilder intBuild = new StringBuilder();
for(int i = 0; i < intSorted.length; i++){
if(i+1 == intSorted.length){
intBuild.append(intSorted[i]);
}
else{
intBuild.append(intSorted[i] + ", ");
}
}
//Turns the string array into a string to print
StringBuilder stringBuild = new StringBuilder();
for(int i = 0; i < stringSorted.length; i++){
if(i+1 == stringSorted.length){
stringBuild.append(stringSorted[i]);
}
else{
stringBuild.append(stringSorted[i] + ", ");
}
}
System.out.println(intBuild);
System.out.println(stringBuild);
}
private static int sortAndCount(int intToSort[], String stringToSort[]){
int inversionsLeft;
int inversionsRight;
int inversionsMerged;
if(intToSort.length == 1){
return 0;
}
int m = intToSort.length/2;
int[] intLeft = new int[m];
String[] stringLeft = new String[m];
int[] intRight = new int[intToSort.length-m];
String[] stringRight = new String[intToSort.length-m];
for (int i=0; i < m; i++){
intLeft[i] = intToSort[i];
stringLeft[i] = stringToSort[i];
}
for (int i = 0;i < intRight.length; i++){
intRight[i] = intToSort[m+i];
stringRight[i] = stringToSort[m+i];
}
inversionsLeft = sortAndCount(intLeft, stringLeft);
inversionsRight = sortAndCount(intRight, stringRight);
intSorted = new int[intToSort.length];
stringSorted = new String[stringToSort.length];
inversionsMerged = mergeAndCount(intLeft, intRight, stringLeft, stringRight);
return(inversionsLeft + inversionsRight + inversionsMerged);
}
private static int mergeAndCount(int[] intLeft, int[] intRight, String[] stringLeft, String[] stringRight){
int count = 0;
int i = 0;
int j = 0;
int k = 0;
while(i < intLeft.length && j < intRight.length){
if(intLeft[i] < intRight[j]){
intSorted[k] = intLeft[i];
stringSorted[k] = stringLeft[i];
i++;
}
else{
intSorted[k] = intRight[j];
stringSorted[k] = stringRight[j];
count += intLeft.length - i + 1;
j++;
}
k++;
}
while (i < intLeft.length)
{
intSorted[k] = intLeft[i];
stringSorted[k] = stringLeft[i];
k++;
i++;
}
while (j < intRight.length)
{
intSorted[k] = intRight[j];
stringSorted[k] = stringRight[j];
j++;
k++;
}
return count;
}
I think the problem is here (comments added by me):
// Create some arrays into which we write the result of merging the
// arrays intLeft, intRight, stringLeft, stringRight.
intSorted = new int[intToSort.length];
stringSorted = new String[stringToSort.length];
// Do the merging into intSorted and stringSorted.
inversionsMerged = mergeAndCount(intLeft, intRight, stringLeft, stringRight);
// Oops... we haven't updated intToSort and stringToSort!
// We need to copy the sorted values from intSorted and stringSorted
// back into intToSort and stringToSort before we return.
return(inversionsLeft + inversionsRight + inversionsMerged);
I'll leave it up to you to fill in the gap.
I took your code, filled in the gap myself, and ran it. It seemed to work; this was the output I got:
7
1, 2, 3, 4, 5, 6
1, 2, 3, 4, 5, 6
Good luck!
Well the reason that your arrays don't get sorted is that your recursive algorithm keeps recreating the intSorted [] and stringSorted [] with each invocation.
Also your recursive method just returns an int (the number of inversions performed). In order of the recursive approach to work each sortAndCount must return it's piece of the array sorted. This makes it difficult to attempt to sort two different arrays in the same algorithm.
I have made a few minor tweaks to your code and now it sorts the int[] correctly.
If you want to count inversions at the same time that you sort, I would suggest adding a passByReference to a Counter object that does nothing but count inversions (like a visitor pattern).
Here is my code:
public class Test {
private static int[] intSorted;
public static void main(String[] args) {
//Creates new string to sort
//Creates new int to sort
int[] intt3 = {1,3,4,6,2,5};
//Calls sortAndCount on int and prints the number of inversions
System.out.println(sortAndCount(intt3));
//Turns the int array into a string to print
StringBuilder intBuild = new StringBuilder();
for(int i = 0; i < intSorted.length; i++){
if(i+1 == intSorted.length){
intBuild.append(intSorted[i]);
}
else{
intBuild.append(intSorted[i] + ", ");
}
}
//Turns the string array into a string to print
System.out.println(intBuild);
}
private static int[] sortAndCount(int intToSort[]){
int inversionsLeft;
int inversionsRight;
int inversionsMerged;
if(intToSort.length == 1){
return intToSort;
}
int m = intToSort.length/2;
int[] intLeft = new int[m];
String[] stringLeft = new String[m];
int[] intRight = new int[intToSort.length-m];
String[] stringRight = new String[intToSort.length-m];
for (int i=0; i < m; i++){
intLeft[i] = intToSort[i];
}
for (int i = 0;i < intRight.length; i++){
intRight[i] = intToSort[m+i];
}
intLeft = sortAndCount(intLeft);
intRight = sortAndCount(intRight);
intSorted = new int[intToSort.length];
intSorted = mergeAndCount(intLeft, intRight);
return intSorted;
}
private static int[] mergeAndCount(int[] intLeft, int[] intRight){
int count = 0;
int i = 0;
int j = 0;
int k = 0;
while(i < intLeft.length && j < intRight.length){
if(intLeft[i] < intRight[j]){
intSorted[k] = intLeft[i];
i++;
}
else{
intSorted[k] = intRight[j];
count += intLeft.length - i + 1;
j++;
}
k++;
}
while (i < intLeft.length)
{
intSorted[k] = intLeft[i];
k++;
i++;
}
while (j < intRight.length)
{
intSorted[k] = intRight[j];
j++;
k++;
}
return intSorted;
}
}

Sort an Integer Array and Store result with its index in Java

hello guys i need to sort some elements of integer in an integer array and need to store the index of the sorted list
assume if the elements in array are
x[]= {10,20,40,70,80,50,30};
i need to get the index of the sorted order say in this case i need to get 4,3,5,2,6,0 (ascending) (array x starting from 0)
A simple way (not algorithmically clever) would be to make a new list (or array) of objects from the existing list that contains the value and the index:
class ValueAndIndex implements Comparable<ValueAndIndex> {
final int value;
final int index;
ValueAndIndex(int value, int index) {
this.value = value;
this.index = index;
}
#Override public int compareTo(ValueAndIndex other) {
// compare on value;
if (this.value < other.value) {
return -1;
} else if (this.value > other.value) {
return 1;
} else {
return 0;
}
}
}
Now, create instances of this class in a list:
List<ValueAndIndex> secondaryList = new ArrayList<ValueAndIndex>(x.length);
for (int i = 0; i < x.length; ++i) {
secondaryList.add(new ValueAndIndex(x[i], i));
}
Sort this list:
Collections.sort(secondaryList);
Now, the indices are still in this list:
int [] indexesInSortedOrder = new int[x.length];
for (int i = 0; i < secondaryList.size(); ++i) {
indexesInSortedOrder[i] = secondaryList.get(i).index;
}
System.out.println(Arrays.toString(indexesInSortedOrder));
Possible solution
//sort the array intio a new array
y[] = x;
Arrays.sort(y); //sort ascending
//final array of indexes
int index_array[] = new int[7];
//iteretate on x arrat
for(int i=0; i<7; i++)
//search the position of a value of the original x array into the sorted y array, store the position in the index array
index_array[i] = arrays.binarySearch(x,y[i]);
you can create an array
y[] = {0,1,2,3,4,5,6};
And ith any sorting algorithm, when you switching moving two elements in array x, do the same in array y
One way to do (what I understand) you need:
Determine the size n of the original array.
Create result array R and initialize its elements with 0 . . n-1
Finally implement one sort algorithm in the way that it sorts a copy(!) of your original array whilst also switching the elements in R
Example run:
Copied Result
Array
------------------
1. 2-3-1 0-1-2
2. 2-1-3 0-2-1
3. 1-2-3 2-0-1
public Map sortDecendingDFSGlobal() {
Map<String, Object> multiValues = new HashMap<String, Object>();
double[] dfs = this.global_dfs;
int[] index = new int[dfs.length];
for (int i = 0; i < dfs.length; i++) {
index[i] = i;//for required indexing
}
for (int i = 0; i < dfs.length; i++) {
//sorting dfsglobal in decending order
double temp = dfs[i];
double swap = dfs[i];
int swapIndex = i;
//keeping track of changing indexing during sorting of dfsglobal
int indStart = index[i];
int indSwap = index[i];
int number = i;
for (int j = i; j < dfs.length; j++) {
if (temp < dfs[j]) {
temp = dfs[j];
swapIndex = j;
indSwap = index[j];
number = j;
}
}
dfs[i] = temp;
dfs[swapIndex] = swap;
index[i] = indSwap;
index[number] = indStart;
}
//again sorting the index matrix for exact indexing
for (int i = 0; i < index.length - 1; i++) {
for(int j = i; j < index.length - 1; j++ )
{
if(dfs[j] == dfs[j + 1] && index[j] > index[j + 1])
{
int temp = index[j];
index[j] = index[j+1];
index[j + 1] = temp;
}
}
}
this.sortedDFS = dfs;
this.arrIndex = index;
multiValues.put("sorted", dfs);
multiValues.put("index", index);
return multiValues;
} //SortedDecendingDFSGlobal()

Categories