Divide and Conquer: repeatedly cut problem into ``equal'' halves.
Make two recursive calls using left, center, right:
Single element lists are, by default, sorted.
``Depth'' of this recursion: log n
After return from both recursive calls, merge lists into a sorted list.
Cost of merge: O(n)
Mergesort: O( )
Mergesort: Example [144]
Given two sorted lists. Use a temporary output array:
| 1 | 13 | 24 | 26 |
| 2 | 15 | 27 | 38 |
Move the smallest element into the temporary array:
| 1 | 13 | 24 | 26 |
| 2 | 15 | 27 | 38 |
| 1 | |||||||
| 1 | 13 | 24 | 26 |
| 2 | 15 | 27 | 38 |
| 1 | 2 | ||||||
| 1 | 13 | 24 | 26 |
| 2 | 15 | 27 | 38 |
| 1 | 2 | 13 | |||||
Mergesort needs an ``extra'' array.
Is it stable?
Mergesort: mergesrt [145]
% gcc -o mergesrt mergesrt.c > tcc mergesrt.c
Data File with Test Case: merge.dat: 8 24 13 1 26 2 27 15 38
% mergesrt merge.dat 8 48 16 [ 1 2 13 15 24 26 27 38 ] 0 0 % mergesrt merge.dat step n move comp 1 2 3 4 5 6 7 8 i j 8 0 0 [ 24 13 1 26 2 27 15 38 ] 0 0 8 4 1 [ 13 24 1 26 2 27 15 38 ] 1 2 8 8 2 [ 13 24 1 26 2 27 15 38 ] 3 4 8 16 5 [ 1 13 24 26 2 27 15 38 ] 1 4 8 20 6 [ 1 13 24 26 2 27 15 38 ] 5 6 8 24 7 [ 1 13 24 26 2 27 15 38 ] 7 8 8 32 10 [ 1 13 24 26 2 15 27 38 ] 5 8 8 48 16 [ 1 2 13 15 24 26 27 38 ] 1 8
Mergesort: mergesrt.c [146]
void m_sort( input_type a[], input_type tmp_array[], int left, right )
{
/* input_type tmp_array[N]; why don't we want this? */
int center;
if (left < right) {
center = (left + right) / 2;
m_sort( a, tmp_array, left, center );
m_sort( a, tmp_array, center+1, right );
merge( a, tmp_array, left, center+1, right );
}
}
void merge_sort(input_type a[], int n) {
input_type tmp_array[MAX];
m_sort(a, tmp_array, 1, n);
}
void merge( input_type a[], /* contains all lists, including list 1 and 2 */
input_type tmp_array[], /* uses the same locations as a */
int l_pos, /* start of left half - list 1 */
int r_pos, /* start of right half - list 2 */
int right_end /* end of list 2 */ ) {
int i, left_end, num_elements, tmp_pos;
left_end = r_pos - 1;
tmp_pos = l_pos;
num_elements = right_end - l_pos + 1;
while ( (l_pos <= left_end) && (r_pos <= right_end) )
if (a[l_pos] <= a[r_pos] )
tmp_array[tmp_pos++] = a[l_pos++];
else
tmp_array[tmp_pos++] = a[r_pos++];
while (l_pos <= left_end) tmp_array[tmp_pos++] = a[l_pos++];
while (r_pos <= right_end) tmp_array[tmp_pos++] = a[r_pos++];
for (i=1; i<=num_elements; i++, right_end-- )
a[right_end] = tmp_array[right_end];
}
Mergesort: Analysis [147]
Mergesort goes thru the same steps - independent of the data.
Best-case = Worst-case = Average-case.
T(n)= running time on a list on n elements.
T(1) = 1
T(n)= 2 times running time on a list of n/2 elements + linear merge
T(n)= 2T(n/2)+ n
Brute force method:
T(n)=2T(n/2)+n=2[2T(n/4)+n/2]+n=4T(n/4)+2n
T(n)=4[2T(n/8)+n/4]+2n=8T(n/8)+3n
T(n)= 2**kT(n/2**k)+k*n
and there are k=log n equations to get to T(1):
T(n) = nT(1)+nlog n = nlog n + n = O( )
Mergesort: Analysis (Telescope) [148]
Divide by n:
Telescope:
...
There are log n equations above.
T(n) = nlog n + n = O( )