/************************************************************
  FILE: crt.cc
  K.Becker
  June 9 1999

  Update: Nov. 10 1999
          clean-up and add DC & CC

  Program to show various collision resolution techniques
  in action.

  WARNING: input error checking is minimal

  Expected arguments:
  1: table size: -t <n>

  2: collision resolution technique (c.r.t.) to use
        -lp  = linear probing (default)
        -dh1 = double hashing (type 1: hash twice)
        -dh2 = double hashing (type 2: vary increment)
        -co  = chained overflow (2-pass)
	-sc  = simple chaining (probes next, step=1)
        -ch  = coalesced hashing (probes bottom-up)
        -dc  = direct chaining (dynamic)
        -cc  = computed chaining (dynamic)
        -bm  = brent's method (dynamic)
        -bti = binary tree insertion (dynamic)

  3: (optional) debug flag: -d 1 | 2 | 3
        [0] no trace (default)
	[1] minimal - trace collisions only
	[2] trace all keys
	[3] show table after each insertion

  4: file containing keys to be loaded

-----------------------------------------------------------
      TABLE OF CONTENTS..

******* Admin Stuff ****************************
void help( )                 : displays simple man page
int pl ( int ln )            : convert link value to print 
                                 (so null link looks reasonable)
void displaytable( int Table[] )
                             :  Draw the Hash Table
void displaytablelinks( int Table[], int Links[] )
                             : Draw the Hash Table (with associated links)
int crtcode( char* crttype ) : convert (text) code for crt to number 
                                  [see constants for mapping]
void getargs (int argc, char* argv[], 
	      char*& fname, int& size, int& debug, int& crt )
                             : Get the Command Line Arguments
                             : should be crt -t <n> -crt -d <n> fname

******* Hashing Stuff ****************************
int hash( int key )          : the first hash function
int hash2( int key )         : the secondary hash function
int step( int key )          : calculates the step value 
                                     (incrementing function)
int next ( int loc, int stepsize ) 
                             : calculate the next location in the table
                                      with wrap-around
int prev ( int loc, int stepsize )
                             : calculate the next location in the table
                                     going backwards (with wrap-around)

******* Placement Algorithms ****************************
void placelp( int key )      : Linear Probing
void placedh1( int key )     : Double Hashing Type 1: hash twice
void placedh2( int key )     : Double Hashing Type 2: vary increment

--- Chained Overflow ---
void copass2 ()              : 2nd pass for Chained Overflow
void placeco( int key )      : 1st pass for Chained Overflow

void placesc( int key )      : Simple Chaining
void placech( int key )      : Coalesced Hashing
void placedc( int key )      : Direct Chaining
void placecc( int key )      : Computed Chaining
void placebm( int key )      : Brent's Method

--- for Binary Tree Insertion ----
void initnode ( node* N, int sival, int isrc, node* p1 )
                             : initialize a new node
int which ( node* np, int val )
                             : returns given value from specified node
void printline( node* np, int sp1, int sp2, char* label, int valcode)
                             : display a line of output (part of tree)
void drawtree ( node* P, int levels )
                             : draw the decision tree
void deltree ( node* P )     : release the tree when finished
void placebti( int key )     : Binary Tree Insertion

**********************************************************/

#include <stdio.h>
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <fstream.h>
#include <string.h>

//--- GENERAL CONSTANTS-----------------------------------
const int EMPTY     = INT_MAX;
const int YES       = 1;
const int NO        = 0;

//--- COLLISION RESOLUTION TECHNIQUES---------------------
const int LP = 0;            // Linear Probing
const int DH1 = 1;           // Double Hashing Type 1
const int DH2 = 2;           // Double Hashing Type 2
const int CO = 3;            // Chained Overflow
const int SC = 9;            // Simple Chaining
const int CH = 4;            // Coalesced Hashing
const int DC = 5;            // Direct Chaining
const int CC = 6;            // Computed Chaining
const int BM = 7;            // Brent's Method
const int BTI = 8;           // Binary Tree Insertion

//--- GLOBALLY USED VARIABLES----------------------------

// 'generic' placement function:
void (*place) (int key);

int AddrSpace = 29;          // useable addresses (default value)

int* Table;                  // the hash table itself
int* Links;                  // for links if required
int* Overflow;               // for 2nd pass of Chained Overflow

int Nkeys = 0;               // count of keys actually placed
                             // to allow us to detect full table
int Ovfcount = 0;            // count of overflow records

int key;                     // key to be placed (incoming key)
int sval;                    // step value for incoming key

int debug = 0;               // debug flag (command line)
int crt   = LP;              // collision resolution technique to be used

int haslinks = NO;           // set if c.r.t. uses links

char* fname;                 // name of file with keys to place
fstream keyfile;             // file with keys to place

char* outname;               // name of file with table of keys (and links)
fstream outfile;             // file with hash table

// structure for tree in Binary Tree Insertion
typedef struct node
{
  int K;       // the value of the resident key
  int loc;     // location of this key in Table
  int S;       // step size (i-value) for this key
  int Si;      // step size for incoming key (parent)
  int rchild;  // is this a right child?

  node* parent;   // pointer to parent
  node* sibling;  // pointer to right sibling (same depth)
  node* left;     // pointer to left subtree
  node* right;    // pointer to right subtree
};

/*********************************************************/
/***** admin stuff  **************************************/
/*********************************************************/

