package Sorts; import java.lang.Math; import java.util.Random; /** * @author [Hemanth Kotagiri](https://github.com/hemanth-kotagiri) * @see [Tim Sort](https://en.wikipedia.org/wiki/Tim_sort) */ class TimSort { int array[]; int array_length; int RUN = 32; /** * @brief A constructor which takes in the array specified by the user. * @param array : Array given by the user. */ public TimSort(int[] array) { this.array = array; this.array_length = array.length; } /** * @brief A constructor which takes in an array length and randomly * initializes an array. * @param array_length length given by the user. */ public TimSort(int array_length) { Random rand = new Random(); this.array_length = array_length; this.array = new int[this.array_length]; for (int i = 0; i < this.array_length; i++) { int random_number = rand.nextInt(1000); this.array[i] = random_number; } } /** * @brief A method to change the size of the run. * @param run : Value specified by the user to change the run. */ public void change_run(int run) { this.RUN = run; } /** * @brief A default constructor when no parameters are given. * Initializes the array length to be 100. * Generates a random number array of size 100. */ public TimSort() { this.array_length = 100; this.array = new int[this.array_length]; Random rand = new Random(); for (int i = 0; i < this.array_length; i++) { int random_number = rand.nextInt(1000); this.array[i] = random_number; } } /** * @brief Performs Insertion Sort Algorithm on given array with bounded * indices. * @param array: The array on which the algorithm is to be performed. * @param start_idx: The starting index from which the algorithm is to be * performed. * @param end_idx: The ending index at which the algorithm needs to stop * sorting. */ public void insertion_sort(int[] array, int start_idx, int end_idx) { for (int i = 0; i < array.length; i++) { int current_element = array[i]; int j = i - 1; while (j >= 0 && array[j] > current_element) { array[j + 1] = array[j]; j--; } array[j + 1] = current_element; } } /** * @brief A method to merge two runs(chunks of array). * @param array: The origin array which is to be sorted. * @param start: Starting index of the first run(chunk). * @param mid: The ending index of the first run(chunk). * @param end: Ending index of the second run(chunk). */ public void merge_runs(int array[], int start, int mid, int end) { int first_array_size = mid - start + 1, second_array_size = end - mid; int array1[] = new int[first_array_size], array2[] = new int[second_array_size]; int i = 0, j = 0, k = 0; // Building the two sub arrays from the array to merge later for (i = 0; i < first_array_size; i++) array1[i] = array[start + i]; for (i = 0; i < second_array_size; i++) array2[i] = array[mid + 1 + i]; i = 0; j = 0; k = start; while (i < first_array_size && j < second_array_size) { if (array1[i] <= array2[j]) { array[k] = array1[i]; i++; } else { array[k] = array2[j]; j++; } k++; } while (i < first_array_size) { array[k] = array1[i]; k++; i++; } while (j < second_array_size) { array[k] = array2[j]; k++; j++; } } /** * @brief Tim Sort Algorithm method. */ public void algorithm() { // Before Sorting System.out.println("Before sorting the array: "); this.showArrayElements(); System.out.println(); // Applying insertion sort on RUNS. for (int i = 0; i < this.array_length; i += this.RUN) this.insertion_sort(this.array, i, Math.min(i + this.RUN, (this.array_length - 1))); for (int split = this.RUN; split < this.array_length; split = 2 * split) { for (int start_idx = 0; start_idx < this.array_length; start_idx += 2 * split) { int mid = start_idx + split - 1; int end_idx = Math.min((start_idx + 2 * split - 1), (this.array_length - 1)); this.merge_runs(this.array, start_idx, mid, end_idx); } } // After sorting System.out.println("After sorting the array: "); this.showArrayElements(); System.out.println(); } /** * @brief A method to show the elements inside the array. */ public void showArrayElements() { for (int i = 0; i < this.array.length; i++) { System.out.print(this.array[i] + " "); } System.out.println(); } /** * @brief A method to test the sorting algorithm */ static void test() { int[] array = { 4, 1, 3, 17, 12, 11, 8 }; TimSort sorterObj1 = new TimSort(); TimSort sorterObj2 = new TimSort(50); TimSort sorterObj3 = new TimSort(array); sorterObj1.algorithm(); sorterObj2.algorithm(); sorterObj3.algorithm(); // Testing the first array for(int i = 0; i < sorterObj1.array_length - 1; i++) { assert((sorterObj1.array[i] <= sorterObj1.array[i +1])) : "Array is not sorted"; } // Testing the second array. for(int i = 0; i < sorterObj2.array_length - 1; i++) { assert((sorterObj2.array[i] <= sorterObj2.array[i + 1])) : "Array is not sorted"; } // Testing the third array. for(int i = 0; i < sorterObj3.array_length - 1; i++) { assert((sorterObj3.array[i] <= sorterObj3.array[i + 1])) : "Array is not sorted"; } } public static void main(String[] args) { test(); } }