/* file randomizedQuickSort.h */
          // code by bds, 2/00
#ifndef __RANDOMIZEDQUICKSORT__
#define __RANDOMIZEDQUICKSORT__

#include <iterator>

/* 
 randomizedSelect(b, e, k) returns the k-th largest element in the 
 range [p..e).  k must be in the range [0..e-b).

 For example, the median of the values is randomizedSelect(b, e, (e-b)/2) 
 and the second smallest is randomizedSelect(b, e, 1).

 We require that class Iterator has pointer arithmetic operations
 and that the unknown class pointed to by dereferencing iterators has 
 operator <= defined.
*/
template<class Iterator>  // use with any pointer type
typename std::iterator_traits<Iterator>::value_type  // the return type
randomizedSelect(Iterator b, Iterator e, int k) // the arg types
{
  // The items in locations [b, (b+1) .. e) will be permuted to the extent 
  // needed to find the k-th largest.
  if ((e-b) <= 1) 
    // then zero or one elements -- and that's already sorted.
    return b[0]; 
  else
  {
    Iterator q = randomizedPartition(p, e);
    q++;
    int m = q - b; // size of first segment.
    if (k < m)
	return randomizedSelect(p, q, k);
    else
	return randomizedSelect(q, e, k-m);
  }
}

template<class Iterator>
inline Iterator randomizedPartition(Iterator p, Iterator e)
// We assume that e > p.
{ Iterator i = p + rand() % (e - p);  // i is random in [p..e).
  std::swap(*i, *p);

  // regular partition
           i = p-1;
  Iterator j = e;
  typename std::iterator_traits<Iterator>::value_type x = *p;
  while ( true )
  { do j-- ; while ( !( *j <= x ) );
    do i++ ; while ( !( x <= *i ) );
    //do i++ ; while ( !( x <= *i ) );
    if ( i < j ) std::swap( *i, *j );
    else return j;
  }
}

#endif
