先说一句:哈希表真的很重要很重要!我寝室一哥们,在做一个操作系统(先承认,他比我NB多了!不过他的NB也是用数不清的付出换来的!相信大家有一天也会变得很NB的!),他被文件系统里面的哈希表问题缠绕了将近一个月!就这一点就足见哈希表的重要性了!
哈希表的构造方法和处理冲突方法均有多种,所以你懂的!练练其中一两中组合,然后了解各种组合的优劣处,在实际运用的时候再灵活选择合适的组合吧!
#include < stdio.h >
#include < stdlib.h >#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status ;//-----对数值型关键字的比较--------//
#define EQ( a , b ) ( ( a ) == ( b ) )
#define LT( a , b ) ( ( a ) < ( b ) )
#define LQ( a , b ) ( ( a ) <= ( b ) )typedef int KeyType ; //定义关键字的类型
typedef struct {
KeyType key ;
} SElemType ;//-----------开放定址哈希表的存储结构----------------//
typedef struct {
SElemType *elem ; //数据元素存储基址
int count ; //当前数据元素个数
int sizeindex ; //hashsize[sizeindex]为当前容量
} HashTable ;#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1
#define NULLKEY -1//int hashsize[ ] = { 11 , 19 , 29 , 37 } ; //开放定址哈希表容量递增表,一个合适的素数序列
//int hashlen = 0 ; //哈希表表长,全局变量int hashsize[ 4 ] ; //Take care! 头文件中只能声明,不能定义!
int hashlen ;Status InitHash( HashTable *H ) ;
unsigned int Hash( KeyType K ) ;
void collision( int *p , int d ) ;
Status SearchHash( HashTable H , KeyType K , int *p , int *c ) ;
Status InsertHash( HashTable *H , SElemType e ) ;
void RecreateHashTable( HashTable *H ) ;
Status TraverseHash( HashTable H , void ( *Visit )( SElemType e ) ) ;
void visit( SElemType e ) ;//------------------Basic Function----------------------//
hashsize[ ] = { 11 , 19 , 29 , 37 } ;
hashlen = 0 ;Status InitHash( HashTable *H )
{
int i ;( *H ).count = 0 ;
( *H ).sizeindex = 0 ;
hashlen = hashsize[ 0 ] ; // hashsize[ ( *H ).sizeindex ] is the same!( *H ).elem = ( SElemType * )malloc( sizeof( SElemType ) ) ;
if( !( *H ).elem )
{
printf( "There isn't enough palce for it!" ) ;
exit( OVERFLOW ) ;
}
for( i = 0 ; i < hashlen ; ++ i )
( *H ).elem[ i ].key = NULLKEY ;return OK ;
}Status DestroyHash( HashTable *H )
{
free( ( *H ).elem ) ;
( *H ).elem = NULL ;
( *H ).count = 0 ;
( *H ).sizeindex = 0 ;return OK ;
}
unsigned int Hash( KeyType K ) //哈希函数
{
return K%hashlen ; //除留余数法
}void collision( int *p , int d ) //处理冲突函数
{
( *p ) = ( ( *p ) + d ) % hashlen ; //开放定址法,采用线性探测在散列
}Status SearchHash( HashTable H , KeyType K , int *p , int *c )
{ //在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p只是待查数据元素在表中的位置,并返回SUCCESS;
//否则以p只是插入的位置,并返回UNSUCCESS。以c统计冲突次数,其初值置零,供建表插入时参考。( *p ) = Hash( K ) ; //求得哈希地址
while( H.elem[ *p ].key != NULLKEY && !EQ( K , H.elem[ *p ].key ) ) //该位置有记录,并且关键字不想等
{
++( *c ) ;
if( *c < hashlen )
collision( p , *c ) ; //求得下一探查地址p
else
break ;
}if( EQ( K , H.elem[ *p ].key ) )
return SUCCESS ;
else
return UNSUCCESS ;
}Status InsertHash( HashTable *H , SElemType e )
{ //查找不成功时插入元素e到开放定址哈希表H中,并返回OK;若冲突次数过大,则需重建哈希表
int p , c = 0 ;if( SearchHash( *H , e.key , &p , &c ) )
return DUPLICATE ;
else
{
if( c < hashsize[ ( *H ).sizeindex ]/2 )//冲突次数c未达到上限( c的阈值可调 )
{
( *H ).elem[ p ] = e ; //插入e
++( *H ).count ;
return OK ;
}
else
{
RecreateHashTable( H ) ; //重建哈希表
return UNSUCCESS ;
}
}
}void RecreateHashTable( HashTable *H )
{
int i , count = ( *H ).count ;SElemType *p , *elem = ( SElemType * )malloc( count * sizeof( SElemType ) ) ;
p = elem ;
for( i = 0 ; i < hashlen ; ++ i ) //元素个数是count,但这里却是hashlen,因为元素不能全部填满哈希表,而元素随机分布在哈希表的各个地方.
{
if( ( *H ).elem[ i ].key != NULLKEY ) //保存原数据
*p++ = *( H->elem + i ) ; // (*H).elem[i] is the same!
}( *H ).count = 0 ;
( *H ).sizeindex++ ;
hashlen = hashsize[ ( *H ).sizeindex ] ; //hashlen为当前容量
p = ( SElemType * )realloc( ( *H ).elem , hashlen*sizeof( SElemType ) ) ;
if( !p )
exit( OVERFLOW ) ;
( *H ).elem = p ;
for( i = 0 ; i < hashlen ; ++ i )
( *H ).elem[ i ].key = NULLKEY ;for( p = elem ; p < elem + count ; ++p ) //将原有的数据按照新的表长插入到新建哈希表中.
InsertHash( H , *p ) ;
}Status TraverseHash( HashTable H , void ( *Visit )( SElemType e ) )
{
int i ;for( i = 0 ; i < hashlen ; ++ i )
{
if( H.elem[ i ].key != NULLKEY )
Visit( H.elem[ i ] ) ;
}return OK ;
}void visit( SElemType e )
{
printf( "%5d" , e.key ) ;
}
int main( )
{
int i , p , c = 0 ;
HashTable H ;
SElemType e[ ] = { 4 , 23 , 01 , 18 , 20 } ;
// SElemType e[ ] = { 4 , 63 , 01 , 18 , 20 , 42 , 21 } ;InitHash( &H ) ;
for( i = 0 ; i < 5 ; ++ i )
InsertHash( &H , e[ i ] ) ;SearchHash( H , 1 , &p , &c ) ; //p所查找元素的位置,c为冲突次数!
printf( "%5d%5d\n" , p , c ) ;TraverseHash( H , visit ) ;
printf( "\n" ) ;
return 0 ;
}