Skip to content

Commit 011b31e

Browse files
committed
Added mergesort iterative int implementation
1 parent 9d60203 commit 011b31e

File tree

3 files changed

+170
-9
lines changed

3 files changed

+170
-9
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,116 @@
11
package src.algorithms.sorting.mergeSort.iterative;
22

3+
/** Here, we are implementing MergeSort where we sort the array in increasing (or more precisely, non-decreasing)
4+
* order iteratively.
5+
*
6+
* Brief Description:
7+
* The iterative implementation of MergeSort takes a bottom-up approach, where the sorting process starts by merging
8+
* intervals of size 1. Intervals of size 1 are trivially in sorted order. The algorithm then proceeds to merge
9+
* adjacent sorted intervals, doubling the interval size with each merge step, until the entire array is fully sorted.
10+
*
11+
* Implementation Invariant:
12+
* At each iteration of the merging process, the main array is divided into sub-arrays of a certain interval
13+
* size (<interval>). Each of these sub-arrays is sorted within itself. The last sub-array may not be of size
14+
* <interval> but it is still sorted since its size is necessarily less than <interval>.
15+
*
16+
* Complexity Analysis:
17+
* Time:
18+
* - Worst case: O(nlogn)
19+
* - Average case: O(nlogn)
20+
* - Best case: O(nlogn)
21+
*
22+
* Given two sorted arrays of size p and q, we need O(p + q) time to merge the two arrays into one sorted array, since
23+
* we have to iterate through every element in both arrays once.
24+
*
25+
* At the 1st level of the merge process, our merging subroutine involves n sub-arrays of size 1, taking O(n) time.
26+
* At the 2nd level of the merge process, our merging subroutine involves (n/2) sub-arrays of size 2, taking O(n) time.
27+
* At the kth level of the merge process, our merging subroutine involves (n/(2^(k-1))) sub-arrays of size (2^(k-1)),
28+
* taking O(n) time.
29+
*
30+
* Since <interval> doubles at every iteration of the merge process, there are logn such levels. Every level takes
31+
* O(n) time, hence overall time complexity is n * logn = O(nlogn)
32+
*
33+
* Regardless of how sorted the input array is, MergeSort carries out the partitioning and merging process, so the
34+
* time complexity of MergeSort is O(nlogn) for all cases.
35+
*
36+
* Space:
37+
* - O(n) since we require a temporary array to temporarily store the merged elements in sorted order
38+
*/
39+
340
public class MergeSort {
41+
42+
/**
43+
* Sorts the given array in non-decreasing order.
44+
*
45+
* @param arr The given array to be sorted.
46+
*/
47+
public static void sort(int[] arr) {
48+
int interval = 1;
49+
int n = arr.length;
50+
int[] temp = new int[n];
51+
52+
while (interval < n) {
53+
for (int i = 0; i < n - interval; i += 2 * interval) {
54+
int end = Math.min(i + 2 * interval - 1, n - 1);
55+
int mid = i + interval - 1;
56+
merge(arr, i, mid, end, temp);
57+
}
58+
interval *= 2;
59+
}
60+
}
61+
62+
/**
63+
* Merges two sorted sub-arrays within the given array. The two sub-arrays are arr[start, mid] and
64+
* arr[mid + 1, end]. Upon completion of this function, arr[start, end] will be in sorted order.
65+
*
66+
* @param arr The array containing the sub-arrays to be merged.
67+
* @param start The starting index of the first sub-array to be merged.
68+
* @param mid The ending index (inclusive) of the first sub-array to be merged. In the iterative implementation,
69+
* the mid parameter is required in the merge function to determine the splitting point between the
70+
* sub-arrays to be merged.
71+
* @param end The ending index (inclusive) of the second sub-array to be merged.
72+
* @param temp A temporary array used for merging intermediate results.
73+
*/
74+
private static void merge(int[] arr, int start, int mid, int end, int[] temp) {
75+
int i = start;
76+
int j = mid + 1;
77+
int pointer = start;
78+
79+
// Merge the two sorted sub-arrays into the temp array
80+
while (i <= mid && j <= end) {
81+
if (arr[i] <= arr[j]) {
82+
//we use <= here to maintain stability of MergeSort. If arr[i] == arr[j], the algorithm prefers the
83+
//one from the left sub-array (arr[i]). This decision preserves the relative order of equal elements.
84+
85+
//if we change this to arr[i] >= arr[j], we can sort the array in non-increasing order.
86+
87+
temp[pointer] = arr[i];
88+
i++;
89+
} else {
90+
temp[pointer] = arr[j];
91+
j++;
92+
}
93+
pointer++;
94+
}
95+
96+
// Copy any remaining elements from the left sub-array
97+
while (i <= mid) {
98+
temp[pointer] = arr[i];
99+
i++;
100+
pointer++;
101+
}
102+
103+
// Copy any remaining elements from the right sub-array
104+
while (j <= end) {
105+
temp[pointer] = arr[j];
106+
j++;
107+
pointer++;
108+
}
109+
110+
// Copy the merged elements back to the original array
111+
for (int k = start; k <= end; k++) {
112+
arr[k] = temp[k];
113+
}
114+
}
115+
4116
}