void help( )
{
  cout << "Program to test various collision resolution techniques" << endl;
  cout << "  used when loading a hash table" << endl << endl;
  cout << "Usage: crt [-t <n>] [-<crt>] [-d <n>] fname" << endl;
  cout << "       WARNING: input error checking is minimal" << endl;
  cout << endl;
  cout << "  Expected arguments:" << endl;
  cout << "  1: table size: " << endl;
  cout << "     -t <n>" << endl;
  cout << endl;
  cout << "  2: collision resolution technique (c.r.t.) to use" << endl;
  cout << "        -lp  = linear probing (default)" << endl;
  cout << "	-dh1 = double hashing - type 1: hash twice" << endl;
  cout << "	-dh2 = double hashing - type 2: vary increment" << endl;
  cout << "	-co  = chained overflow (2-pass)" << endl;
  cout << "        -sc  = simple chaining (probes next, step=1)" << endl;
  cout << "	-ch  = coalesced hashing (probes bottom-up)" << endl;
  cout << "	-dc  = direct chaining (dynamic)" << endl;
  cout << "	-cc  = computed chaining (dynamic)" << endl;
  cout << "	-bm  = brent's method" << endl;
  cout << "	-bti = binary tree insertion" << endl;
  cout << endl;
  cout << "  3: (optional) debug flag: -d 1 | 2 | 3" << endl;
  cout << "        [0] no trace (default)" << endl;
  cout << "	[1] minimal - trace collisions only" << endl;
  cout << "	[2] trace all keys" << endl;
  cout << "	[3] show table after each insertion" << endl;
  cout << endl;
  cout << "  4: file containing keys to be loaded" << endl;
  cout << endl;

} // help

//-------------------------------------------------------//
int pl ( int ln )
{
  // convert link value to print (so null link looks reasonable)
  if (ln == EMPTY)
    return -1;
  else
    return ln;

} // pl

//-------------------------------------------------------//
void displaytable( int Table[] )
  //
  // Draw the Hash Table
{
  int i;
  
  for (i = 0; i < AddrSpace; i++)
    if (Table[i] == EMPTY)
      cout << setw(3) << i << ": ---"
	   << endl;
    else
      cout << setw(3) << i << ": "
	   << setw(3) << Table [i]
	   << endl;

  cout << endl;
  return;
} // displaytable

//-------------------------------------------------------//
void displaytablelinks( int Table[], int Links[] )
  //
  // Draw the Hash Table (with associated links)
{
  int i;
  
  for (i = 0; i < AddrSpace; i++)
    if (Table[i] == EMPTY)
      cout << setw(3) << i << ": ---"
	   << "  " << setw(3) << pl(Links [i])
	   << endl;
  else
    cout << setw(3) << i << ": "
	 << setw(3) << Table [i]
	 << "  " << setw(3) << pl(Links [i])
	 << endl;

  cout << endl;
  return;
} // displaytablelinks

//-------------------------------------------------------//
int crtcode( char* crttype )
{
  // convert (text) code for collision resolution technique
  // to number [see constants for mapping]

  if ( strcmp( crttype, "-lp" ) == 0 )
    {
      cout << "Using Linear Probing..." << endl;
      return LP;
    }
  else if ( strcmp( crttype, "-dh1" ) == 0 )
    {
      cout << "Using Double Hashing Type 1 (hash twice)..." << endl;
      return DH1;
    }
  else if ( strcmp( crttype, "-dh2" ) == 0 )
    {
      cout << "Using Double Hashing Type 2 (vary increment)..." << endl;
      return DH2;
    }
  else if ( strcmp( crttype, "-co" ) == 0 )
    {
      cout << "Using Chained Overflow..." << endl;
      return CO;
    }
  else if ( strcmp( crttype, "-sc" ) == 0 )
    {
      cout << "Using Simple Chaining..." << endl;
      return SC;
    }
  else if ( strcmp( crttype, "-ch" ) == 0 )
    {
      cout << "Using Coalesced Hashing (probes bottom up).." << endl;
      return CH;
    }
  else if ( strcmp( crttype, "-dc" ) == 0 )
    {
      cout << "Using Direct Chaining" << endl;
      return DC;
    }

  else if ( strcmp( crttype, "-cc" ) == 0 )
    {
      cout << "Using Computed Chaining..." << endl;
      return CC;
    }
  else if ( strcmp( crttype, "-bm" ) == 0 )
    {
      cout << "Using Brent's Method..." << endl;
      return BM;
    }
  else if ( strcmp( crttype, "-bti" ) == 0 )
    {
      cout << "Using Binary Tree Insertion..." << endl;
      return BTI;
    }
  else
    {
      cout << "Using Default..." << endl;
      return LP;
    }

} // crtcode

//-------------------------------------------------------//
void getargs (int argc, char* argv[], 
	      char*& fname1,          // input file name
	      char*& fname2,          // output file name
	      int& size,              // table size
	      int& debug,             // debug code
	      int& crt )              
  //
  // Get the Command Line Arguments
  //
  // should be crt -t <n> -crt -d <n> fname
{
  if (argc > 1) // table size is first
    size = atoi( argv[2]);

  if (argc > 3) // c.r.t. MUST be next
    crt = crtcode(argv[3]);

  if ((argc > 4) && (strcmp(argv[4],"-d") == 0)) // -d optional
    // debug code arg4= "-d"; arg5= debug setting
    // convert char digit to number
    debug = atoi( argv[5] );

  fname1 = argv[argc-1]; // last = filename
  strcpy ( fname2, fname1 );  // make a copy of infile name
  if (argc > 3) 
    strcat (fname2, argv[3]); // append crt to filename for output
  else 
    strcat (fname2, "-out");

  return;
} // getargs

