1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <vector>
using namespace std;
template <class HashedObj>
class HashTable
{
public:
explicit HashTable( const HashedObj & notFound, int size = 101 );
HashTable( const HashTable & rhs )
: ITEM_NOT_FOUND( rhs.ITEM_NOT_FOUND ),
array( rhs.array ), currentSize( rhs.currentSize ) { }
const HashedObj & find( const HashedObj & x ) const;
void makeEmpty( );
void insert( const HashedObj & x );
void remove( const HashedObj & x );
const HashTable & operator=( const HashTable & rhs );
enum EntryType { ACTIVE, EMPTY, DELETED };
private:
struct HashEntry
{
HashedObj element;
EntryType info;
HashEntry( const HashedObj & e = HashedObj( ), EntryType i = EMPTY )
: element( e ), info( i ) { }
};
vector<HashEntry> array;
int currentSize;
const HashedObj ITEM_NOT_FOUND;
bool isActive( int currentPos ) const;
int findPos( const HashedObj & x ) const;
void rehash( );
};
/**
* Construct the hash table.
*/
template <class HashedObj>
HashTable<HashedObj>::HashTable( const HashedObj & notFound, int size )
: ITEM_NOT_FOUND( notFound ), array( nextPrime( size ) )
{
makeEmpty( );
}
void HashTable<class HashedObj>::makeEmpty()
{
currentSize = 0;
for( int i = 0; i < array.currentSize(); i++ )
array[ i ].info = EMPTY;
}
/**
* Method that performs quadratic probing resolution.
* Return the position where the search for x terminates.
*/
template <class HashedObj>
int HashTable<HashedObj>::findPos( const HashedObj & x ) const
{
int collisionNum = 0;
int currentPos = hash( x, array.size( ) );
while( array[ currentPos ].info != EMPTY &&
array[ currentPos ].element != x )
{
currentPos += 2 * ++collisionNum - 1; // add the difference
if( currentPos >= array.size( ) ) // perform the mod
currentPos –= array.size( ); // if necessary
}
return currentPos;
}
/**
* Return true if currentPos exists and is active.
*/
template <class HashedObj>
bool HashTable<HashedObj>::isActive( int currentPos ) const
{
return array[ currentPos ].info == ACTIVE;
}
/**
* Remove item x from the hash table.
* x has to be in the table
*/
template <class HashedObj>
void HashTable<HashedObj>::remove( const HashedObj & x )
{
int currentPos = findPos( x );
if( isActive( currentPos ) )
array[ currentPos ].info = DELETED;
}
/**
* Find item x in the hash table.
* Return the matching item, or ITEM_NOT_FOUND, if not found.
*/
template <class HashedObj>
const HashedObj & HashTable<HashedObj>::find( const HashedObj & x ) const
{
int currentPos = findPos( x );
if (isActive( currentPos ))
return array[ currentPos ].element;
return ITEM_NOT_FOUND;
}
/**
* Insert item x into the hash table. If the item is
* already present, then do nothing.
*/
template <class HashedObj>
void HashTable<HashedObj>::insert( const HashedObj & x )
{
// Insert x as active
int currentPos = findPos( x );
if( isActive( currentPos ) )
return;
array[ currentPos ] = HashEntry( x, ACTIVE );
// enlarge the hash table if necessary
if( ++currentSize >= array.size( ) / 2 )
rehash( );
}
/**
* Expand the hash table.
*/
template <class HashedObj>
void HashTable<HashedObj>::rehash( )
{
vector<HashEntry> oldArray = array;
// Create new double-sized, empty table
array.resize( nextPrime( 2 * oldArray.size( ) ) );
for( int j = 0; j < array.size( ); j++ )
array[ j ].info = EMPTY;
// Copy table over
currentSize = 0;
for( int i = 0; i < oldArray.size( ); i++ )
if( oldArray[ i ].info == ACTIVE )
insert( oldArray[ i ].element );
}
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;
}
#endif
|