第九章(5).哈希表

先说一句:哈希表真的很重要很重要!我寝室一哥们,在做一个操作系统(先承认,他比我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 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值