/*********************************************************/
/***** Hashing Routines **********************************/
/*********************************************************/

int hash( int key )
  //
  // the first hash function
{ 
  int h;
  h = key % AddrSpace; // simple algorithm
  
  /*****/
  if (debug > 1)
    cout << "Key " << key
	 << " hashes to " << h
	 << endl;
  /*****/
  return h;
} // hash

//-------------------------------------------------------//

int hash2( int key )
  //
  // the secondary hash function
{ 
  int h;
  h = key*key % AddrSpace; // simple algorithm
  
  /*****/
  if (debug > 1)
    cout << "Key " << key
	 << " now hashes to " << h
	 << endl;
  /*****/
  return h;
} // hash2

//-------------------------------------------------------//

int step( int key )
  //
  // calculates the step value (incrementing function)
{ 
  int s;

  if (key == EMPTY)
    s = 0;
  else
    {
      s = (int)(key/AddrSpace) % AddrSpace; // simple algorithm
      if (s == 0) // can't allow a step size of 0
	s = 1;
    }
  
  /*****/
  if ((debug > 1) && (key != EMPTY))
    cout << "     Key " << key
	 << " step size is " << s
	 << endl;
  /*****/
  return s;
} // step

//-------------------------------------------------------//
int next ( int loc, int stepsize )
{
  // calculate the next location in the table
  // with wrap-around 
  // wraps as often as necessary mostly for Computed Chaining
  //   which could have reeely big steps
  int v;

  v = loc + stepsize;
  while ( v >= AddrSpace )
    v -= AddrSpace;
  return v;

} // next

//-------------------------------------------------------//
int prev ( int loc, int stepsize )
{
  // calculate the next location in the table
  // going backwards (with wrap-around)
  int v;

  v = loc - stepsize;
  while ( v < 0 )
    v += AddrSpace;
  return v;

} // prev

/*********************************************************/
/******* Placement Algorithms ****************************/
/*********************************************************/

// all assume they will only be called if there is room in the Table
//  i.e. they do not check for full Table
//
// These routines don't necessarily guarantee the space will be found
//    or that we won't loop endlessly while searching for a spot

void placech( int key ); // so we can use in another

void placelp( int key )
{
  // collision resolution technique: Linear Probing
  //    - looks for next location by linear search
  //    - step size 1

  int location;

  location = hash( key );
  
  while( Table[location] != EMPTY )
    {
      /*****/
      if (debug)
	cout << "      Loc: " << location
	     << " occupied by " << Table[location]
	     << endl;
      /*****/

      location = next( location, 1 );
    }

  Table[location] = key;
  /*****/
  if (debug)
    cout << "      Placed Key " << key << " at "
	 << location << endl;
  /*****/

  return;
} // placelp

//=======================================================//
void placedh1( int key )
{
  // collision resolution technique: Double Hashing Type 1
  //    hash twice
  //    - then revert to linear probing

  int location;

  location = hash( key );
  if ( Table[location] == EMPTY )
    {
      /*****/
      if (debug > 1)
	cout << "      placed at " << location << endl;
      /*****/
      Table[location] = key;
    }
  else // hash again
    {
      /*****/
      if (debug)
	cout << "      loc: " << location
	     << " occupied by: " << Table[location] << endl;
      /*****/
      location = hash2( key );
      
      // revert to linear probing if necessary
      while( Table[location] != EMPTY )
	{
	  /*****/
	  if (debug)
	    cout << "     loc: " << location
		 << " occupied by: " << Table[location] << endl;
	  /*****/
	  location = next( location, 1 );
	}

      /*****/
      if (debug)
	cout << "      placed at " << location << endl;
      /*****/
      Table[location] = key;
    }

  return;
} // placedh1

//=======================================================//
void placedh2( int key )
{
  // collision resolution technique: Double Hashing Type 2
  //   vary increment - basically still linear probing

  int location;
  int stepsize;

  location = hash( key );
  stepsize = step( key );

  while( Table[location] != EMPTY )
    {
      /*****/
      if (debug)
	cout << "      Loc: " << location
	     << " occupied by " << Table[location]
	     << endl;
      /*****/

      location = next( location, stepsize );
    }

  Table[location] = key;
  /*****/
  if (debug)
    cout << "      Placed Key " << key << " at "
	 << location << endl;
  /*****/


  return;
} // placedh2

//=======================================================//
//===== CHAINED OVERFLOW ================================//
//  place all keys that can go at home address
//  - save all synonyms for pass 2
//  - locations for synonyms found by linear search
//  - uses chains

void placesc( int key);  // uses simple chaining for second pass

void copass2 ()
{
  // do the second pass where we place synonyms
  // uses global array Overflow
  //
  // uses simple chaining for second pass

  int i;

  /*****/
  if (debug)
    cout << "Starting Pass 2................." << endl;
  /*****/
  
  for (i = 0; i < Ovfcount; i++)
    placesc( Overflow[i]);
  
  return;
} // copass2

