Merge sort for string getting null pointer exception? - java

void MERGE(String[]A, int p, int q, int r) {
int n1 = q - p + 2;
int n2 = r - q + 1;
String[] L = new String[n1];
String[] R = new String[n2];
int i,j;
for (i = 0; i < L.length; i++) {
L[i] = A[p+i];
}
for (j = 0; i < R.length; j++) {
R[j] = A[q+j+1];
}
L[n1-1] = "";
R[n2-1] = "";
i = 0;
j = 0;
for (int k = p; k <= r; k++) {
if (L[i].compareToIgnoreCase(R[j]) < 0) {
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
}
}
public void MERGE_SORT(String[] A, int p, int r) {
if (p < r) {
int q = (p+r)/2;
MERGE_SORT(A, p, q);
MERGE_SORT(A, q+1, r);
MERGE(A, p, q, r);
}
}
This algorithm was originally for integers this how I changed it to sort strings. I get a NullPointerException. The problem seems to be at the compareToIgnoreCase() line. is this even how you implement mergesort for strings?
public static void main(String[] args) {
String[] sA = {"Jack", "John", "Mike", "Moss", "Xo"};
Sort ob = new Sort();
ob.MERGE_SORT(sA, 0, sA.length - 1);
}

The second for-loop in method MERGE uses the wrong variable i (instead of j) for checking the upper bound (i < R.length). It should be:
for (j = 0; j < R.length; j++) {
R[j] = A[q+j+1];
}
Apart from that, there are two other issues in the code:
(1) The for-loops for initializing L and R should run to L.length - 1 respectively R.length - 1:
for (i = 0; i < L.length - 1; i++) {
L[i] = A[p + i];
}
for (j = 0; j < R.length - 1; j++) {
R[j] = A[q + j + 1];
}
(2) You are using a sentinel in L and R at the last place to guarantee that the merging for-loop never exceeds the arrays. This sentinel should be larger than the largest possible value in the array. In case of an int[] this could be Integer.MAX_VALUE (which is just as large as the largest possible element, but this might be acceptable). But as you have arrays of String, you'd need the largest possible String value. You are using the empty String ("") instead, which is the smallest possible String:
L[n1 - 1] = "";
R[n2 - 1] = "";
For testing, you can use something like "ZZZ", but you should rewrite the merging algorithm to work without sentinel:
L[n1 - 1] = "ZZZ";
R[n2 - 1] = "ZZZ";

Related

I implemented this merge sort algorithm into java and it didn't work

This my introductory course to Algorithms, and I understand algorithms and I can design them, but this is the first time I tryed to apply it in java code, please tell me what i did wrong in this code for it to not work properly
I'm trying to apply this algorithm ,
this is the rest of the algorithm
This is my main void:
int[] A = { 5, 2, 4, 7, 1, 3, 2, 6 };
int p = 1;
int r = A.length;
Main obi = new Main ();
obi.mergeSort (A, p, r);
my first function:
public void mergeSort (int[]A, int p, int r) {
if (p < r){
int q = (p + r) / 2;
mergeSort (A, p, q);
mergeSort (A, q + 1, r);
merge (A, p, q, r);
}
}
my second function:
public void merge (int[]A, int p, int q, int r) {
int n1 = q - p + 1;
int n2 = r - q;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; i++){
L[i] = A[p + i - 1];
}
for (int j = 0; j < n2; j++){
R[j] = A[q + j];
}
int i = 0;
int j = 0;
for (int k = p - 1; k < r; k++){
if (L[i] <= R[j]){
A[k] = L[i];
i = i + 1;
} else {
A[k] = R[j];
j = j + 1;
}
}
}
And this is the error message I got:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at Main.merge(Main.java:44)
at Main.mergeSort(Main.java:19)
at Main.mergeSort(Main.java:17)
at Main.mergeSort(Main.java:17)
at Main.main(Main.java:10)
I tried to let L[] and R[] have length n1+1 and n2+1 but it didn't help.
There are multiple problems in your code:
the arguments r and q should be the index of the first element in the slice, hence int p = 0; in main() instead of 1, and the index past the last element in the slice, hence correctly int r = A.length;
With this convention, there is no need for confusing and error prone +1/-1 adjustments in the merge and mergeSort methods.
Furthermore, the merging loop in merge should be modified to avoid accessing L[i] or R[j] when the corresponding index reaches the length of the array.
Here is a modified version:
...
int[] A = { 5, 2, 4, 7, 1, 3, 2, 6 };
int p = 0;
int r = A.length;
Main obi = new Main();
obi.mergeSort(A, p, r);
...
public void mergeSort(int[]A, int p, int r) {
if (r - p > 1) {
int q = p + (r - p) / 2;
mergeSort(A, p, q);
mergeSort(A, q, r);
merge(A, p, q, r);
}
}
public void merge(int[]A, int p, int q, int r) {
int n1 = q - p;
int n2 = r - q;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; i++) {
L[i] = A[p + i];
}
for (int j = 0; j < n2; j++) {
R[j] = A[q + j];
}
int i = 0;
int j = 0;
for (int k = p; k < r; k++) {
if (i < n1 && (j >= n2 || L[i] <= R[j])) {
A[k] = L[i];
i = i + 1;
} else {
A[k] = R[j];
j = j + 1;
}
}
}
Note that the merge method can be simplified as the elements of the second half never get overwritten before they are moved into their final spot, so there is no need to save them:
public void merge(int[]A, int p, int q, int r) {
int n1 = q - p;
int L[] = new int[n1];
for (int i = 0; i < n1; i++) {
L[i] = A[p + i];
}
int i = 0;
int j = q;
int k = p;
while (i < n1) {
if (j >= r || L[i] <= A[j])
A[k++] = L[i++];
else
A[k++] = A[j++];
}
}
Either L or R finishes first.
for (int k = p - 1; k < r; k++){
if (L[i] <= R[j]){
A[k] = L[i];
i = i + 1;
} else {
A[k] = R[j];
j = j + 1;
}
}
Lets say L finishes first then i becomes L.length+1 so that when the next iteration occurs L[i] is invalid as its one past the end.

