// L-32 MCS 360 Fri 10 Apr 2020 : quicksortv2

/* Our second version of quicksort uses a partition function. */

#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 read_vector ( vector< pair<int,char> > &v, int n );
// reads a vector of n elements

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

void partition
 ( vector< pair<int,char> >& v, int lower, int upper, int& pivot );
// takes v[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 vanilla_quicksort 
 ( vector< pair<int,char> >& v, int k, int lb, int ub );
// applies quicksort to the vector v[lb]..v[ub], the parameter k
// keeps track of the levels of recursion, initialize with 0

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

   cout << "Random vector ? (y/n) ";
   char answer; cin >> answer;

   vector< pair<int,char> > v;
   srand(time(0));

   if( answer == 'y')
   {
      v = random_vector(n);
      cout << n << " random items : ";
   }
   else
   {
      read_vector(v,n);
      cout << "your vector of " << n << " items : ";
   }
   write_vector(v); cout << endl;

   vanilla_quicksort(v,0,0,n-1);

   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 read_vector ( vector< pair<int,char> > &v, int n )
{
   for(int i=0; i<n; i++)
   {
      cout << "-> give v[" << i << "] : ";
      int nbr; cin >> nbr;
  
      pair<int,char> p;
      p.first = nbr;
      p.second = 'a' + rand() % 26;
      v.push_back(p);
   }
}

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

void partition
 ( vector< pair<int,char> >& v, int lower, int upper, int& pivot )
{
   pair<int,char> x = v[pivot];

   int up = lower+1; // index will go up 
   int down = upper; // index will go down

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

      if(up == down) break;

      cout << "swapping " << up << " with " << down << endl;
      pair<int,char> tmp = v[up];
      v[up] = v[down]; v[down] = tmp;
   }
   cout << "up = " << up << "  down = " << down << endl;
   if(v[up].first > x.first) up--;
   cout << "moving pivot to " << up << endl;
   v[lower] = v[up]; v[up] = x;
   pivot = up;
}

void vanilla_quicksort 
 ( vector< pair<int,char> >& v, int k, int lb, int ub )
{
   for(int i=0; i<k; i++) cout << "  ";
   write_vector(v); cout << endl;
   
   if(ub - lb > 0)
   {
      int pivot = lb;

      cout << "calling partition ..." << endl;
      cout << "  k = " << k << "  lb = " << lb << "  ub = " << ub << endl;
      partition(v,lb,ub,pivot);
      cout << "  lb = " << lb << "  ub = " << ub
           << "  pivot = " << pivot << endl;

      // cout << "continue ? (y/n) "; char answer; cin >> answer;

      // if(answer == 'y')
      // {
         vanilla_quicksort(v,k+1,lb,pivot-1);
         vanilla_quicksort(v,k+1,pivot+1,ub);
      // }

   }
}