//-------------------------------------------------------//
void placeco( int key )
{
  // collision resolution technique: Chained Overflow
  int location;

  location = hash( key );

  if (Table[location] == EMPTY)
    {
      Table[location] = key; // place it
      /*****/
      if (debug > 1)
	cout << "      Placed key " << key << " at "
	     << location << endl;
      /*****/
    }
  else // occupied means we have a synonym; save it for second pass
    {
      Overflow[Ovfcount] = key;
      Ovfcount++;
      /*****/
      if (debug)
	cout << "     Collision. Occupied by " << Table[location]
	     << " Incoming key reserved for 2nd pass." << endl;
      /*****/
    }

  return;
} // placeco

//=======================================================//
void placesc( int key )
{
  // collision resolution technique: Simple Chaining
  //  - uses chains and step size of 1
  //  - simply adds to current chain - regardless of whether
  //     keys in chain are all synonyms or not
  //  - finds next available location with forward linear probing

  int location;
  int ln;

  haslinks = YES;
  location = hash(key);

  if (Table[location] == EMPTY)
    {
      /*****/
      if (debug > 1)
	cout << "      placed at: " << location << endl;
      /*****/
      Table[location] = key;
    }
  else // occupied - follow links in chain to end
    {
      ln = Links[location];
      /*****/
      if (debug)
	{
	  cout << "      loc: " << location << " occupied by: "
	       << Table[location]
	       << " - stepping through chain..." << endl;
	  cout << "           " << Table[location]
	       << "'s link is: " << pl(ln) << endl;
	}
      /*****/
      
      while ( ln != EMPTY ) // get to end of chain
	{
	  location = ln;
	  /*****/
	  if (debug && (ln != EMPTY))
	    {
	      cout << "      stepping to " << ln
		   << " has key: " << Table[ln] << endl;
	      cout << "           " << Table[ln]
		   << "'s link is: " << pl(Links[ln]) << endl;
	    }
	  /*****/
	  ln = Links[location];
	}

      /*****/
      if (debug)
	cout << "          got to end of chain; now probing forward..." 
	     << endl;
      /*****/

      // now use probing to find next spot
      ln = next( location, 1);
      while (Table[ln] != EMPTY)
	{
	  /*****/
	  if (debug)
	    cout << "      loc: " << ln << " occupied by "
		 << Table[ln] << endl;
	  /*****/
	  ln = next( ln, 1 );
	}

      // PLACE
      /*****/
      if (debug)
	cout << "      Key: " << key << " placed at " << ln
	     << " link at " << location << " set to "
	     << ln << endl;
      /*****/
      Table[ln] = key;
      Links[location] = ln;

    } // else find location

  return;
} // placesc

//=======================================================//
void placech( int key )
{
  // collision resolution technique: Coalesced Hashing
  //  - uses chains and varies step size
  //  - simply adds to current chain - regardless of whether
  //     keys in chain are all synonyms or not
  //  - searches bottom up

  int location;
  int stepsize;
  int ln;

  haslinks = YES;
  location = hash(key);
  stepsize = step(key);

  //----- HOME ADDRESS EMPTY -----
  if (Table[location] == EMPTY)
    {
      /*****/
      if (debug > 1)
	cout << "      placed at: " << location << endl;
      /*****/
      Table[location] = key;
    }

  //----- HOME ADDRESS OCCUPIED -----
  else // occupied - follow links in chain to end
    {
      ln = Links[location];
      /*****/
      if (debug)
	{
	  cout << "      loc: " << location << " occupied by: "
	       << Table[location]
	       << " - stepping through chain..." << endl;
	  cout << "           " << Table[location]
	       << "'s link is: " << pl(ln) << endl;
	}
      /*****/
      
      //----- GET TO END OF CHAIN -----
      while ( ln != EMPTY ) // get to end of chain
	{
	  location = ln;
	  /*****/
	  if (debug && (ln != EMPTY))
	    {
	      cout << "      stepping to " << ln
		   << " has key: " << Table[ln] << endl;
	      cout << "           " << Table[ln]
		   << "'s link is: " << pl(Links[ln]) << endl;
	    }
	  /*****/
	  ln = Links[location];
	}

      /*****/
      if (debug)
	cout << "          got to end of chain; now probing from bottom up..." 
	     << endl;
      /*****/

      // ----- FIND NEXT AVAILABLE HOLE -----
      // now use probing to find next spot
      ln = AddrSpace-1;
      while (Table[ln] != EMPTY)
	{
	  /*****/
	  if (debug)
	    cout << "      loc: " << ln << " occupied by "
		 << Table[ln] << endl;
	  /*****/
	  ln = prev( ln, stepsize );
	}

      // PLACE
      /*****/
      if (debug)
	cout << "      Key: " << key << " placed at " << ln
	     << " link at " << location << " set to "
	     << ln << endl;
      /*****/
      Table[ln] = key;
      Links[location] = ln;

    } // else find location

  return;
} // placech