Union or intersection of Java Sets

What is the simplest way to make a union or an intersection of Sets in Java? I've seen some strange solutions to this simple problem (e.g. manually iterating the two sets).
The simplest one-line solution is this:
set1.addAll(set2); // Union
set1.retainAll(set2); // Intersection
The above solution is destructive, meaning that contents of the original set1 my change.
If you don't want to touch your existing sets, create a new set:
var result = new HashSet<>(set1); // In Java 10 and above
Set<Integer> result = new HashSet<>(set1); // In Java < 10
result.addAll(set2); // Union
result.retainAll(set2); // Intersection
While guava for sure is neater and pretty much standard, here's a non destructive way to do union and intersect using only standard Java
Set s1 = Set.of(1,2,3);
Set s2 = Set.of(3,4,5);
Set union = Stream.concat(s1.stream(),s2.stream()).collect(Collectors.toSet());
Set intersect = s1.stream().filter(s2::contains).collect(Collectors.toSet());
You can achieve this using Google's Guava library. The following explanation is given below with the help of an example:
// Set a
Set<String> a = new HashSet<String>();
a.add("x");
a.add("y");
a.add("z");
// Set b
Set<String> b = new HashSet<String>();
b.add("x");
b.add("p");
b.add("q");
Now, Calculating Intersection of two Set in Java:
Set<String> intersection = Sets.intersection(a, b);
System.out.printf("Intersection of two Set %s and %s in Java is %s %n",
a.toString(), b.toString(), intersection.toString());
Output: Intersection of two Set [z, y, x] and [q, p, x] in Java is [x]
Similarly, Calculating Union of two Set in Java:
Set<String> union = Sets.union(a, b);
System.out.printf("Union of two Set %s and %s in Java is %s %n",
a.toString(), b.toString(), union.toString());
Output: Union of two Set [z, y, x] and [q, p, x] in Java is [q, p, x, z, y]
You can read more about guava library at https://google.github.io/guava/releases/18.0/api/docs/
In order to add guava library to your project, You can see https://stackoverflow.com/a/4648947/8258942
import java.util.*;
public class sets {
public static void swap(int array[], int a, int b) { // Swap function for sorting
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
public static int[] sort(int array[]) { // sort function for binary search (Selection sort)
int minIndex;
int j;
for (int i = 0; i < array.length; i++) {
minIndex = i;
for (j = i + 1; j < array.length; j++) {
if (array[minIndex] > array[j])
minIndex = j;
}
swap(array, minIndex, i);
}
return array;
}
public static boolean search(int array[], int search) { // Binary search for intersection and difference
int l = array.length;
int mid = 0;
int lowerLimit = 0, upperLimit = l - 1;
while (lowerLimit <= upperLimit) {
mid = (lowerLimit + upperLimit) / 2;
if (array[mid] == search) {
return true;
} else if (array[mid] > search)
upperLimit = mid - 1;
else if (array[mid] < search)
lowerLimit = mid + 1;
}
return false;
}
public static int[] append(int array[], int add) { // To add elements
int newArray[] = new int[array.length + 1];
for (int i = 0; i < array.length; i++) {
newArray[i] = array[i];
}
newArray[array.length] = add;
newArray = sort(newArray);
return newArray;
}
public static int[] remove(int array[], int index) { // To remove duplicates
int anotherArray[] = new int[array.length - 1];
int k = 0;
if (array == null || index < 0 || index > array.length) {
return array;
}
for (int i = 0; i < array.length; i++) {
if (index == i) {
continue;
}
anotherArray[k++] = array[i];
}
return anotherArray;
}
public static void Union(int A[], int B[]) { // Union of a set
int union[] = new int[A.length + B.length];
for (int i = 0; i < A.length; i++) {
union[i] = A[i];
}
for (int j = A.length, i = 0; i < B.length || j < union.length; i++, j++) {
union[j] = B[i];
}
for (int i = 0; i < union.length; i++) {
for (int j = 0; j < union.length; j++) {
if (union[i] == union[j] && j != i) {
union = remove(union, j); // Removing duplicates
}
}
}
union = sort(union);
System.out.print("A U B = {"); // Printing
for (int i = 0; i < union.length; i++) {
if (i != union.length - 1)
System.out.print(union[i] + ", ");
else
System.out.print(union[i] + "}");
}
}
public static void Intersection(int A[], int B[]) {
int greater = (A.length > B.length) ? (A.length) : (B.length);
int intersect[] = new int[1];
int G[] = (A.length > B.length) ? A : B;
int L[] = (A.length < B.length) ? A : B;
for (int i = 0; i < greater; i++) {
if (search(L, G[i]) == true) { // Common elements
intersect = append(intersect, G[i]);
}
}
for (int i = 0; i < intersect.length; i++) {
for (int j = 0; j < intersect.length; j++) {
if (intersect[i] == intersect[j] && j != i) {
intersect = remove(intersect, j); // Removing duplicates
}
}
}
System.out.print("A ∩ B = {"); // Printing
for (int i = 1; i < intersect.length; i++) {
if (i != intersect.length - 1)
System.out.print(intersect[i] + ", ");
else
System.out.print(intersect[i] + "}");
}
}
public static void difference(int A[], int B[]) {
int diff[] = new int[1];
int G[] = (A.length > B.length) ? A : B;
int L[] = (A.length < B.length) ? A : B;
int greater = G.length;
for (int i = 0; i < greater; i++) {
if (search(L, G[i]) == false) {
diff = append(diff, G[i]); // Elements not in common
}
}
for (int i = 0; i < diff.length; i++) {
for (int j = 0; j < diff.length; j++) {
if (diff[i] == diff[j] && j != i) {
diff = remove(diff, j); // Removing duplicates
}
}
}
System.out.println("Where A is the larger set, and B is the smaller set.");
System.out.print("A - B = {"); // Printing
for (int i = 1; i < diff.length; i++) {
if (i != diff.length - 1)
System.out.print(diff[i] + ", ");
else
System.out.print(diff[i] + "}");
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the operation");
String operation = sc.next().toLowerCase();
System.out.println("Enter the length of the first set.");
int l1 = sc.nextInt();
System.out.println("Enter the length of the second set.");
int l2 = sc.nextInt();
int A[] = new int[l1];
int B[] = new int[l2];
System.out.println("Enter the elements of the first set.");
System.out.print("A = ");
for (int i = 0; i < l1; i++) {
A[i] = sc.nextInt();
}
System.out.println("Enter the elements of the second set.");
System.out.print("B = ");
for (int i = 0; i < l2; i++) {
B[i] = sc.nextInt();
}
A = sort(A); // Sorting the sets before passing
B = sort(B);
sc.close();
switch (operation) {
case "union":
Union(A, B);
break;
case "intersection":
Intersection(A, B);
break;
case "difference":
difference(B, A);
break;
default:
System.out.println("Invalid Operation");
}
}
}
When I think of union and intersection, it is in the first loop an operation on sets, i.e. a map
            Set<T>  x  Set<T>  →  Set<T>Not clear, why it would appear in Java design that shirtsleeved.
static <T> Set<T> union(Set<T> a, Set<T> b)
{
Set<T> res = new HashSet<T>(a);
res.addAll(b);
return res;
}
static <T> Set<T> intersection(Set<T> a, Set<T> b)
{
Set<T> res = new HashSet<T>(a);
res.retainAll(b);
return res;
}

Merge sort implementation questions in Java

I'm in an algorithms course and am learning about merge sort. Our professor recommended we try to implement the pseudo code provided in the book.
Am I correct in using Integer.MAX_VALUE as a sentinel value when
sorting an array of integers (used in lines 8 & 9 in the Merge
method pseudo code below)?
For line 2 of the Merge-Sort pseudo code method, is it correct to code that in Java using Math.ceil() like I did? (Edit: It's actually floor and I updated my code to reflect this.)
If you see any other mistakes please let me know!
Here is the pseudo code the book gives for merge sort.
And, here is how I coded it in Java:
public void mergeSort(int[] arrNums, int p, int r) {
if (p < r) {
int q = (p + r) / 2;
mergeSort(arrNums, p, q);
mergeSort(arrNums, q + 1, r);
merge(arrNums, p, q, r);
}
}
public void merge(int[] arrNums, int p, int q, int r) {
int nOne = q - p + 1;
int nTwo = r - q;
int[] arrLeft = new int[nOne + 1];
int[] arrRight = new int[nTwo + 1];
for (int i = 0; i < nOne; i++) {
arrLeft[i] = arrNums[p + i - 1];
}
for (int j = 0; j < nTwo; j++) {
arrRight[j] = arrNums[q + j];
}
arrLeft[nOne] = Integer.MAX_VALUE;
arrRight[nTwo] = Integer.MAX_VALUE;
// Tracks arrLeft index
int i = 0;
// Tracks arrRight index
int j = 0;
for (int k = p; k < r; k++) {
if (arrLeft[i] <= arrRight[j]) {
arrNums[k] = arrLeft[i];
i++;
} else {
arrNums[k] = arrRight[j];
j++;
}
}
}
The last for loop in your merge method, variable k should start from p - 1:
for (int k = p - 1; k < r; k++) {
if (arrLeft[i] <= arrRight[j]) {
arrNums[k] = arrLeft[i];
i++;
} else {
arrNums[k] = arrRight[j];
j++;
}
}
Pseudo code in many text books likes to start array index from 1, so here you need to subtract it by 1.
I implemented it a few days ago, if someone will be interested.
private static void mergeSort(double[] arr, int start, int end){
if(start < end){
int mid = ( start + end ) / 2;
mergeSort(arr, start, mid);
mergeSort(arr, mid + 1, end);
Merge(arr, start, mid, end);
}
}
private static void Merge(double[] arr, int start, int mid, int end){
double[] leftArray = new double[mid - start + 2];
double[] rightArray = new double[end - mid + 1];
for(int i = start; i <= mid; i++ )
leftArray[i - start] = arr[i];
for (int i = mid + 1; i <= end; i++ )
rightArray[i - mid - 1] = arr[i];
leftArray[mid - start + 1] = Double.POSITIVE_INFINITY;
rightArray[end - mid] = Double.POSITIVE_INFINITY;
int leftIndex = 0, rightIndex = 0;
for (int k = start; k <= end; k++){
if(leftArray[leftIndex] <= rightArray[rightIndex])
arr[k] = leftArray[leftIndex++];
else
arr[k] = rightArray[rightIndex++];
}
}

Dynamic Programming algorithm for Longest Common Subsequence in Java

I'm trying to write a dynamic programming algorithm for the Longest Common Subsequence.
The return should be the length of this subsequence.
But my algorithm always returns 0. I couldn't find the error.
public static int LCS(String A, String B, int m, int n) {
int table[][] = new int[m + 1][n + 1];
for (int i = 0; i < m; i++) {
table[i][0] = 0;
}
for (int i = 1; i < n; i++) {
table[0][n] = 0;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (A.charAt(i) == B.charAt(j)) {
table[i][j] = table[i - 1][j - 1] + 1;
} else {
table[i][j] = max(table[i][j - 1], table[i - 1][j]);
}
}
}
return table[m][n];
}
private static int max(int a, int b) {
return (a > b) ? a : b;
}
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
System.out.println("Your input words:\n");
String x = in.nextLine();
String y = in.nextLine();
in.close();
int m = x.length();
int n = y.length();
System.out.println("Length of LCS is " + LCS(x, y, m, n));
}
Looks like you implemented this algorithm, but have a few errors:
Your loops should be 1..m and 1..n inclusive, meaning you need to change < to <=.
charAt() is zero-based, so you need charAt(i - 1) and charAt(j - 1).
These are not errors, but:
The loops to initialize to 0 are unnecessary in Java. table is already initialized to all zeroes by the new operator.
No need to implement max(), since it's already implemented as Math.max().
So, here is the result, using names from the linked article:
public static int LCS(String X, String Y) {
final int m = X.length();
final int n = Y.length();
int[][] C = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (X.charAt(i - 1) == Y.charAt(j - 1))
C[i][j] = C[i - 1][j - 1] + 1;
else
C[i][j] = Math.max(C[i][j - 1], C[i - 1][j]);
return C[m][n];
}
TEST
System.out.println(LCS("This is a test", "Does it work ok?"));
OUTPUT
5
Here is the matching letters of the longest common subsequence:
This is a test
↑↑↑ ↑ ↑
↓↓↓ ↓ ↓
Does it work ok?
The conditions in the for loops use i < m or j < n.
As a consequence i is never equal to m and j is never equal to n, so table[m][n] is never modified inside these loops, right?
The value returned is the value at table[m][n] which is never modified: 0.

having problems with mergesort algorithm

I am currently trying to transcribe a mergesort algorithm from a pseudocode level to a working implementation in java. This is my code
public int[] merge(int a[], int b[]) {
int c[] = new int[a.length + b.length];
int i = 0, j = 0;
for (int k = 0; k < c.length; k++) {
if (a[i] <= b[j]) {
c[k] = a[i++];
} else {
c[k] = b[j++];
}
}
return c;
}
The pseudocode interpretation is correct to the best of my knowledge but it keeps returning an ArrayOutofBound Exception.
Where did I get it all wrong.
This would obviously give the out of bound exception because you are not keeping track of the length of a and b arrays . Since k = a + b , a and b will always be less than k . Hence the exception.
And when you apply this check, remember to copy the remaining of the items, whether they are of a[] or b[] , to copy them to c[]. See this -
for(;i<a.length;i++)
c[k++] = a[i++];
for(;j<b.length;b++)
c[k++] = b[j++];
The merge algorithm in the way you intend to implement it is a bit more elaborated, below you'll find a correct implementation:
public int[] merge(int a[], int b[]) {
int i = 0, j = 0, k = 0;
int m = a.length, n = b.length;
int[] c = new int[m + n];
// Merge to the end of one of the source arrays
while (i < m && j < n) {
if (a[i] <= b[j]) {
c[k] = a[i];
i++;
} else {
c[k] = b[j];
j++;
}
k++;
}
// Determine which source array has elements remaining and
// append those to the result array
if (i < m) {
for (int p = i; p < m; p++) {
c[k] = a[p];
k++;
}
} else {
for (int p = j; p < n; p++) {
c[k] = b[p];
k++;
}
}
return c;
}

Categories