// L-32 MCS 360 Fri 5 Nov 2010 : quicksortv3

/* This third version of quicksort uses the partition function
   with the iterator and allows to time the execution. 

   For competitive timings, compile with the optimization flag "-O3"
*/

#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> >::const_iterator first,
   vector< pair<int,char> >::const_iterator last );
// writes from *first to *last, *last included

vector< pair<int,char> >::iterator partition
 ( vector< pair<int,char> >::iterator lower,
   vector< pair<int,char> >::iterator upper );
// takes *lower as pivot and interchanges elements so that
// v[i].first <= v[pivot].first for all i < pivot, and
// v[i].first > v[pivot].first for all i > pivot,
// where lower <= pivot <= upper

void quicksort 
 ( vector< pair<int,char> >::iterator lower,
   vector< pair<int,char> >::iterator upper, int k );
// applies quicksort to the vector of elements between lower and upper,
// upper is included; the parameter k
// keeps track of the levels of recursion, initialize with 0

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.begin(),v.end()-1); cout << endl;

   std::clock_t tstart,tstop;
   tstart = std::clock();
   quicksort(v.begin(),v.end()-1,0);
   tstop = std::clock();
   cout << "time elapsed : " 
        << (tstop - tstart)/double(CLOCKS_PER_SEC) 
        << " seconds" << endl;

   // cout << "the sorted vector : ";
   // write_vector(v.begin(),v.end()-1); 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 write_vector
 ( vector< pair<int,char> >::const_iterator first,
   vector< pair<int,char> >::const_iterator last )
{
   vector< pair<int,char> >::const_iterator i;

   for(i=first; i!=(last+1); i++)
      cout << "(" << i->first
           << "," << i->second
           << ")";
}

vector< pair<int,char> >::iterator partition
 ( vector< pair<int,char> >::iterator lower,
   vector< pair<int,char> >::iterator upper )
{
   vector< pair<int,char> >::iterator pivot;
   vector< pair<int,char> >::iterator up = lower+1;
   vector< pair<int,char> >::iterator down = upper;

   pair<int,char> x = *lower;

   while(up != down)
   {
      while((up != down) && (up->first <= x.first)) up++;
      while((up != down) && (down->first > x.first)) down--;

      if(up == down) break;

      pair<int,char> tmp = *up;
      *up = *down; *down = tmp;
   }
   if(up->first > x.first) up--;
   *lower = *up; *up = x;
   pivot = up;

   return pivot;
}

void quicksort 
 ( vector< pair<int,char> >::iterator lower,
   vector< pair<int,char> >::iterator upper, int k )
{
   // for(int i=0; i<k; i++) cout << "  ";
   // write_vector(lower,upper); cout << endl;
   
   if(lower != upper)
   {
      vector< pair<int,char> >::iterator pivot;
      pivot = partition(lower,upper);

      if(lower != pivot) quicksort(lower,pivot-1,k+1);
      if(upper != pivot) quicksort(pivot+1,upper,k+1);
   }
}