//=======================================================//
void placedc( int key )
{
  // collision resolution technique: Direct Chaining (dynamic)
  //   Variation on Coalesced Hashing
  //   When collision: if resident key is not at home, remove it
  //   (and all its successors); place the incoming key (link it in) 
  //   then re-place the reserved keys
  //   - uses step size of 1
  //   - uses simple chaining to replace keys
  //
  // NOTE: the links for the keys removed for re-placement are unimportant
  //       so we don't need to save them
  //     : this process could be iterative: every time we go to place a key,
  //       there could be more keys to move, but we don't in this version
  //       - we simply re-place keys using coalesced hashing

  int* replace;   // place to save keys that must be re-placed
  int rpcount;    // count of keys in 'replace' that need to be reinserted

  int location;
  int nextlink;
  int ln;

  haslinks = YES;
  location = hash(key);

  //----- HOME ADDRESS EMPTY -----
  if (Table[location] == EMPTY)
    {
      /*****/
      if (debug > 1)
	cout << "      placed at: " << location << endl;
      /*****/
      Table[location] = key;
    }

  //----- HOME ADDRESS OCCUPIED BY SYNONYM ----
  else if (hash(Table[location]) == location) // occupied by synonym
    // follow links in chain to end
    {
      ln = Links[location];
      /*****/
      if (debug)
	{
	  cout << "      loc: " << location << " occupied by: "
	       << Table[location]
	       << " - stepping through chain..." << endl;
	  cout << "           " << Table[location]
	       << "'s link is: " << pl(ln) << endl;
	}
      /*****/
      
      // ----- GET TO END OF CHAIN -----
      while ( ln != EMPTY ) // get to end of chain
	{
	  location = ln;
	  /*****/
	  if (debug && (ln != EMPTY))
	    {
	      cout << "      stepping to " << ln
		   << " has key: " << Table[ln] << endl;
	      cout << "           " << Table[ln]
		   << "'s link is: " << pl(Links[ln]) << endl;
	    }
	  /*****/
	  ln = Links[location];
	}

      /*****/
      if (debug)
	cout << "          got to end of chain; now probing next address..." 
	     << endl;
      /*****/

      // ----- FIND NEXT AVAILABLE LOCATION -----
      // now use forward linear probing to find next spot
      ln = next( location, 1);
      while (Table[ln] != EMPTY)
	{
	  /*****/
	  if (debug)
	    cout << "      loc: " << ln << " occupied by "
		 << Table[ln] << endl;
	  /*****/
	  ln = next( ln, 1 );
	}

      // PLACE
      /*****/
      if (debug)
	cout << "      Key: " << key << " placed at " << ln
	     << " link at " << location << " set to "
	     << ln << endl;
      /*****/
      Table[ln] = key;
      Links[location] = ln;

    } // else synonym; find location

  // ----- HOME ADDRESS OCCUPIED BY OTHER -----
  else // occupied by other than synonym;
    {
      // must remove it and all it's successors
      replace = new int[AddrSpace];
      rpcount = 0;

      // un-load keys in chain
      ln = location;
      while (ln != EMPTY)
	{
	  replace[rpcount] = Table[ln]; // get the key to re-place
	  rpcount++;
	  Table[ln] = EMPTY; // clear it's place in table
	  nextlink = Links[ln]; // find out where next one is
	  Links[ln] = EMPTY; // clear the link too
	  ln = nextlink; // this is location of next one
	} // while not empty follow chain

      // place incoming
      Table[location] = key;

      /*****/
      if (debug)
	{
	  cout << "      Key: " << key << " placed at " << location << endl;
	  cout << "         About to re-place rest of chain...\n" << endl;
	}
      /*****/

      // re-place the rest
      for (ln = 0; ln < rpcount; ln++)
	{
	  placesc( replace[ln] ); // use simple chaining
	} // end for

      delete [] replace;
      rpcount = 0;

    } // end pull keys and re-place

  return;
} // placedc

//=======================================================//
void placecc( int key )
{
  // collision resolution technique: Computed Chaining (dynamic)
  //    - uses pseudolinks
  //    - moves records not at home address
  //    - calculates step size based on RESIDENT key at
  //      each step
  //    - gets next location using step size of last key in chain

  int location;
  int stepsize;
  int pseudolink;
  int ln;
  int nextlink;

  int* replace;
  int rpcount;

  haslinks = YES;
  location = hash(key);

  //----- HOME ADDRESS EMPTY -----
  if (Table[location] == EMPTY)
    {
      /*****/
      if (debug > 1)
	cout << "      placed at: " << location << endl;
      /*****/
      Table[location] = key;
    }

  //----- HOME ADDRESS OCCUPIED BY SYNONYM -----
  else if (hash(Table[location]) == location) // occupied by synonym
    // follow links in chain to end
    {
      // next link is calculated : remember it is an offset from current
      if (Links[location] != EMPTY)
	ln = next(location, (Links[location] * step(Table[location])));
      else
	ln = EMPTY;
      /*****/
      if (debug)
	{
	  cout << "      loc: " << location << " occupied by: "
	       << Table[location]
	       << " - stepping through chain..." << endl;
	  cout << "           " << Table[location]
	       << "'s link is: " << pl(ln) << endl;
	}
      /*****/
      
      // ----- GET TO END OF CHAIN -----
      while ( ln != EMPTY ) // get to end of chain
	{
	  location = ln;
	  /*****/
	  if (debug && (ln != EMPTY))
	    {
	      cout << "      stepping to " << ln
		   << " has key: " << Table[ln] << endl;
	      cout << "           " << Table[ln]
		   << "'s link is: " << pl(Links[ln]) << endl;
	    }
	  /*****/
	  // next link is calculated
	  if (Links[location] != EMPTY)
	    ln = next(location, (Links[location] * step(Table[location])));
	  else
	    ln = EMPTY;
    } // while ln not empty

      /*****/
      if (debug)
	cout << "          got to end of chain; now probing down by stepsize..." 
	     << endl;
      /*****/

      // ----- FIND NEXT AVAILABLE HOLE -----
      // now use probing to find next spot
      // next place to look calculated using step size of resident key
      stepsize = step( Table[location] );
      ln = next( location, stepsize );
      pseudolink = 1;

      while (Table[ln] != EMPTY)
	{
	  /*****/
	  if (debug)
	    cout << "      loc: " << ln << " occupied by "
		 << Table[ln] << endl;
	  /*****/
	  ln = next( ln, stepsize );
	  pseudolink++;
	}

      // PLACE
      /*****/
      if (debug)
	cout << "      Key: " << key << " placed at " << ln
	     << " link at " << location << " set to "
	     << pseudolink << endl;
      /*****/
      Table[ln] = key;
      Links[location] = pseudolink;

    } // else find location of synonym

  //----- HOME ADDRESS OCCUPIED BY SOMEONE ELSE -----
  else // occupied by other than synonym
    {
      // must remove it and all it's successors
      replace = new int[AddrSpace];
      rpcount = 0;

      // un-load keys in chain
      ln = location;
      while (ln != EMPTY)
	{
	  replace[rpcount] = Table[ln]; // get the key to re-place
	  rpcount++;
	  /*****/
	  if (debug)
	    cout << "    Key: " << Table[ln] << " pulled from " << ln
		 << " step to next is " << pl(Links[ln]) << endl;
	  /*****/

	  // find out where next one is
	  if (Links[ln] != EMPTY)
	    {
	      nextlink = next(ln, (Links[ln] * step(Table[ln]))); 
	      Table[ln] = EMPTY; // clear it's place in table
	      Links[ln] = EMPTY; // clear the link too
	      ln = nextlink; // this is location of next one
	    }
	  else
	    {
	      Table[ln] = EMPTY; // clear it's place in table
	      ln = EMPTY;
	    }
	} // while not empty follow chain
      
      // place incoming
      Table[location] = key;
      
      /*****/
      if (debug)
	{
	  cout << "      Key: " << key << " placed at " << location << endl;
	  cout << "         About to re-place rest of chain...\n" << endl;
	}
      /*****/
      
      // re-place the rest
      for (ln = 0; ln < rpcount; ln++)
	{
	  placecc( replace[ln] );  // not sure this is
	  // reasonable or even safe but doing it anyways

	} // end for
      
      delete [] replace;
      rpcount = 0;
      
    } // end pull keys and re-place

  return;
} // placecc

