next up previous contents
Next: Quicksort: Introduction Up: Sorting Previous: Bubble Sort: Introduction   Contents

Mergesort: Introduction [143]

Divide and Conquer: repeatedly cut problem into ``equal'' halves.

Make two recursive calls using left, center, right:



\framebox[18cm][c]{unsorted list}

\framebox[8.85cm][c]{unsorted list} \framebox[8.85cm][c]{unsorted list}

\framebox[4.28cm][c]{unsorted} \framebox[4.28cm][c]{unsorted} \framebox[4.28cm][c]{unsorted} \framebox[4.28cm][c]{unsorted}

\framebox[2.0cm][c]{uns} \framebox[2.0cm][c]{uns} \framebox[2.0cm][c]{uns} \framebox[2.0cm][c]{uns} \framebox[2.0cm][c]{uns} \framebox[2.0cm][c]{uns} \framebox[2.0cm][c]{uns} \framebox[2.0cm][c]{uns}

\framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u} \framebox[0.85cm][c]{u}



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
$\uparrow$      
2 15 27 38
$\uparrow$      
               
$\uparrow$              



Move the smallest element into the temporary array:



1 13 24 26
  $\uparrow$    
2 15 27 38
$\uparrow$      
1              
  $\uparrow$            



1 13 24 26
  $\uparrow$    
2 15 27 38
  $\uparrow$    
1 2            
    $\uparrow$          



1 13 24 26
    $\uparrow$  
2 15 27 38
  $\uparrow$    
1 2 13          
      $\uparrow$        



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:



${\displaystyle \frac{T(n)}{n} = \frac{T(n/2)}{n/2} + 1}$



Telescope:



${\displaystyle \frac{T(n/2)}{n/2} = \frac{T(n/4)}{n/4} + 1}$



${\displaystyle \frac{T(n/4)}{n/4} = \frac{T(n/8)}{n/8} + 1}$



...





${\displaystyle \frac{T(2)}{2} = \frac{T(1)}{1} + 1}$



There are log n equations above.



${\displaystyle \frac{T(n)}{n} = \frac{T(1)}{1} + \log n}$



T(n) = nlog n + n = O( )


next up previous contents
Next: Quicksort: Introduction Up: Sorting Previous: Bubble Sort: Introduction   Contents
Ted Billard 2001-10-25