二次探査再ハッシュHashテーブルのC++実装

18087 ワード

/*****************************************************************************
 *                                    student.h

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


#ifndef STUDENT_H
#define STUDENT_H




#include <iostream>
#include <string>




using namespace std;




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


#endif


 
/*****************************************************************************
 *                                    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.
 *
 *****************************************************************************/
/*
	      ,               ,           。
	      ,    :          ,         ,    
	         ,            。                    
	     。


    :        ,        ,              ,
               。
*/


#ifndef HASHTABLE_H
#define HASHTABLE_H


#include <iostream>
#include <cstdlib>
#include <string>


using namespace std;


template <typename Object, typename Key>
class HashTable
{
	public:
		
		explicit HashTable( int size = 7 );
		~HashTable();


		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"


#endif

 
実装ファイル:
 
/*****************************************************************************
 *                               hashtable_impl.h
 *
 * Implementation for Hashtable class.
 *
 *****************************************************************************/


// constructors and deconstructor
template <typename Object, typename Key>
HashTable<Object, Key>::HashTable( int size ) : tableSize(size)
{
	array = new HashEntry[tableSize];
	if( array == NULL )
	{
		cout << "Out of memory!" << 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 the "k" and the 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;
	}
}


//insert an element into the hashtable. If the number
//is greater than half of the table size, then  make "re-hashing"
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;
}


//remove 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;
}


//find the position of the element with key "k" int the hashtable
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 &&
		   array[currentPos].element.key != k )
	{
		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
//                ,          ,         
//       ,         。                    。
//  ,                  (              ),
//         ,    (    )                。
//         (rehashing)。           ;      O(N),   N
//               2N,         ,            。
//               。


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 == NULL )
	{
		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;
}


//find the next prime number larger than n
int nextPrime( int n )
{
	int i = n+1;
	while( isPrime(i)==false )
		i += 2;


	return i;


}


 
テストファイル:
 
/*****************************************************************************
 *                               hashtable_test.cpp
 *
 * Hash table class testing.
 *
 *****************************************************************************/


#include <iostream>
#include <string>
#include "Student.h"
#include "hashtable.h"


using namespace std;


const int 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 j=0; j<N; ++j )
	{
		if( ht.remove( y[j], stu ) )
			cout << "removing success: " << stu;
		else
			cout << "Removing failure." << endl;
	}
	cout << endl;
	for( int k=0; k<N; ++k )
	{
        if( ht.search( x[k], stu ) )
            cout << "Searching success: " << stu;
        else
            cout << "Searching failure." << endl;
	 }
    cout << endl;


	return 0;
}