//=======================================================//
void placebm( int key )
{
  // collision resolution technique: Brent's Method

  // Build primary probe chain in its entirety; store in PPC
  //  - this is not really necessary or efficient but done for
  //    illustrative purposes and hopefully for clarity

  int** PPC ; // [AddrSpace][2] col 0 for key values
                          // col 1 for current location of key in Table
  int S;                  // length of PPC
  int i,j;                // used as they are in lectures

  int homeaddr;           // of incoming key
  int stepsize;           // of incoming key
  int loc;                // first free hole in primary probe chain
                          // i.e. the end of PPC
  int iloc;               // current location of key 'i' from PPC
  int istep;              // step size of key 'i'
  int nextplace;          // jth potential position for ith key

  int i_plus_j;           // to control outer loop of attempt to
                          // find better location
  int placed;             // true when incoming key has been placed

  int temp;

  /****------BEGIN------****/

  // for building the primary probe chain
  PPC = new int*[AddrSpace];
  for (i = 0; i< AddrSpace; i++)
    PPC[i] = new int[2];

  homeaddr = loc = hash( key );
  stepsize = step( key );
  S = 1;

  /*****/
  if (debug && (Table[loc] != EMPTY))
    cout << "Primary Probe Chain:" << endl;
  /*****/

  // Build Primary Probe Chain
  while ( Table[loc] != EMPTY )
    {
      PPC[S-1][0] = Table[loc];    // key at that address
      PPC[S-1][1] = loc;           // where it lives
      /******/
      if (debug)
	{
	  cout << "     S: " << S
	       << " loc: " << loc
	       << "  ";
	  temp = step( Table[loc]); // prints out the step size for us
	}
      /*****/

      S++;
      loc = next( loc, stepsize );

    } // while not EMPTY

  // now S is length of PPC
  // homeaddr + S*stepsize = loc = location of first available hole
  // done set-up

  // ----- PLACE INCOMING SIMPLY -----
  if ( S <= 2 ) // can't do better by moving keys so simply place
                // the incoming key
    {
      Table[loc] = key;
      /*****/
      if (debug)
	cout << "     Placed key at "
	     << loc << endl;
      /*****/
    }

  // ----- LOOK FOR BETTER ARRANGEMENTS -----
  else // look for alternative locations
    {
      placed = 0;
      for ( i_plus_j = 2; i_plus_j < S; i_plus_j ++ )
	{
	  for (i = 1, j = i_plus_j - i; i < i_plus_j; i++, j-- )
	    {
	      // ? can we move the ith key in PPC j positions
	      // along its chain?
	      iloc = PPC[i-1][1];          // location of this key
	      istep = step( PPC[i-1][0]);  // its step size
	      nextplace = next( iloc, j*istep );
	                                   // the jth position for this key
	      /*****/
	      if (debug)
		cout << "      i = " << i << " j = " << j
		     << " try moving " << PPC[i-1][0]
		     << " to loc " << nextplace
		     << endl;
	      /*****/

	      if (Table[nextplace] == EMPTY)
		{
		  /*****/
		  if (debug)
		    cout << "     found a spot. Move key; "
			 << " Place incoming key at " << iloc
			 << endl;
		  /*****/
		  Table[nextplace] = PPC[i-1][0];
		  Table[iloc] = key;
		  placed = 1;
		  break;
		}
	      else // not empty
		{
		  /*****/
		  if (debug)
		    cout << "      failed: occupied." << endl;
		  /*****/
		} // if loc EMPTY
	    } // for i,j

	  if (placed) return;  // DONE

	} // for i_plus_j
      
    } // else look for alternatives
  
  // ----- NOTHING BETTER -----
  if (!placed) // couldn't find a better location
    {
      /*****/
      if (debug)
	cout << "     Place key at end of PPC: loc: "
	     << loc << endl;
      /*****/

      Table[loc] = key;

    } // if !placed
  
  return;
} // placebm

