From f4addcd9a443bf4e6b1b1318ecc4d1fad061e8fc Mon Sep 17 00:00:00 2001
From: Brandon Gastelo <shady1765@gmail.com>
Date: Fri, 19 Oct 2018 22:54:20 -0700
Subject: [PATCH] Added support for using merge sort on generic objects
 implementing the Comparable interface.

Added merge sort implementations for missing primitive types: byte, char, float, short, and long.
Added test cases for each type.
---
 .../allalgorithms/sorting/MergeSort.java      | 815 ++++++++++++++----
 .../allalgorithms/sorting/MergeSortTest.java  |  56 +-
 2 files changed, 700 insertions(+), 171 deletions(-)

diff --git a/src/main/java/com/abranhe/allalgorithms/sorting/MergeSort.java b/src/main/java/com/abranhe/allalgorithms/sorting/MergeSort.java
index afb46ec..d47c625 100644
--- a/src/main/java/com/abranhe/allalgorithms/sorting/MergeSort.java
+++ b/src/main/java/com/abranhe/allalgorithms/sorting/MergeSort.java
@@ -23,179 +23,654 @@
 
 package com.abranhe.allalgorithms.sorting;
 
+import java.util.Arrays;
+
 /**
- * The class {@code MergeSort} contains methods for performing
- * a poor :( merge sort algorithm of Integers and Doubles
+ * The class {@code MergeSort} contains methods for performing a poor :( merge
+ * sort algorithm of Integers and Doubles
  *
- * @author  Carlos Abraham Hernandez
- * @since   0.0.1
+ * @author Carlos Abraham Hernandez
+ * @author Brandon Gastelo
+ * @since 0.0.1
  */
 public class MergeSort {
 
-    /**
-     * This class should not be instantiated.
-     */
-    private MergeSort() { }
-
-    /**
-     * Merges two subarrays of arr[].
-     * First subarray is arr[l..m]
-     * Second subarray is arr[m+1..r]
-     *
-     * @param arr array
-     * @param l index to start sorting
-     * @param m index of the middle of the array
-     * @param r index to finish sorting
-     */
-    private static void merge(int arr[], int l, int m, int r) {
-
-        int n1 = m - l + 1;
-        int n2 = r - m;
-
-        int L[] = new int [n1];
-        int R[] = new int [n2];
-
-        System.arraycopy(arr, l + 0, L, 0, n1);
-
-        for (int j=0; j<n2; ++j)
-            R[j] = arr[m + 1+ j];
-
-        int i = 0, j = 0;
-
-        int k = l;
-        while (i < n1 && j < n2) {
-            if (L[i] <= R[j]) {
-                arr[k] = L[i];
-                i++;
-            }
-            else {
-                arr[k] = R[j];
-                j++;
-            }
-            k++;
-        }
-
-        while (i < n1) {
-            arr[k] = L[i];
-            i++;
-            k++;
-        }
-
-        while (j < n2) {
-            arr[k] = R[j];
-            j++;
-            k++;
-        }
-    }
-
-    /**
-     * Merges two subarrays of arr[]. type double
-     * First subarray is arr[l..m]
-     * Second subarray is arr[m+1..r]
-     *
-     * @param arr array
-     * @param l index to start sorting
-     * @param m index of the middle of the array
-     * @param r index to finish sorting
-     */
-    private static void merge(double arr[], int l, int m, int r) {
-
-        int n1 = m - l + 1;
-        int n2 = r - m;
-
-        double L[] = new double [n1];
-        double R[] = new double [n2];
-
-        System.arraycopy(arr, l + 0, L, 0, n1);
-
-        for (int j=0; j<n2; ++j)
-            R[j] = arr[m + 1+ j];
-
-        int i = 0, j = 0;
-
-        int k = l;
-        while (i < n1 && j < n2) {
-            if (L[i] <= R[j]) {
-                arr[k] = L[i];
-                i++;
-            }
-            else {
-                arr[k] = R[j];
-                j++;
-            }
-            k++;
-        }
-
-        while (i < n1) {
-            arr[k] = L[i];
-            i++;
-            k++;
-        }
-
-        while (j < n2) {
-            arr[k] = R[j];
-            j++;
-            k++;
-        }
-    }
-
-    /**
-     * Sort array of integers
-     * @param arr array
-     * @param l index to start sorting
-     * @param r index to finish sorting
-     */
-    private static void sort(int arr[], int l, int r) {
-        if (l < r) {
-
-            int m = (l+r)/2;
-
-            sort(arr, l, m);
-            sort(arr , m+1, r);
-
-            merge(arr, l, m, r);
-        }
-    }
-
-    /**
-     * Sort array of doubles
-     * @param arr array
-     * @param l index to start sorting
-     * @param r index to finish sorting
-     */
-    private static void sort(double arr[], int l, int r) {
-        if (l < r) {
-
-            int m = (l+r)/2;
-
-            sort(arr, l, m);
-            sort(arr , m+1, r);
-
-            merge(arr, l, m, r);
-        }
-    }
-
-    /**
-     * The sort method of the {@code MergeSort} class
-     * takes an array of {@code Integers} an sort it.
-     *
-     * @param arr array of integers to be sorted
-     */
-    public static void sort(int arr[]) {
-        int l = 0;
-        int r = arr.length-1;
-        sort(arr, l, r);
-    }
-
-    /**
-     * The sort method of the {@code MergeSort} class
-     * takes an array of {@code Double} an sort it.
-     *
-     * @param arr array of doubles to be sorted
-     */
-    public static void sort(double arr[]) {
-        int l = 0;
-        int r = arr.length-1;
-        sort(arr, l, r);
-    }
+	/**
+	 * This class should not be instantiated.
+	 */
+	private MergeSort() {
+	}
+	
+	/**
+	 * Merges two subarrays of arr[]. First subarray is arr[l..m] Second subarray is
+	 * arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static void merge(byte arr[], int l, int m, int r) {
+
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		byte L[] = new byte[n1];
+		byte R[] = new byte[n2];
+
+		System.arraycopy(arr, l + 0, L, 0, n1);
+
+		for (int j = 0; j < n2; ++j)
+			R[j] = arr[m + 1 + j];
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i] <= R[j]) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * Merges two subarrays of arr[]. First subarray is arr[l..m] Second subarray is
+	 * arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static void merge(char arr[], int l, int m, int r) {
+
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		char L[] = new char[n1];
+		char R[] = new char[n2];
+
+		System.arraycopy(arr, l + 0, L, 0, n1);
+
+		for (int j = 0; j < n2; ++j)
+			R[j] = arr[m + 1 + j];
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i] <= R[j]) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * Merges two subarrays of arr[]. type double First subarray is arr[l..m] Second
+	 * subarray is arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static void merge(double arr[], int l, int m, int r) {
+
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		double L[] = new double[n1];
+		double R[] = new double[n2];
+
+		System.arraycopy(arr, l + 0, L, 0, n1);
+
+		for (int j = 0; j < n2; ++j)
+			R[j] = arr[m + 1 + j];
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i] <= R[j]) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * Merges two subarrays of arr[]. First subarray is arr[l..m] Second subarray is
+	 * arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static void merge(float arr[], int l, int m, int r) {
+
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		float L[] = new float[n1];
+		float R[] = new float[n2];
+
+		System.arraycopy(arr, l + 0, L, 0, n1);
+
+		for (int j = 0; j < n2; ++j)
+			R[j] = arr[m + 1 + j];
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i] <= R[j]) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * Merges two subarrays of arr[]. First subarray is arr[l..m] Second subarray is
+	 * arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static void merge(int arr[], int l, int m, int r) {
+
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		int L[] = new int[n1];
+		int R[] = new int[n2];
+
+		System.arraycopy(arr, l + 0, L, 0, n1);
+
+		for (int j = 0; j < n2; ++j)
+			R[j] = arr[m + 1 + j];
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i] <= R[j]) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * Merges two subarrays of arr[]. First subarray is arr[l..m] Second subarray is
+	 * arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static void merge(long arr[], int l, int m, int r) {
+
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		long L[] = new long[n1];
+		long R[] = new long[n2];
+
+		System.arraycopy(arr, l + 0, L, 0, n1);
+
+		for (int j = 0; j < n2; ++j)
+			R[j] = arr[m + 1 + j];
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i] <= R[j]) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * Merges two subarrays of arr[]. First subarray is arr[l..m] Second subarray is
+	 * arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static void merge(short arr[], int l, int m, int r) {
+
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		short L[] = new short[n1];
+		short R[] = new short[n2];
+
+		System.arraycopy(arr, l + 0, L, 0, n1);
+
+		for (int j = 0; j < n2; ++j)
+			R[j] = arr[m + 1 + j];
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i] <= R[j]) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * Merges two subarrays of arr[]. generic type First subarray is arr[l..m]
+	 * Second subarray is arr[m+1..r]
+	 *
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param m   index of the middle of the array
+	 * @param r   index to finish sorting
+	 */
+	private static <T extends Comparable<? super T>> void merge(T arr[], int l, int m, int r) {
+		int n1 = m - l + 1;
+		int n2 = r - m;
+
+		T L[] = Arrays.copyOfRange(arr, l, l + n1);
+		T R[] = Arrays.copyOfRange(arr, m + 1, r + 1);
+
+		int i = 0, j = 0;
+
+		int k = l;
+		while (i < n1 && j < n2) {
+			if (L[i].compareTo(R[j]) <= 0) {
+				arr[k] = L[i];
+				i++;
+			} else {
+				arr[k] = R[j];
+				j++;
+			}
+			k++;
+		}
+
+		while (i < n1) {
+			arr[k] = L[i];
+			i++;
+			k++;
+		}
+
+		while (j < n2) {
+			arr[k] = R[j];
+			j++;
+			k++;
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of {@code Byte}
+	 * an sort it.
+	 *
+	 * @param arr array of doubles to be sorted
+	 */
+	public static void sort(byte arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of bytes
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static void sort(byte arr[], int l, int r) {
+		if (l < r) {
+
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of
+	 * {@code Character} an sort it.
+	 *
+	 * @param arr array of doubles to be sorted
+	 */
+	public static void sort(char arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of characters
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static void sort(char arr[], int l, int r) {
+		if (l < r) {
+
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of
+	 * {@code Double} an sort it.
+	 *
+	 * @param arr array of doubles to be sorted
+	 */
+	public static void sort(double arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of doubles
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static void sort(double arr[], int l, int r) {
+		if (l < r) {
+
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of
+	 * {@code Float} an sort it.
+	 *
+	 * @param arr array of doubles to be sorted
+	 */
+	public static void sort(float arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of floats
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static void sort(float arr[], int l, int r) {
+		if (l < r) {
+
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of
+	 * {@code Integers} an sort it.
+	 *
+	 * @param arr array of integers to be sorted
+	 */
+	public static void sort(int arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of integers
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static void sort(int arr[], int l, int r) {
+		if (l < r) {
+
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of {@code Long}
+	 * an sort it.
+	 *
+	 * @param arr array of doubles to be sorted
+	 */
+	public static void sort(long arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of longs
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static void sort(long arr[], int l, int r) {
+		if (l < r) {
+
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of
+	 * {@code Short} an sort it.
+	 *
+	 * @param arr array of doubles to be sorted
+	 */
+	public static void sort(short arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of shorts
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static void sort(short arr[], int l, int r) {
+		if (l < r) {
+
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
+
+	/**
+	 * The sort method of the {@code MergeSort} class takes an array of
+	 * {@code Comparable} objects and sorts them.
+	 *
+	 * @param arr array of objects to be sorted
+	 */
+	public static <T extends Comparable<? super T>> void sort(T arr[]) {
+		int l = 0;
+		int r = arr.length - 1;
+		sort(arr, l, r);
+	}
+
+	/**
+	 * Sort array of generic objects
+	 * 
+	 * @param arr array
+	 * @param l   index to start sorting
+	 * @param r   index to finish sorting
+	 */
+	private static <T extends Comparable<? super T>> void sort(T[] arr, int l, int r) {
+		if (l < r) {
+			int m = (l + r) / 2;
+
+			sort(arr, l, m);
+			sort(arr, m + 1, r);
+
+			merge(arr, l, m, r);
+		}
+	}
 }
diff --git a/src/test/java/com/abranhe/allalgorithms/sorting/MergeSortTest.java b/src/test/java/com/abranhe/allalgorithms/sorting/MergeSortTest.java
index 04e2bf5..1d98943 100644
--- a/src/test/java/com/abranhe/allalgorithms/sorting/MergeSortTest.java
+++ b/src/test/java/com/abranhe/allalgorithms/sorting/MergeSortTest.java
@@ -27,6 +27,42 @@
 
 public class MergeSortTest {
 
+	private byte[] bytesArr = {7, -3, 0, 30, 19, 27};
+    private byte[] expectedBytesArr = {-3, 0, 7, 19, 27, 30};
+
+    @Test public void sortBytes() {
+        MergeSort.sort(bytesArr);
+        assertArrayEquals("Sort Bytes", expectedBytesArr, bytesArr);
+
+    }
+	
+    private char[] charsArr = {7, 3, 0, 30, 19, 27};
+    private char[] expectedCharsArr = {0, 3, 7, 19, 27, 30};
+
+    @Test public void sortChars() {
+        MergeSort.sort(charsArr);
+        assertArrayEquals("Sort Chars", expectedCharsArr, charsArr);
+
+    }
+    
+    private short[] shortsArr = {7, -3, 0, 30, 19, 27};
+    private short[] expectedShortsArr = {-3, 0, 7, 19, 27, 30};
+
+    @Test public void sortShorts() {
+        MergeSort.sort(shortsArr);
+        assertArrayEquals("Sort Shorts", expectedShortsArr, shortsArr);
+
+    }
+    
+    private long[] longsArr = {7, -3, 0, 30, 19, 27};
+    private long[] expectedLongsArr = {-3, 0, 7, 19, 27, 30};
+
+    @Test public void sortLongs() {
+        MergeSort.sort(longsArr);
+        assertArrayEquals("Sort Longs", expectedLongsArr, longsArr);
+
+    }
+    
     private int[] integersArr = {7, -3, 0, 30, 19, 27};
     private int[] expectedIntegersArr = {-3, 0, 7, 19, 27, 30};
 
@@ -43,4 +79,22 @@ public class MergeSortTest {
         MergeSort.sort(doublesArr);
         assertArrayEquals("Sort Doubles", expectedDoublesArr, doublesArr, 7);
     }
-}
\ No newline at end of file
+    
+    private String[] stringsArr = {"Dog", "Cat", "Car", "Tree", "House", "Java"};
+    private String[] expectedStringsArr = {"Car", "Cat", "Dog", "House", "Java" , "Tree"};
+    
+    @Test public void sortStrings() {
+    	MergeSort.sort(stringsArr);
+    	assertArrayEquals("Sort Strings", stringsArr, expectedStringsArr);
+    }
+    
+    private float[] floatsArr = {7f, 1f, 9f, 0f, 7f, -3f};
+    private float[] expectedFloatsArr = {-3f, 0f, 1f, 7f, 7f, 9f};
+
+    @Test public void sortFloats() {
+        MergeSort.sort(floatsArr);
+        assertArrayEquals("Sort Floats", expectedFloatsArr, floatsArr, 7);
+    }
+    
+    
+}