// L-31 MCS 360 Wed 3 Nov 2010 : shell_sort

/* Shell sort uses a modification of the insertion_sort
   of Lecture 30. */

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;

vector< pair<int,char> > random_vector ( int n );
// returns a vector of n random 2-digit numbers
// associated with lower case letters

void write_vector ( vector< pair<int,char> > v );
// writes the vector v

void vanilla_shell_sort ( vector< pair<int,char> >& v );
// applies insertion sort to the vector v

void vanilla_insertion_sort 
 ( vector< pair<int,char> >& v, int start, int gap );
// applies insertion sort to the subvector v
// at subscripts start + k*gap, for k = 0, 1, ...

int main()
{
   cout << "give n : ";
   int n; cin >> n;

   srand(time(0));
   vector< pair<int,char> > v = random_vector(n);
   cout << n << " random items : ";
   write_vector(v); cout << endl;

   vanilla_shell_sort(v);

   cout << "the sorted vector : ";
   write_vector(v); cout << endl;

   return 0;
}

vector< pair<int,char> > random_vector ( int n )
{
   vector< pair<int,char> > v;

   for(int i=0; i<n; i++)
   {
      pair<int,char> p;
      p.first = 10 + (rand() % 90);
      p.second = 'a' + rand() % 26;
      v.push_back(p);
   }

   return v;
}

void write_vector ( vector< pair<int,char> > v )
{
   for(int i=0; i<v.size(); i++)
      cout << "(" << v[i].first
           << "," << v[i].second
           << ")";
}

void vanilla_insertion_sort 
 ( vector< pair<int,char> >& v, int start, int gap )
{
   for(int i=start+gap; i<v.size(); i=i+gap)
   {
      int j=i-gap;

      while((j >= start) && (v[i].first < v[j].first)) j=j-gap;

      j = j + gap;
      if(j < i)
      {
         pair<int,char> tmp = v[i];

         for(int k=i-gap; k>=j; k=k-gap) v[k+gap] = v[k];
         v[j] = tmp;

         cout << "after " << i << " <-> " << j << " : ";
         write_vector(v); cout << endl;
      }
   }
}

void vanilla_shell_sort ( vector< pair<int,char> >& v )
{
   int gap = v.size()/2;

   while(gap > 0)
   {
      for(int i=0; i<gap; i++)
      {
         cout << "insertion sort starts at " << i
              << " with gap " << gap << endl;
         vanilla_insertion_sort(v,i,gap);
      }
      if(gap == 2)
         gap = 1;
      else
         gap = int(gap/2.2);
   }
}