//=======================================================//
//==== Support Routines for Binary Tree Insertion =======//
//=======================================================//

void initnode ( node* N, int sival, int isrc, node* p1 )
{
  // initialize a new node

  N->S = step(N->K);
  N->Si = sival;
  N->rchild = isrc;
  N->parent = p1;
  N->sibling = NULL;
  N->left = NULL;
  N->right = NULL;

  return;
} // initnode

//--------------------------------------------------------//
int which ( node* np, int val )
{
  // figure out which value we want from the node
  switch (val)
    {
    case 1: return np->loc;
      break;
    case 2: return np->K;
      break;
    case 3: return np->S;
      break;
    case 4: return np->Si;
    }

} // which

//--------------------------------------------------------//
void printline( node* np, int sp1, int sp2, char* label, int valcode)
{
  int val;
  // print a line of output
  // for displaying the decision tree
  
  val = which( np, valcode );
  if (val != EMPTY)
    cout << setw(sp1) << label << setw(4) << val;
  else
    cout << setw(sp1) << label << setw(4) << " ---";
  np = np->sibling;
  while( np != NULL )
    {
      val = which( np, valcode );
      if (val != EMPTY)
	cout << setw(sp2) << label << setw(4) << val;
      else
	cout << setw(sp2) << label << setw(4) << " ---";
      np = np->sibling;
    }
  cout << endl;
  return;
} // printline

//--------------------------------------------------------//
void drawtree ( node* P, int levels )
{
  // draw the decision tree we have made
  int totalsp,firstsp,midsp;
  node* np;
  int i;
  int l2draw; // don't draw more than 4 levels
              // because that's all that will fit nicely on a page

  if (levels > 4)
    l2draw = 4;
  else 
    l2draw = levels;

  totalsp = int(pow( 2, l2draw )) * 6; // total spaces required for this tree
  firstsp = totalsp -3;
  np = P;

  /*****/
  if (debug)
    cout << " Drawing tree with " << levels << " levels..." << endl;
  /*****/


  for ( i = 1; i <= l2draw; i++ )
    {
      midsp = firstsp;
      firstsp = (firstsp + 3 ) / 2 - 3;

      // must do one line at a time
      // location of key
      printline( np, firstsp, midsp, "L:", 1);
      // key value
      printline( np, firstsp, midsp, "K:", 2);
      // step value of this key
      printline( np, firstsp, midsp, "S:", 3);
      //step value of incoming key
      printline( np, firstsp, midsp, "Si:", 4);

      cout << endl; // give us a blank line

      // go to the next level of the tree
      np = np->left;
    } // for i

  return;
} // drawtree

//-------------------------------------------------------//
void deltree ( node* P )
{
  // Done: release the tree

  if (P->left != NULL)
    {
      deltree( P->left );
      delete P->left;
    }
  if (P->right != NULL)
    {
      deltree( P->right );
      delete P->right;
    }
  delete P;
  return;
} // deltree

