// // Code from Weiss C++ Data Structures text heavily modified by Robert // Sloan on October 14, 2002, to use STL instead of Weiss's own // classes. // // Especially interesting design and coding issues: // Use of the STL find function from the algorith library to actually // do the searching in the linked lists. Find takes 3 arguments: a // begin and end iterator, and the item being sought. // Here, just for extra kicks, Sloan was driven mad by the program // failing to compile until he realized that he needed to refer to the // function as std::find (even with the using statement up top), // because otherwise it would be taken as the HashTable::find. // Note that in insert and remove when we actually want to ALTER a // list, we have to refer to theLists[position], because if we just // declared a variable: // whichList = theLists[position] // and altered it, we would be altering a COPY of the list that // resides in the hashtable. // // Generates a warning about implicit typenames with g++ compiler; but // works just fine // #include "SeparateChaining.hh" #include #include using namespace std; /** * Used for debugging */ template void printList( const list< T > & l) { list::const_iterator itr = l.begin(); while (itr != l.end()) { cout << *itr << endl; itr++; } } /** * Internal method to test if a positive number is prime. * Not an efficient algorithm. */ bool isPrime( int n ) { if( n == 2 || n == 3 ) return true; if( n == 1 || n % 2 == 0 ) return false; for( int i = 3; i * i <= n; i += 2 ) if( n % i == 0 ) return false; return true; } /** * Internal method to return a prime number at least as large as n. * Assumes n > 0. */ int nextPrime( int n ) { if( n % 2 == 0 ) n++; for( ; !isPrime( n ); n += 2 ) ; return n; } template void HashTable::printTable() const { for (int i = 0; i < theLists.size(); i++) { cout << "Slot " << i << ": "; printList(theLists[i]); cout << endl; } } /** * Construct the hash table. */ template HashTable::HashTable( const HashedObj & notFound, int size ) : ITEM_NOT_FOUND( notFound ), theLists( nextPrime( size ) ) {} /** * Insert item x into the hash table. If the item is * already present, then do nothing. */ template void HashTable::insert( const HashedObj & x ) { int slotNumber = hash( x, theLists.size( ) ); list whichList = theLists[ slotNumber ]; //Check that item is NOT already in list. If not, insert it if (std::find(whichList.begin(), whichList.end(), x) == whichList.end()) theLists[slotNumber].push_front(x); } /** * Remove item x from the hash table. */ template void HashTable::remove( const HashedObj & x ) { int slotNumber = hash( x, theLists.size( ) ); list::iterator itr = std::find(theLists[slotNumber].begin(), theLists[slotNumber].end(), x); if ( itr != theLists[slotNumber].end() ) // i.e., x is in list at itr theLists[slotNumber].erase(itr); } /** * Find item x in the hash table. * Return the matching item or ITEM_NOT_FOUND if not found */ template const HashedObj & HashTable::find( const HashedObj & x ) const { list whichList = theLists[ hash( x, theLists.size( ) ) ]; list::iterator itr = std::find(whichList.begin(), whichList.end(), x); if( itr == whichList.end() ) return ITEM_NOT_FOUND; else return *itr; } /** * Make the hash table logically empty. */ template void HashTable::makeEmpty( ) { for( int i = 0; i < theLists.size( ); i++ ) theLists[ i ].clear( ); } /** * Deep copy. */ template const HashTable & HashTable::operator=( const HashTable & rhs ) { if( this != &rhs ) theLists = rhs.theLists; return *this; } /** * A hash routine for string objects. */ int hash( const string & key, int tableSize ) { int hashVal = 0; for( int i = 0; i < key.length( ); i++ ) hashVal = 37 * hashVal + key[ i ]; hashVal %= tableSize; if( hashVal < 0 ) hashVal += tableSize; return hashVal; } /** * A hash routine for ints. */ int hash( int key, int tableSize ) { if( key < 0 ) key = -key; return key % tableSize; }