//  File: itmergesort.c
//  Non-recursive 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 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] ;
   }
}


// Non-recursive Merge Sort
//   Idea: merge adjacent entries of the array to form sorted groups
//   of 2 entries.  Then merge the adjacent groups to form sorted groups
//   of 4 entries, then 8 entries, ... until the entire array is sorted.

void MergeSort(Array& A) {

   int n, low, high, length, low1, high1, low2, high2 ;

   n = A.length() ;
   low = 0 ;
   high = n-1 ;
   Array temp(n) ;

   length = 1 ; // group length

   while(length < n) {
      low1  = low ;
      high1 = low1 + length - 1 ;
      low2  = low1 + length ;
      high2 = low2 + length - 1 ;

      while (high2 <= high) {
         merge(A, low1, high1, low2, high2, temp) ;

         low1  = low1 + 2*length ;
         high1 = low1 + length - 1 ;
         low2  = low1 + length ;
         high2 = low2 + length - 1 ;
      }

      // Merge last group with remaining entries if they exist
	  //
      if (high1 < high) {
         merge(A, low1, high1, low2, high, temp) ;
      }

      length = 2*length ;     
   }
}

