//  File: mergesort.C
//  Merge Sort Routines

#include <assert.h>
#include <iostream.h>
#include <iomanip.h>
#include "array.h"
#include "sorts.h"


// Local function prototypes
//

static void merge(Array&, int, int, int, int, Array&) ;
static void RecMergeSort(Array&, int, int) ;


static void merge(
   Array &A, int low1, int high1, 
   int low2, int high2, Array &temp
) {

   int t=0, i1=low1, i2=low2 ;

   // Sanity check
   assert(low2 == high1 + 1) ;
  
   // while there are elements in both halves, copy the lowest one
   //
   while (i1 <= high1 && i2 <= high2) {
      if (A[i1] < A[i2]) {
         temp[t++] = A[i1++] ;
      } else {
         temp[t++] = A[i2++] ;
      }
   }

   // copy any remaining elements, if any
   //
   while (i1 <= high1) {
	  temp[t++] = A[i1++] ; 
   }
   while (i2 <= high2) {
      temp[t++] = A[i2++] ;
   }

   // copy the now-sorted elements back into the original array 
   //
   for (t = low1; t <= high2; t++) {
      A[t] = temp[t - low1] ;
   }
}


static void RecMergeSort(Array &A, int low, int high, Array& temp) {

#ifndef NDEBUG
   cout << "MergeSort: low = " << low << ", high = " << high << endl ;
#endif

  if (low >= high) return ;
  
   int mid = (low + high)/2 ;
   RecMergeSort(A, low, mid, temp) ;
   RecMergeSort(A, mid + 1, high, temp) ;
   
   merge(A, low, mid, mid + 1, high, temp) ;
}


void MergeSort(Array& A) {

   Array temp(A.length()) ;

   RecMergeSort(A, 0, A.length()-1, temp) ;
}
