|
|
|
|
|
|
|
|
|
|
|
|
We now write the merge( ) algorithm that merges 2 sorted array portions:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right portions int k = 0; // Current copy location in help array H The merge( ) method will be invoked repeatedly If we create a helper array inside merge( ) we would repeatedly allocate and de-allocate memory That is inefficient So we create the helper array in main( ) once and pass it to merge() as parameter H[ ] else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
We first define and initialize the indexes that points to the current elements in the sorted portions:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in help array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both arrays have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
We define and initialize the index k that points to the output location in the helper array H[ ]:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both arrays have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
We repeat as long as one of the array portion still has an unprocessed element:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both arrays have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
We must handle 3 cases:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { case 1: both (sorted) portions have unprocessed elements case 2: the left portion is exhausted case 3: the right portion is exhausted } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
Case 1: how to detect when both arrays have unprocessed elements:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H)
{
int i = s, j = m; // Current elements in left and right (sorted) portions
int k = 0; // Current copy location in helper array H
while ( i < m || j < e ) // Loop as long as there are unprocessed items
{
if ( i < m && j < e )
{ // Both portions have unprocessed elements
if ( A[i].compareTo(A[j]) <= 0 )
H[k++] = A[i++];
else
H[k++] = A[j++];
}
else if ( i == m ) // Left part is exhausted (empty)
H[k++] = A[j++];
else if ( j == e ) // Right part is exhausted (empty)
H[k++] = A[i++];
}
// Copy H[ ] back to A[ ]
for (i = s, k = 0; i < e; i++, k++)
A[i] = H[k];
}
|
Case 1: if A[i] <= A[j], we copy A[i] over to H[k] and increment i and k:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both portions have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k] = A[i]; i++; k++; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
Shorthand: if we increase a variable by 1 after we used the variable, we can use var++ for short:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both portions have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
Case 1 continued: if A[i] > A[j], we copy A[j] over to H[k] and increment j and k:
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both portions have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
Case 2: if the left portion of the array is exhausted, we copy A[j] over to H[k] (and increment j and k):
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both portions have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
Case 3: if the right portion of the array is exhausted, we copy A[i] over to H[k] (and increment i and k):
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both portions have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
Finally: copy the merged result in H[ ] (starting at index 0) back to A[ ] (starting at index s):
public static <T extends Comparable<T>> void merge(T[] A, int s, int m, int e, T[] H) { int i = s, j = m; // Current elements in left and right (sorted) portions int k = 0; // Current copy location in helper array H while ( i < m || j < e ) // Loop as long as there are unprocessed items { if ( i < m && j < e ) { // Both portions have unprocessed elements if ( A[i].compareTo(A[j]) <= 0 ) H[k++] = A[i++]; else H[k++] = A[j++]; } else if ( i == m ) // Left part is exhausted (empty) H[k++] = A[j++]; else if ( j == e ) // Right part is exhausted (empty) H[k++] = A[i++]; } // Copy H[ ] back to A[ ] for (i = s, k = 0; i < e; i++, k++) A[i] = H[k]; } |
public static void main(String[] args) { Integer[] list = {2, 9, 4, 6, 7, 3, 5, 8, 10, 1}; // <-----> <-----> // sorted sorted Integer[] help = new Integer[list.length]; // Helper array printArray(list); MergeSort.merge(list, 2, 5, 8, help); printArray(list); } public static |
DEMO: 14-sort/10-merge-sort/Demo.java
An array of
1 element is
sorted !!
By merging
2 arrays of
1 elements, we get
a sorted portion
of size = 2
Here is how to
sort an
array of
2 elements:
public static void main(String[] args) { Integer[] list = {7, 3}; Integer[] help = new Integer[list.length]; // Helper array printArray(list); // Merge arrays of 1 elements MergeSort.merge(list, 0, 1, 2, help); printArray(list); } |
DEMO: 14-sort/10-merge-sort/Demo2.java
An array of
1 element is
sorted !!
By merging
2 arrays of
1 elements, we get
a sorted portion
of size = 2
By merging
2 (sorted) arrays of
2 elements, we get
a sorted portion
of size = 4
Here is how to
sort an
array of
4 elements:
public static void main(String[] args) { Integer[] list = {7, 3, 8, 5}; Integer[] help = new Integer[list.length]; // Helper array printArray(list); // Merge arrays of 1 elements MergeSort.merge(list, 0, 1, 2, help); MergeSort.merge(list, 2, 3, 4, help); // Merge arrays of 2 elements MergeSort.merge(list, 0, 2, 4, help); printArray(list); } |
DEMO: 14-sort/10-merge-sort/Demo3.java (and so on - see Demo4.java)