Skip to content

Commit be4b255

Browse files
authored
Merge pull request #22 from kaitinghh/branch-mergeSort
Added merge sort
2 parents dfa4654 + ea2fac1 commit be4b255

File tree

16 files changed

+487
-146
lines changed

16 files changed

+487
-146
lines changed

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ This repository contains implementation of some of the fundamental data structur
3131
* [Generalized case](src/algorithms/sorting/cyclicSort/generalised) of O(n^2) time complexity
3232
- [Knuth-Morris-Pratt](src/algorithms/patternFinding/) aka KMP algorithm
3333
- [Matrix Operations](others/matrix_operations/)
34+
- [Bubble Sort](src/algorithms/sorting/bubbleSort)
35+
- [Insertion Sort](src/algorithms/sorting/insertionSort)
36+
- [Selection Sort](src/algorithms/sorting/selectionSort)
3437
- Merge Sort
35-
* Recursive
36-
* Bottom-up iterative
38+
* [Recursive](src/algorithms/sorting/mergeSort/recursive)
39+
* [Bottom-up iterative](src/algorithms/sorting/mergeSort/iterative)
3740
- Quick Sort
3841
* 3-way Partitioning
3942
- Radix Sort
@@ -47,10 +50,10 @@ This repository contains implementation of some of the fundamental data structur
4750
2. Binary Search
4851
* Peak Finding
4952
3. Sorting
50-
* Bubble
51-
* Insertion
52-
* Selection
53-
* Merge
53+
* [Bubble](src/algorithms/sorting/bubbleSort)
54+
* [Insertion](src/algorithms/sorting/insertionSort)
55+
* [Selection](src/algorithms/sorting/selectionSort)
56+
* [Merge](src/algorithms/sorting/mergeSort)
5457
* Quick
5558
4. Trees
5659
* Binary search tree

assets/MergeSortIterative.jpg

39.2 KB
Loading

assets/MergeSortRecursive.png

77.8 KB
Loading
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
![InsertionSort](../../../../assets/InsertionSort.png)
2+
3+
Image taken from: https://www.hackerrank.com/challenges/correctness-invariant/problem
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
![InsertionSort](../../../../assets/InsertionSort.png)
22

3-
Image taken from: https://www.hackerrank.com/challenges/correctness-invariant/problem
3+
Image Source: https://www.hackerrank.com/challenges/correctness-invariant/problem
Lines changed: 102 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,116 @@
11
package src.algorithms.sorting.mergeSort.iterative;
22

3-
import java.util.*;
4-
5-
/**
6-
* Iterative implementation of Merge sort with O(n) space
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
738
*/
39+
840
public class MergeSort {
941

10-
/**
11-
* Sorts a list from a specified start to end point.
12-
*
13-
* Note: starting with an interval size (call this var <interval>) of 1 and iteratively *2,
14-
* Merge two sub-lists of size <interval> together using merge routine.
15-
* Invariant: Partitioning the main list into sub-lists of size <interval>,
16-
* each of this sub-list is sorted within itself (the last sub-list may not be of
17-
* size <interval> but it is still sorted since the size is necessarily less than <interval>.
18-
*
19-
* @param <T> generic type of object
20-
* @param lst list of objects to be sorted
21-
* @param start sorting starts at this index
22-
* @param end sorting ends (inclusive) at this index
23-
*/
24-
private static <T extends Comparable<T>> void mergeSort(List<T> lst, int start, int end) {
25-
if (start == end) {
26-
return;
27-
}
28-
int size = lst.size();
29-
int interval = 1;
30-
List<T> tmp = new ArrayList<>();
31-
for (T item : lst) {
32-
tmp.add(item);
33-
}
34-
while (interval < lst.size()) {
35-
for (int i = 0; i + interval < size; i += 2*interval) {
36-
int start1 = i;
37-
int start2 = i + interval;
38-
int e = i + 2 * interval - 1;
39-
if (e > size - 1) {
40-
e = size - 1;
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;
4159
}
42-
merge(lst, tmp, start1, start2, e);
43-
}
44-
interval *= 2;
4560
}
46-
47-
}
4861

49-
/**
50-
* Merging algorithm that merges two sorted sub-lists into one final sorted list.
51-
* @param <T> generic type of object
52-
* @param lst at the end, elements from s1 to e (inclusive) of lst are sorted
53-
* @param s1 start index of first sub-list
54-
* @param s2 start index of second sub-list; note that end index of first sub-list is s2-1
55-
* @param e end index of second sub-list
56-
*/
57-
private static <T extends Comparable<T>> void merge(List<T> lst, List<T> tmp, int s1, int s2, int e) {
58-
int startLeft = s1;
59-
int startRight = s2;
60-
int tmpIdx = s1;
61-
while (startLeft < s2 && startRight < e + 1) {
62-
if (lst.get(startLeft).compareTo(lst.get(startRight)) < 0) {
63-
tmp.set(tmpIdx, lst.get(startLeft++));
64-
} else {
65-
tmp.set(tmpIdx, lst.get(startRight++));
66-
}
67-
tmpIdx++;
68-
}
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;
6978

70-
while (startLeft < s2) {
71-
tmp.set(tmpIdx++, lst.get(startLeft++));
72-
}
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.
7384

74-
while (startRight < e + 1) {
75-
tmp.set(tmpIdx++, lst.get(startRight++));
76-
}
85+
//if we change this to arr[i] >= arr[j], we can sort the array in non-increasing order.
7786

78-
for (int i = s1; i < e+1; i++) {
79-
lst.set(i, tmp.get(i));
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+
}
80114
}
81-
}
82115

