// search example. linear and binary search
// bds 10/98
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include "tracing.h"

void initialize( float[], int );

template< class T >
int binarySearch( T b[], T searchKey, int low, int high );

template< class T >
int linearSearch( T b[], int bSize, T searchKey) ;

int search( float b[], int bSize, float searchKey, int& index) {

  //index = linearSearch( b, bSize, searchKey);
  index = binarySearch( b, searchKey, 0, bSize-1);
  return index != bSize && b[index] == searchKey; 

}

int tracing = 0; // false

int main(int argc, char* argv[]) {
   float dataSet[ 1000000 ];
   int size, index;
   float key;
   int success; // boolean
   if ( argc != 3 ) {
     cout << "usage: " << argv[0] << " dataSetSize numberOfSearches" << endl;
     cout << "If dataSetSize is negative, -dataSetSize used and tracing done."
          << endl;
     return 0;
   }

   size = atoi( argv[1] );
   if ( size < 0 ) { tracing = 1; size = -size; }
   initialize( dataSet, size );

   for (int i = atoi( argv[2] ); i > 0; i--) {
     key = (float) ((rand() * rand())%(2*size));
     success = search( dataSet, size, key, index );
     if (success)
       cout << key << " found at location " << index << endl;
     else
       cout << key << " not found at any location" << endl;
   }
}

void initialize( float A[], int s ) {
  for (int i = 0; i < s; i++)
    A[i] = 2*i;
}

/*
void initialize( float A[], int s ) {
  for (int i = 0; i < s; i++)
    A[i] = (float) rand();
}
*/

//// Generic search algorithms

template <class T>
int linearSearch( T b[], int bSize, T searchKey) {
  int location = bSize;
  // implements a linear search process
  for (int i = 0; i < bSize; i++) {
    if (tracing) enter ("linearSearchLoop", i);
    if ( b[i] == searchKey ) {
      location = i;
    }
    if (tracing) exit (NULL, i, location);
  }
  return location; 
}

template< class T >
int binarySearch( T b[], T searchKey, int low, int high ) {
// assume: b is sorted in increasing order.
// assert: if searchKey in range b[low] thru b[high] then the 
// index of an occurence of searchKey is returned.
  int ans;
  if (tracing) enter( "binarySearch", low, high );

  if (low == high) ans = low;
  else {
    // assert: low < high
    int middle = (low + high)/2;
    // assert: low <= middle < high
    // thus assert: low:middle and middle+1:high are both strictly smaller 
    // ranges than low:high.
    if ( b[middle] >= searchKey )
      // assert: if searchKey is in b[low:high] then it is in b[low:middle]
      ans = binarySearch( b, searchKey, low, middle );
    else
      // assert: if searchKey is in b[low:high] then it is in b[middle+1:high]
      ans = binarySearch( b, searchKey, middle + 1, high);
  }
  // assert: if searchKey is in b[low:high] then it is in b[ans]

  if (tracing) exit( NULL, low, high, ans );
  return ans;
}
  
