www.pudn.com > GameEngine_src.rar > CHashTable.h


#ifndef CHashTable_h 
#define CHashTable_h 
#include  
#include  
#include  
#include  
 
 
///////////////////////////////////////////////////////////////////////////// 
//哈希表元素,注意T必须能够使用%,==,和=号运算符,还要有复制构造函数 
///////////////////////////////////////////////////////////////////////////// 
template  
class CHashTableNode 
{ 
public: 
	CHashTableNode() 
	{ m_IsNotNull = false; } 
	~CHashTableNode() 
	{ m_IsNotNull = false; } 
 
	T m_element;			//元素 
	bool m_IsNotNull;		//该元素是否有数据,true为非空,false为空 
}; 
 
///////////////////////////////////////////////////////////////////////////// 
//哈希表模板,注意使用此哈希表类前,一定要先初始化 
///////////////////////////////////////////////////////////////////////////// 
template  
class CHashTable   
{ 
public: 
	CHashTable(); 
	~CHashTable(); 
 
	bool Init( int size );						//初始化,size为表长度 
	void Free();								//释放 
 
	bool Insert( T &e )							//不重复的插入一个元素 
	{ return Insert( e, false ); } 
 
	bool Insert( T &e, bool isRepeat );			//插入一个元素 
	T  * Find( const T &in );					//查找一个元素 
	void Clear();								//清空所有元素 
	void CopyElement( T *pBuf );				//把当前的所有元素拷贝到一个缓冲中 
	void CopyFromArray( T *pBuf, int isize );	//把一个数组中的元素散列到表中 
 
	int  GetElementNum() { return m_iElementNum; } 
	void SetElementNum( int i ) {m_iElementNum = i;} 
	int  GetTableSize()  { return m_iTableSize; } 
	bool IsEmpty()		{ return m_iElementNum <= 0; } 
	CHashTableNode  *GetPointer() 
	{ return m_HashTable; } 
 
public: 
	void Begin();								//在迭代中把当前指针移到第一个元素 
	bool IsNotEnd();							//判断当前指针是否超过了最后元素 
	void MoveNext();							//向下移动当前指针 
	T    *GetCur()								//获取当前指针 
	{return &(m_HashTable[m_iCurElement].m_element); }			 
 
public: 
	static bool IsPrimeNum( int n );			//判断一个数是否是素数 
	static int GetMaxPrimeNum( int n );			//计算小于n的最大素数(用在hash2中) 
	static int GetMinPrimeNum( int n );			//计算大于n的最小素数(用在ReHash) 
 
private: 
	int Hash1( const T &e );					//一次哈希函数 
	int Hash2( const T &e );					//二次哈希函数 
	int Hash( const T &e, int i );				//哈希函数(二次哈希) 
 
private: 
	bool IsFull( int n );						//判断表是否已满 
	bool ReHash();								//重新哈希 
	bool InsertHelp( T &e, CHashTableNode * );//插入辅助函数 
 
private: 
	int m_iTableSize;							//表的长度(为素数) 
	int m_iElementNum;							//当前表中元素个数 
	int m_iPrevPrimeNum;						//小于表长度的最大素数 
	int m_iCurElement;							//当前的元素ID(用于迭代) 
	CHashTableNode  *m_HashTable;			//哈希表 
 
public: 
	friend std::ostream &operator<<( std::ostream &os, CHashTable &table ); 
 
}; 
 