83-
/**
84-
* Sorting algorithm that clients calls
85-
* @param <T> generic type
86-
* @param lst list to be sorted
87-
*/
88-
public static <T extends Comparable<T>> void sort(List<T> lst) {
89-
mergeSort(lst, 0, lst.size() - 1);
90-
}
91116
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
![MergeSort Iterative](../../../../../assets/MergeSortIterative.jpg)
2+
3+
Image Source: https://www.chelponline.com/iterative-merge-sort-12243
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package src.algorithms.sorting.mergeSort.legacy.iterative;
2+
3+
import java.util.*;
4+
5+
/**
6+
* Iterative implementation of Merge sort with O(n) space
7+
*/
8+
public class MergeSort {
9+
10+
/**
11+
* Sorts a list from a specified start to end point.
12+
*
13+
* Note: starting with an interval size (call this var <interval>) of 1 and iteratively *2,
14+
* Merge two sub-lists of size <interval> together using merge routine.
15+
* Invariant: Partitioning the main list into sub-lists of size <interval>,
16+
* each of this sub-list is sorted within itself (the last sub-list may not be of
17+
* size <interval> but it is still sorted since the size is necessarily less than <interval>.
18+
*
19+
* @param <T> generic type of object
20+
* @param lst list of objects to be sorted
21+
* @param start sorting starts at this index
22+
* @param end sorting ends (inclusive) at this index
23+
*/
24+
private static <T extends Comparable<T>> void mergeSort(List<T> lst, int start, int end) {
25+
if (start == end) {
26+
return;
27+
}
28+
int size = lst.size();
29+
int interval = 1;
30+
List<T> tmp = new ArrayList<>();
31+
for (T item : lst) {
32+
tmp.add(item);
33+
}
34+
while (interval < lst.size()) {
35+
for (int i = 0; i + interval < size; i += 2*interval) {
36+
int start1 = i;
37+
int start2 = i + interval;
38+
int e = i + 2 * interval - 1;
39+
if (e > size - 1) {
40+
e = size - 1;
41+
}
42+
merge(lst, tmp, start1, start2, e);
43+
}
44+
interval *= 2;
45+
}
46+
47+
}
48+
49+
/**
50+
* Merging algorithm that merges two sorted sub-lists into one final sorted list.
51+
* @param <T> generic type of object
52+
* @param lst at the end, elements from s1 to e (inclusive) of lst are sorted
53+
* @param s1 start index of first sub-list
54+
* @param s2 start index of second sub-list; note that end index of first sub-list is s2-1
55+
* @param e end index of second sub-list
56+
*/
57+
private static <T extends Comparable<T>> void merge(List<T> lst, List<T> tmp, int s1, int s2, int e) {
58+
int startLeft = s1;
59+
int startRight = s2;
60+
int tmpIdx = s1;
61+
while (startLeft < s2 && startRight < e + 1) {
62+
if (lst.get(startLeft).compareTo(lst.get(startRight)) < 0) {
63+
tmp.set(tmpIdx, lst.get(startLeft++));
64+
} else {
65+
tmp.set(tmpIdx, lst.get(startRight++));
66+
}
67+
tmpIdx++;
68+
}
69+
70+
while (startLeft < s2) {
71+
tmp.set(tmpIdx++, lst.get(startLeft++));
72+
}
73+
74+
while (startRight < e + 1) {
75+
tmp.set(tmpIdx++, lst.get(startRight++));
76+
}
77+
78+
for (int i = s1; i < e+1; i++) {
79+
lst.set(i, tmp.get(i));
80+
}
81+
}
82+
83+
/**
84+
* Sorting algorithm that clients calls
85+
* @param <T> generic type
86+
* @param lst list to be sorted
87+
*/
88+
public static <T extends Comparable<T>> void sort(List<T> lst) {
89+
mergeSort(lst, 0, lst.size() - 1);
90+
}
91+
}

0 commit comments

Comments
 (0)