Implement the following Hash class using separate chaining.
template <typename HashedObj>
class HashTable
{
public:
HashTable(int (* h)(HashedObj x), int size = 101 )
: currentSize( 0 ), hash(h)
{ theLists.resize( size ); }
bool contains( const HashedObj & x ) const
// If x is in the table, it returns true, otherwise, it returns false.
{
//insert here.
}
void makeEmpty( )
{
for( int i = 0; i < theLists.size( ); i++ )
theLists[ i ].clear( );
}
bool insert( const HashedObj & x )
//Insert key x if x is not in the table and return true. Otherwise, return false and do nothing. If the table is full, you will call rehash.
{
//insert here.
}
bool remove( const HashedObj & x )
//If x is present in the table, remove it and return true. Otherwise, return false.
{
//insert here.
}
private:
vector<list<HashedObj> > theLists; // The array of Lists
int currentSize;
int (*hash)(HashedObj x); //hash function
int myhash( const HashedObj & x ) const
{
int hashVal = hash( x );
hashVal %= theLists.size( );
if( hashVal < 0 )
hashVal += theLists.size( );
return hashVal;
}
void rehash( )
{
vector<list<HashedObj> > oldLists = theLists;
// Create new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( int j = 0; j < theLists.size( ); j++ )
theLists[ j ].clear( );
// Copy table over
currentSize = 0;
for( int i = 0; i < oldLists.size( ); i++ )
{
list<HashedObj>::iterator itr = oldLists[ i ].begin( );
while( itr != oldLists[ i ].end( ) )
insert( *itr++ );
}
}
};
The constructor HashTable has two parameters: the first one specifies your hash function and the second one specifies the size of the hash table.
For example, you may create a hash table like the following:
HashTable t(h, 10007);
where h is a hash function you have defined.
You may use the following functions:
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;
}
int nextPrime( int n )
{
if( n % 2 == 0 )
n++;
for( ; !isPrime( n ); n += 2 )
;
return n;
}
题目要求实现一个哈希类。此处需要注意的是:
1、在类的成员函数后加const,就表明这个函数是不能改变类的成员变量,相当于给this指针加上了const修饰,也不能调用其他非const成员函数,否则编译器会报错;所以在调用与成员变量有关的迭代器时,迭代器类型是const;
2、容器中的类型为模板类型时,在使用迭代器是也要在前面加上 typename;
3、函数指针:是指向函数的指针变量,有了指向函数的指针变量后,可用该指针变量调用函数,函数指针有两个用途:调用函数和做函数的参数;
4、标准库中的list容器有push_back, push_front, pop_back, pop_front;
#include <iostream>
#include <vector>
#include <list>
using namespace std;
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;
}
int nextPrime( int n )
{
if( n % 2 == 0 )
n++;
for( ; !isPrime( n ); n += 2 )
;
return n;
}
template <typename HashedObj>
class HashTable
{
public:
HashTable(int (* h)(HashedObj x), int size = 101 )
: currentSize( 0 ), hash(h)
{ theLists.resize( size ); }
//任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性,相当于给this指针加上了const修饰。
bool contains( const HashedObj & x ) const
// If x is in the table, it returns true, otherwise, it returns false.
{
int key = myhash(x);
//模板类型的迭代器,声明时前面要加“typename”,注意迭代器类型是const
typename list<HashedObj>::const_iterator it = theLists[key].begin();
while (it != theLists[key].end()) {
if (x == *it) {
return true;
}
it++;
}
return false;
}
void makeEmpty()
{
for( int i = 0; i < theLists.size( ); i++ )
theLists[ i ].clear( );
}
bool insert( const HashedObj & x )
//Insert key x if x is not in the table and return true. Otherwise, return false and do nothing. If the table is full, you will call rehash.
{
if (contains(x)) {
return false;
}
if (currentSize + 1 > theLists.size()) {
rehash();
}
int key = myhash(x);
theLists[key].push_back(x);
currentSize++;
return true;
}
bool remove( const HashedObj & x )
//If x is present in the table, remove it and return true. Otherwise, return false.
{
if (!contains(x)) {
return false;
}
int key = myhash(x);
typename list<HashedObj>::iterator it = theLists[key].begin();
while (it != theLists[key].end()) {
if (x == *it) {
theLists[key].erase(it);
return true;
}
it++;
}
}
private:
vector<list<HashedObj> > theLists; // The array of Lists
int currentSize;
int (*hash)(HashedObj x); //hash function
int myhash( const HashedObj & x ) const
{
int hashVal = hash( x );
hashVal %= theLists.size( );
if( hashVal < 0 )
hashVal += theLists.size( );
return hashVal;
}
void rehash( )
{
vector<list<HashedObj> > oldLists = theLists;
// Create new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( int j = 0; j < theLists.size( ); j++ )
theLists[ j ].clear( );
// Copy table over
currentSize = 0;
for( int i = 0; i < oldLists.size( ); i++ )
{
typename list<HashedObj>::iterator itr = oldLists[i].begin();
while( itr != oldLists[ i ].end( ) )
insert( *itr++ );
}
}
};