///////////////////////////////////////////////////////////////////////////// 
// 
///////////////////////////////////////////////////////////////////////////// 
template  
CHashTable::CHashTable() 
{ 
	m_iTableSize	= 0; 
	m_iElementNum	= 0; 
	m_iPrevPrimeNum = 0; 
	m_HashTable		= NULL; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// 
///////////////////////////////////////////////////////////////////////////// 
template  
CHashTable::~CHashTable() 
{ 
	Free(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//判断表是否已满 
///////////////////////////////////////////////////////////////////////////// 
template  
bool CHashTable::IsFull( int n ) 
{ 
	return n >= m_iTableSize; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//判断一个数是否是素数 
///////////////////////////////////////////////////////////////////////////// 
template  
bool CHashTable::IsPrimeNum( int n ) 
{ 
	if ( n % 2 == 0 && n != 2 )			//如果N能够被2整除,N不为素数 
		return false; 
 
	for ( int i = 3; i < n; i += 2 ) 
	{ 
		if ( n % i == 0 ) 
			return false; 
	} 
 
	return true; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//计算小于n的最大素数(用在hash2中) 
///////////////////////////////////////////////////////////////////////////// 
template  
int CHashTable::GetMaxPrimeNum( int n ) 
{ 
	n -= 1; 
	if ( n % 2 == 0 ) 
		n -= 1; 
 
	for ( int i = n; i >= 1; i -= 2 ) 
	{ 
		if ( IsPrimeNum( i ) ) 
			return i; 
	} 
 
	return 1; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//计算大于n的最小素数(用在hash2中) 
///////////////////////////////////////////////////////////////////////////// 
template  
int CHashTable::GetMinPrimeNum( int n ) 
{ 
	n += 1; 
	if ( n % 2 == 0 ) 
		n += 1; 
 
	for ( int i = n; i <= 0x7fffffff; i += 2 ) 
	{ 
		if ( IsPrimeNum( i ) ) 
			return i; 
	} 
 
	return 0; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//初始化,分配数组空间,计算最小素数 
///////////////////////////////////////////////////////////////////////////// 
template  
bool CHashTable::Init( int size ) 
{ 
	if ( size < 3 ) 
		size = 11;							//如果长度过小 
	else if ( !IsPrimeNum( size ) ) 
		size = GetMinPrimeNum( size );		//如果长度不是素数 
 
	m_HashTable = new CHashTableNode[ size ]; 
	if ( m_HashTable == NULL ) 
		return false; 
	 
	m_iTableSize = size; 
	m_iPrevPrimeNum = GetMaxPrimeNum( size ); 
 
	memset( m_HashTable, 0, size * sizeof( CHashTableNode ) ); 
	return true; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//释放 
///////////////////////////////////////////////////////////////////////////// 
template  
void CHashTable::Free() 
{ 
	if ( m_HashTable != NULL ) 
		delete [] m_HashTable; 
 
	m_iTableSize	= 0; 
	m_iElementNum	= 0; 
	m_iPrevPrimeNum = 0; 
	m_HashTable		= NULL; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//清空表中所有元素 
///////////////////////////////////////////////////////////////////////////// 
template  
void CHashTable::Clear() 
{ 
	for ( Begin(); IsNotEnd(); MoveNext() ) 
	{ 
		m_HashTable[m_iCurElement].~CHashTableNode(); 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//把一个数组中的元素散列到表中 
///////////////////////////////////////////////////////////////////////////// 
template  
void CHashTable::CopyFromArray( T *pBuf, int isize ) 
{ 
	for ( int i = 0; i < isize; ++i ) 
	{ 
		Insert( pBuf[i], true ); 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//一次哈希函数 
///////////////////////////////////////////////////////////////////////////// 
template  
int CHashTable::Hash1( const T &e ) 
{ 
	return e % m_iTableSize; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//二次哈希函数 
///////////////////////////////////////////////////////////////////////////// 
template  
int CHashTable::Hash2( const T &e ) 
{ 
	return m_iPrevPrimeNum - ( e % m_iPrevPrimeNum ); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//哈希函数 
///////////////////////////////////////////////////////////////////////////// 
template  
int CHashTable::Hash( const T &e, int i ) 
{ 
	return ( Hash1( e ) + i * Hash2( e ) ) % m_iTableSize; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//插入辅助函数 
///////////////////////////////////////////////////////////////////////////// 
template  
bool CHashTable::InsertHelp( T &e, CHashTableNode *pTable ) 
{ 
	int index = 0; 
 
	for ( int i = 0; i < m_iTableSize; ++i ) 
	{ 
		index = Hash( e, i ); 
		if ( index < 0 || index >= m_iTableSize ) 
			return false; 
 
		if ( pTable[index].m_IsNotNull == false ) 
		{ 
			::new (&pTable[index]) CHashTable; 
 
			pTable[index].m_element = e; 
			pTable[index].m_IsNotNull = true; 
 
			return true; 
		} 
	} 
 
	return false; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//插入函数,isRepeat为是否允许重复元素,为false则不允许 
///////////////////////////////////////////////////////////////////////////// 
template  
bool CHashTable::Insert( T &e, bool isRepeat ) 
{ 
	if ( isRepeat == false ) 
	{ 
		if ( Find( e ) != NULL ) 
		{ 
			return false; 
		} 
	} 
 
	if ( IsFull( m_iElementNum ) ) 
	{ 
		if ( !ReHash() ) 
			return false; 
	} 
	 
	if ( InsertHelp( e, m_HashTable ) ) 
	{ 
		++m_iElementNum; 
		return true; 
	} 
	else 
		return false; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//在表中查找一个元素,如果找到返回指针否则返回NULL,注意 out为函数外存放元素空间 
//而不是表中的指针 
///////////////////////////////////////////////////////////////////////////// 
template  
T * CHashTable::Find( const T & in ) 
{ 
 
	int index = 0; 
	for ( int i = 0; i < m_iTableSize; ++i ) 
	{ 
		index = Hash( in, i ); 
		if ( m_HashTable[index].m_IsNotNull == false ) 
		{ 
			return NULL; 
		} 
		else if ( m_HashTable[index].m_IsNotNull == true && m_HashTable[index].m_element == in ) 
		{ 
			return &m_HashTable[index].m_element; 
		} 
	} 
 
	return NULL; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//当表满后,分配一个长度为原表二倍的新表,原表中的元素散列到新表中 
///////////////////////////////////////////////////////////////////////////// 
template  
bool CHashTable::ReHash() 
{ 
	int oldSize = m_iTableSize; 
	m_iTableSize = GetMinPrimeNum( m_iTableSize * 2 ); 
	m_iPrevPrimeNum = GetMaxPrimeNum( m_iTableSize ); 
	CHashTableNode *newTable = new CHashTableNode[m_iTableSize]; 
 
	if ( newTable == NULL ) 
		return false; 
	 
	memset( newTable, 0, m_iTableSize * sizeof( CHashTableNode ) );			//注意清零 
 
	for ( int i = 0; i < oldSize; ++i ) 
	{ 
		if ( m_HashTable[i].m_IsNotNull ) 
		{ 
			if ( InsertHelp( m_HashTable[i].m_element, newTable ) == false ) 
			{ 
				delete [] newTable; 
				return false; 
			} 
		} 
	} 
 
	delete [] m_HashTable; 
	m_HashTable = newTable; 
 
	return true; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//把当前所有元素拷贝到一个缓冲中 
///////////////////////////////////////////////////////////////////////////// 
template  
void CHashTable::CopyElement( T *pBuf ) 
{ 
	if ( pBuf == NULL || m_iElementNum <= 0 ) 
		return; 
 
	int j = 0; 
	for ( int i = 0; i < m_iTableSize; ++i ) 
	{ 
		if ( m_HashTable[i].m_IsNotNull ) 
		{ 
			pBuf[j++] = m_HashTable[i].m_element; 
		} 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//在迭代中把当前指针移到第一个元素 
///////////////////////////////////////////////////////////////////////////// 
template  
void CHashTable::Begin() 
{ 
	if ( m_iElementNum > 0 ) 
	{ 
		for ( int i = 0; i < m_iTableSize; ++i ) 
		{ 
			if ( m_HashTable[i].m_IsNotNull ) 
			{ 
				m_iCurElement = i; 
				return; 
			} 
		} 
	} 
	else 
	{ 
		m_iCurElement = m_iTableSize; 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//判断当前指针是否超过了最后元素 
///////////////////////////////////////////////////////////////////////////// 
template  
bool CHashTable::IsNotEnd() 
{ 
	return m_iCurElement < m_iTableSize; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//向下移动当前指针 
///////////////////////////////////////////////////////////////////////////// 
template  
void CHashTable::MoveNext() 
{ 
	for ( int i = m_iCurElement + 1; i < m_iTableSize; ++i ) 
	{ 
		if ( m_HashTable[i].m_IsNotNull ) 
		{ 
			m_iCurElement = i; 
			return; 
		} 
	} 
 
	m_iCurElement = m_iTableSize;			//如果找不到剩下的元素,则停止 
} 
 
template  
std::ostream& operator << ( std::ostream &os, CHashTable &table ) 
{ 
	for ( int i = 0; i < table.m_iTableSize; ++i ) 
	{ 
		os << i << '\t' << int(table.m_HashTable[i].m_IsNotNull) << '\t' << table.m_HashTable[i].m_element << std::endl; 
	} 
 
	return os; 
} 
 
#endif