|
|
|
|
|
|
|
|
|
|
|
|
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)