//-------------------------------------------------------//
void placebti( int key )
{
  // collision resolution technique: Binary Tree Insertion
  //
  // The tree represents a series of moves to be made to try
  // and minimize the average length of the probe chains.
  // Tree is used as a decision tree
  //
  // don't need to do regular traversals
  // do need the ability to do a breadth-first traversal

  int homeaddr;

  int levels = 1;
  node* root;        // usual use
  node* incoming;    // the key being placed
  node* parent;      // nearest parent to current level (N)
  node* first;       // first node at this level (N+1)
  node* newnode;     // new node just created (level N+1)
  node* last;        // most recently created node before newnode

  // check for available home address
  homeaddr = hash( key );

  //----- HOME ADDRESS EMPTY -----
  if (Table[homeaddr] == EMPTY)
    {
      Table[homeaddr] = key;
      /*****/
      if (debug > 1)
	cout << "      placed at: " << homeaddr << endl;
      /*****/
    }

  //----- HOME ADDRESS OCCUPIED; BUILD TREE -----
  else  // Starting to build the tree
    {

      incoming = new(node);
      incoming->K = key;
      incoming->loc = homeaddr;
      initnode( incoming, 0, YES, NULL );
      
      root = new(node);
      // what's at 'key's home address?
      root->K = Table[incoming->loc];
      root->loc = incoming->loc;
      initnode( root, incoming->S, YES, incoming );
      
      // filling in the tree
      parent = root;
      first = NULL;
      last = NULL;
      
      // keep going (building) till we find an empty address
      while ( parent->K != EMPTY )
	{
	  // build the left child
	  newnode = new(node);
	  parent->left = newnode;

	  // check for begining of new level N+1
	  if (first == NULL)
	    {
	      first = newnode;
	      last = NULL; // beginning of new level has no last
	                   // must do this to prevent circular references
	      levels++;
	    }
	  // get next position in probe chain
	  newnode->loc = next( parent->loc, parent->Si );

	  newnode->K = Table[newnode->loc];
	  initnode( newnode, parent->Si, NO, parent );
	  // check if we have a sibling to our left
	  if ( last != NULL ) // link it in
	    last->sibling = newnode;
	  last = newnode;
	  
	  // build right child
	  if (newnode->K != EMPTY)
	    {
	      newnode = new(node);
	      parent->right = newnode;
	      // get next position in probe chain
	      newnode->loc = next( parent->loc, parent->S );

	      newnode->K = Table[newnode->loc];
	      initnode( newnode, parent->S, YES, parent );
	      // MUST have left sibling
	      if ( last != NULL )
		last->sibling = newnode;
	      last = newnode;
	      
	      // check to see if we're done...
	      if (newnode->K == EMPTY)
		break;
	      else
		{
		  // get next parent (this level)to work on or go to next level
		  if (parent->sibling != NULL)
		    parent = parent->sibling;
		  else // next level
		    {
		      parent = first;
		      last = NULL;
		      first = NULL;
		    }
		} // checking if we're done
	    } // build right child

	  else // no need to build right child means we're done
	    break;
	  
	} // while not empty

      /*****/
      if (debug)
	cout << "      Empty Spot at: " << last->loc << endl;
      /*****/
      // draw the thing we built
      drawtree ( root, levels );
      
      // Moving the Keys PART 2
      // 'last' is the node which references the empty slot in the Table
      // if it is a right node then move the key@parent into the
      //    specified location in table
      // if it is a left node copy the current location given by 'last'
      //    into the parent node (not in table)
      
      while ( last != root )
	{
	  if (last->rchild)
	    {
	      // do the move
	      Table[last->loc] = last->parent->K;
	      
	      /*****/
	      if (debug)
		cout << "       Move Key: " << last->parent->K
		     << " into Loc: " << last->loc << endl;
	      /*****/
	    }
	  else
	    {
	      // copy current into parent
	      /*****/
	      if (debug)
		cout << "      Skip past Loc: " << last->parent->loc 
		     << " to " << last->loc << endl;
	      /*****/
	      last->parent->loc = last->loc;
	    }
	  // back up to previous level
	  last = last->parent;
	}

      // place incoming key once we get to the root
      Table[root->loc] = key;
      /*****/
      if (debug)
	cout << "      Place key " << key << " at Loc: " << root->loc << endl;
      /*****/
      
      // Done - release tree
      deltree( root );
      delete incoming;

    } // end collision

  return;
} // placebti

/*********************************************************/
/***** MAIN **********************************************/
/*********************************************************/
int main( int argc, char* argv[] )
{
  int i; // for indexing

  // get args - set flags
  if (argc <= 1) // invoked without arguments
    {
      help();
      exit(0);
    }

  outname = new (char[128]);
  getargs ( argc, argv, fname, outname, AddrSpace, debug, crt );
  cout << "Filename is: " << fname << endl;
  cout << "Table Size is: " << AddrSpace << endl;
  cout << "Debug Switch = " << debug << endl << endl;


  // which placement strategy are we going to use?
  switch (crt)
    {
    case LP: place = placelp;
      break;
    case DH1: place = placedh1;
      break;
    case DH2: place = placedh2;
      break;
    case CO: place = placeco;
      break;
    case SC: place = placesc;
      break;
    case CH: place = placech;
      break;
    case DC: place = placedc;
      break;
    case CC: place = placecc;
      break;
    case BM: place = placebm;
      break;
    case BTI: place = placebti;
    } // end switch


  // initialize table:
  Table    = new (int[AddrSpace]);
  Links    = new (int[AddrSpace]);
  Overflow = new (int[AddrSpace]);

  for (i = 0; i < AddrSpace; i++)
    {
      Table[i]    = EMPTY;
      Links[i]    = EMPTY;
      Overflow[i] = EMPTY;
    }

  // open file of keys to place
  keyfile.open( fname, ios::in );
  if (keyfile.fail())
    {
      cout << "Unable to open file. Code is: " << keyfile.rdstate()
	   << " Bailing out." << endl;
      exit(1);
    }

  // while not eof and there's room in the Table
  while ( !keyfile.eof() && (Nkeys < AddrSpace))
    { 
      // read key
      keyfile >> key;
      if (keyfile.eof())
	break; // DONE
      else
	Nkeys++;   // count it

      // place key according to chosen placement strategy
      place( key );

      /*****/
      if (debug > 2)
	if (haslinks)
	  displaytablelinks( Table, Links );
        else
	  displaytable( Table );
      /*****/

      // done
    } // while

  if (Nkeys >= AddrSpace)
    cout << "TABLE FULL" << endl;
  
  // done all PASS 1; check for those that need a second pass
  if (crt == CO)
    copass2();
  
  /*****/
  if (debug < 3) // table hasn't been displayed yet
    if (haslinks)
      displaytablelinks( Table, Links );
    else
      displaytable( Table );
  /*****/
  
  // dump table to file
  outfile.open( outname, ios::out );
  
  for ( i = 0; i < AddrSpace; i++)
    {
      if (Table[i] == EMPTY)
	outfile << -1;
      else
	outfile << Table [i];
    if (haslinks)
      outfile << "  " << pl(Links [i]);
    outfile << endl;
    } // end dump table

  outfile.close();

  cout << "Hash Table File called: " << outname << endl;

  cout << "Done." << endl;

} // END PROGRAM ---------------------------------------------