src/algorithms/sorting/mergeSort/recursive/MergeSort.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package src.algorithms.sorting.mergeSort.recursive;
22

33
/** Here, we are implementing MergeSort where we sort the array in increasing (or more precisely, non-decreasing)
4-
* order.
4+
* order recursively.
55
*
66
* Brief Description:
7-
* MergeSort is a divide-and-conquer sorting algorithm that sorts an array by recursively dividing it into two halves,
8-
* sorting each half separately, and then merging the sorted halves to produce the final sorted output.
7+
* MergeSort is a divide-and-conquer sorting algorithm. The recursive implementation takes a top-down approach by
8+
* recursively dividing the array into two halves, sorting each half separately, and then merging the sorted halves
9+
* to produce the final sorted output.
910
*
1011
* Implementation Invariant (for the merging subroutine):
1112
* The sub-array temp[start, (k-1)] consists of the (𝑘−start) smallest elements of arr[start, mid] and
@@ -31,7 +32,7 @@
3132
public class MergeSort {
3233

3334
/**
34-
* Sorts the sub-array arr[start, end] using the Merge Sort algorithm.
35+
* Sorts the sub-array arr[start, end] using the MergeSort algorithm.
3536
*
3637
* @param arr The given array to be sorted.
3738
* @param start The starting index of the sub-array to be sorted.
@@ -49,13 +50,12 @@ private static void mergeSort(int[] arr, int start, int end, int[] temp) {
4950
}
5051

5152
/**
52-
* Merges two sorted sub-arrays within the given array using the Merge Sort algorithm. The two sub-arrays are
53-
* arr[start, mid] and arr[mid + 1, end]. Upon completion of this function, arr[start, end] will be in sorted
54-
* order.
53+
* Merges two sorted sub-arrays within the given array. The two sub-arrays are arr[start, mid] and
54+
* arr[mid + 1, end]. Upon completion of this function, arr[start, end] will be in sorted order.
5555
*
5656
* @param arr The array containing the sub-arrays to be merged.
5757
* @param start The starting index of the first sub-array to be merged.
58-
* @param end The ending index of the second sub-array to be merged.
58+
* @param end The ending index (inclusive) of the second sub-array to be merged.
5959
* @param temp A temporary array used for merging intermediate results.
6060
*/
6161
private static void merge(int[] arr, int start, int end, int[] temp) {
@@ -104,7 +104,7 @@ private static void merge(int[] arr, int start, int end, int[] temp) {
104104
/**
105105
* Sorts the given array in non-decreasing order.
106106
*
107-
* @param arr array to be sorted
107+
* @param arr The given array to be sorted
108108
*/
109109
public static void sort(int[] arr) {
110110
int n = arr.length;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package test.algorithms.mergeSort.iterative;
2+
3+
import org.junit.Test;
4+
5+
import src.algorithms.sorting.mergeSort.iterative.MergeSort;
6+
7+
import java.util.Arrays;
8+
9+
import static org.junit.Assert.assertArrayEquals;
10+
11+
public class MergeSortTest {
12+
13+
@Test
14+
public void test_insertionSort_shouldReturnSortedArray() {
15+
int[] firstArray =
16+
new int[] {2, 3, 4, 1, 2, 5, 6, 7, 10, 15, 20, 13, 15, 1, 2, 15, 12, 20, 21, 120, 11, 5, 7, 85, 30};
17+
int[] firstResult = Arrays.copyOf(firstArray, firstArray.length);
18+
MergeSort.sort(firstResult);
19+
20+
int[] secondArray
21+
= new int[] {9, 1, 2, 8, 7, 3, 4, 6, 5, 5, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
22+
int[] secondResult = Arrays.copyOf(secondArray, secondArray.length);
23+
MergeSort.sort(secondResult);
24+
25+
int[] thirdArray = new int[] {};
26+
int[] thirdResult = Arrays.copyOf(thirdArray, thirdArray.length);
27+
MergeSort.sort(thirdResult);
28+
29+
int[] fourthArray = new int[] {1};
30+
int[] fourthResult = Arrays.copyOf(fourthArray, fourthArray.length);
31+
MergeSort.sort(fourthResult);
32+
33+
int[] fifthArray = new int[] {5,1,1,2,0,0};
34+
int[] fifthResult = Arrays.copyOf(fifthArray, fifthArray.length);
35+
MergeSort.sort(fifthResult);
36+
37+
Arrays.sort(firstArray); // get expected result
38+
Arrays.sort(secondArray); // get expected result
39+
Arrays.sort(thirdArray); // get expected result
40+
Arrays.sort(fourthArray); // get expected result
41+
Arrays.sort(fifthArray); // get expected result
42+
43+
assertArrayEquals(firstResult, firstArray);
44+
assertArrayEquals(secondResult, secondArray);
45+
assertArrayEquals(thirdResult, thirdArray);
46+
assertArrayEquals(fourthResult, fourthArray);
47+
assertArrayEquals(fifthResult, fifthArray);
48+
}
49+
}

0 commit comments

Comments
 (0)