Hash表算法

Hash表建立了key与value的关系,所以我们可以通过hash函数对value计算出key,从而可以O(1)的时间内,查找到value。

Hash表主要的问题在于发生了碰撞,即两个value的key相同怎么办?

1、避免碰撞

  • 我们可以构造好的hash函数,使key值均匀分布,这样可以使碰撞的概率很小;
  • 构造多个hash函数;
  • 构造多个表,每个表用不同的hash函数;
  • 计算出value的若干验证码,key和验证码一起比较。

2、保存碰撞值

碰撞是不可避免的,我们可以有效的将碰撞的值保存下来。

  • 通过链表,保存在一个key中;
  • 再对key进行计算,找到新的未被占用的key,保存这个value。
我们要相信,Hash表在好的hash算法和碰撞处理方法下,还是挺好用的,所以放心大胆的用吧。
下面给出一段实例代码:

#include <stdio.h>  
#include <ctype.h>    
//crytTable[]里面保存的是HashString函数里面将会用到的一些数据,在prepareCryptTable  
//函数里面初始化  
unsigned long cryptTable[0x500];  
  
//以下的函数生成一个长度为0x500(合10进制数:1280)的cryptTable[0x500]  
void prepareCryptTable()  
{   
    unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;  
  
    for( index1 = 0; index1 < 0x100; index1++ )  
    {   
        for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )  
        {   
            unsigned long temp1, temp2;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp1 = (seed & 0xFFFF) << 0x10;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp2 = (seed & 0xFFFF);  
  
            cryptTable[index2] = ( temp1 | temp2 );   
       }   
   }   
}  
  
//以下函数计算lpszFileName 字符串的hash值,其中dwHashType 为hash的类型,  
//在下面GetHashTablePos函数里面调用本函数,其可以取的值为0、1、2;该函数  
//返回lpszFileName 字符串的hash值;  
unsigned long HashString( char *lpszFileName, unsigned long dwHashType )  
{   
    unsigned char *key  = (unsigned char *)lpszFileName;  
    unsigned long seed1 = 0x7FED7FED;  
    unsigned long seed2 = 0xEEEEEEEE;  
    int ch;  
  
    while( *key != 0 )  
    {   
        ch = toupper(*key++);  
  
        seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);  
        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;   
    }  
    return seed1;   
}  
  
//在main中测试argv[1]的三个hash值:  
//./hash  "arr/units.dat"  
//./hash  "unit/neutral/acritter.grp"  
int main( int argc, char **argv )  
{  
    unsigned long ulHashValue;  
    int i = 0;  
  
    if ( argc != 2 )  
    {  
        printf("please input two arguments/n");  
        return -1;  
    }  
  
     /*初始化数组:crytTable[0x500]*/  
     prepareCryptTable();  
  
     /*打印数组crytTable[0x500]里面的值*/  
     for ( ; i < 0x500; i++ )  
     {  
         if ( i % 10 == 0 )  
         {  
             printf("/n");  
         }  
  
         printf("%-12X", cryptTable[i] );  
     }  
  
     ulHashValue = HashString( argv[1], 0 );  
     printf("/n----%X ----/n", ulHashValue );  
  
     ulHashValue = HashString( argv[1], 1 );  
     printf("----%X ----/n", ulHashValue );  
  
     ulHashValue = HashString( argv[1], 2 );  
     printf("----%X ----/n", ulHashValue );  
  
     return 0;  
}  


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值