头文件:
/*****************************************************************************
* student.h
*
* A student class including comparison operators.
*
* Zhang Ming, 2009-10
*****************************************************************************/
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
using namespace std;
namespace itlab
{
class Student
{
public:
Student() : key(0), firstName("Ming"), lastName("Zhang")
{ }
Student( int number, const string &name1="Ming",
const string &name2="Zhang" )
{
key = number;
firstName = name1;
lastName = name2;
}
~Student()
{ }
inline void operator=( const Student &stu )
{
key = stu.key;
firstName = stu.firstName;
lastName = stu.lastName;
}
inline bool operator<( const Student &stu )
{ return key < stu.key; }
inline bool operator>( const Student &stu )
{ return key > stu.key; }
inline bool operator==( const Student &stu )
{ return key == stu.key; }
friend istream& operator>>( istream &in, Student &stu )
{
in >> stu.key >> stu.lastName >> stu.firstName;
return in;
}
friend ostream& operator<<( ostream &out, Student &stu )
{
out << stu.key << "\t"
<< stu.lastName << " " << stu.firstName << endl;
return out;
}
int key;
private:
string firstName;
string lastName;
};
// class Student
}
// namespace itlab
#endif
// STUDENT_H
/*****************************************************************************
* hashtable.h
*
* Hash table implemented by C++ template class.
*
* This class provides "search", "insert" and "remove" operations by using a
* Hash Table. We use the quadratic probing method to prevent the element
* number exceeding half of the total table size.
*
* Zhang Ming, 2009-10
*****************************************************************************/
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
namespace itlab
{
template <typename Object, typename Key>
class HashTable
{
public:
explicit HashTable( int size=7 );
~HashTable();
// HashTable( const HashTable<Object, Key> &rhs );
// HashTable<Object, Key>& operator=( const HashTable<Object, Key> &rhs );
void makeEmpty();
inline bool search( const Key k, Object &x ) const;
bool insert( const Object &x );
bool remove( const Key k, Object &x );
enum EntryFlag { ACTIVE, EMPTY, DELETED };
private:
struct HashEntry
{
Object element;
EntryFlag info;
HashEntry( const Object &x=Object(), EntryFlag i=EMPTY )
: element(x), info(i)
{ }
};
HashEntry *array;
int currentSize;
int tableSize;
inline bool isActive( int currentPos ) const;
int findPos( const Key k ) const;
void rehash( );
int myhash( const Key k ) const;
};
bool isPrime( int n );
int nextPrime( int n );
#include <hashtable-impl.h>
}
// namespace itlab
#endif
// HASHTABLE_H
实现文件:
/*****************************************************************************
* hashtable-impl.h
*
* Implementation for Hashtable class.
*
* Zhang Ming, 2009-10
*****************************************************************************/
/**
* constructors and destructor
*/
template <typename Object, typename Key>
HashTable<Object, Key>::HashTable( int size ) : tableSize(size)
{
array = new HashEntry[tableSize];
if( !array )
{
cout << "Out of memory!" << endl << endl;
exit( 1 );
}
makeEmpty();
}
template <typename Object, typename Key>
HashTable<Object, Key>::~HashTable()
{
delete []array;
}
/**
* Make the table empty.
*/
template <typename Object, typename Key>
void HashTable<Object, Key>::makeEmpty( )
{
currentSize = 0;
for( int i = 0; i < tableSize; ++i )
array[i].info = EMPTY;
}
/**
* Searching an element with key "k" and then assign it to "x".
*/
template <typename Object, typename Key>
inline bool HashTable<Object, Key>::search( const Key k, Object &x ) const
{
int index = findPos( k );
if( !isActive( index ) )
return false;
else
{
x = array[index].element;
return true;
}
}
/**
* Inserting an element into the table. If the number of elements
* is greater than half of the table size, then making "re-hash".
*/
template <typename Object, typename Key>
bool HashTable<Object, Key>::insert( const Object &x )
{
int currentPos = findPos( x.key );
if( isActive( currentPos ) )
return false;
array[currentPos] = HashEntry( x, ACTIVE );
if( ++currentSize > tableSize/2 )
rehash( );
return true;
}
/**
* Removing an element with key "k" and then assign it to "x".
*/
template <typename Object, typename Key>
bool HashTable<Object, Key>::remove( const Key k, Object &x )
{
int currentPos = findPos( k );
if( !isActive( currentPos ) )
return false;
else
{
x = array[currentPos].element;
array[currentPos].info = DELETED;
currentSize--;
return true;
}
}
/**
* If the current position is active, return true.
*/
template <typename Object, typename Key>
inline bool HashTable<Object, Key>::isActive( int currentPos ) const
{
return array[currentPos].info == ACTIVE;
}
/**
* If the current position is active, return true.
*/
template <typename Object, typename Key>
int HashTable<Object, Key>::findPos( const Key k ) const
{
int offset = 1;
int currentPos = myhash( k );
while( array[currentPos].info != EMPTY && // these two testing
array[currentPos].element.key != k ) // cann't be switched
{
currentPos += offset;
offset += 2;
if( currentPos >= tableSize )
currentPos -= tableSize;
}
return currentPos;
}
/**
* To ensure the number of elements is not greater than
* half of the table size.
*/
template <typename Object, typename Key>
void HashTable<Object, Key>::rehash( )
{
int oldTableSize = tableSize;
HashEntry *oldArray = array;
tableSize = nextPrime( 2*oldTableSize );
array = new HashEntry[tableSize];
if( !array )
{
cerr << "Out of memory!" << endl << endl;
exit( 1 );
}
for( int j=0; j<tableSize; ++j )
array[j].info = EMPTY;
currentSize = 0;
for( int i=0; i<oldTableSize; ++i )
if( oldArray[i].info == ACTIVE )
insert( oldArray[i].element );
delete []oldArray;
}
/**
* hash mapping.
*/
template <typename Object, typename Key>
int HashTable<Object, Key>::myhash( const Key k ) const
{
int hashValue = k % tableSize;
if( hashValue < 0 )
hashValue += tableSize;
return hashValue;
}
/**
* If "n" is a prime number, return true.
*/
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;
}
/**
* Finding the nest prime number greater than "n".
*/
int nextPrime( int n )
{
if( n%2 == 0 )
n++;
for( ; !isPrime(n); n+=2 )
;
return n;
}
测试文件:
/*****************************************************************************
* hashtable_test.cpp
*
* Hash table class testing.
*
* Zhang Ming, 2009-10
*****************************************************************************/
#include <iostream>
#include <string>
#include <student.h>
#include <hashtable.h>
using namespace std;
using namespace itlab;
int const N = 10;
int main()
{
int x[N] = { 3, 2, 1, 4, 5, 6, 7, 10, 9, 8 };
int y[N] = { 3, 2, 1, 4, 5, 16, 17, 20, 19, 18 };
Student stu;
HashTable<Student, int> ht;
for( int i=0; i<N; ++i )
{
stu.key = x[i];
if( ht.insert( stu ) )
cout << "Inserting success: " << stu;
else
cout << "Inserting failure." << endl;
}
cout << endl;
for( int i=0; i<N; ++i )
if( ht.remove( y[i], stu ) )
cout << "Removing success: " << stu;
else
cout << "Removing failure." << endl;
cout << endl;
for( int i=0; i<N; ++i )
if( ht.search( x[i], stu ) )
cout << "Searching success: " << stu;
else
cout << "Searching failure." << endl;
cout << endl;
return 0;
}