构建hash表和两种处理冲突方法

hash表定义:hashing定义了一种将字符组成的字符串转换为固定长度(一般是更短长度)的数值或索引值的方法,称为散列法,也叫哈希法。由于通过更短的哈希值比用原始值进行数据库搜索更快,这种方法一般用来在数据库中建立索引并进行搜索,同时还用在各种解密算法中。

设所有可能出现的关键字集合记为u(简称全集)。实际发生(即实际存储)的关键字集合记为k(|k|比|u|小得多)。|k|是集合k中元素的个数。

散列方法是使用函数hash将u映射到表t[0..m-1]的下标上(m=o(|u|))。这样以u中关键字为自变量,以h为函数的运算结果就是相应结点的存储地址。从而达到在o(1)时间内就可完成查找。

其中:

① hash:u→{0,1,2,…,m-1} ,通常称h为散列函数(hash function)。散列函数h的作用是压缩待处理的下标范围,使待处理的|u|个值减少到m个值,从而降低空间开销。

② t为散列表(hash table)。

③ hash(ki)(ki∈u)是关键字为ki结点存储地址(亦称散列值或散列地址)。

④ 将结点按其关键字的散列地址存储到散列表中的过程称为散列(hashing).

比如:有一组数据包括用户名字、电话、住址等,为了快速的检索,我们可以利用名字作为关键码,hash规则就是把名字中每一个字的拼音的第一个字母拿出来,把该字母在26个字母中的顺序值取出来加在一块作为该记录的地址。比如张三,就是z+s=26+19=45。就是把张三存在地址为45处。

但是这样存在一个问题,比如假如有个用户名字叫做:周四,那么计算它的地址时也是z+s=45,这样它与张三就有相同的地址,这就是冲突,也叫作碰撞(hash碰撞)。

冲突:两个不同的关键字,由于散列函数值相同,因而被映射到同一表位置上。该现象称为冲突(collision)或碰撞。发生冲突的两个关键字称为该散列函数的同义词(synonym)。

冲突基本上不可避免的,除非数据很少,我们只能采取措施尽量避免冲突,或者寻找解决冲突的办法。影响冲突的因素

冲突的频繁程度除了与h相关外,还与表的填满程度相关。

设m和n分别表示表长和表中填入的结点数,则将α=n/m定义为散列表的装填因子(load factor)。α越大,表越满,冲突的机会也越大。通常取α≤1。

 

简单实现程序如下:

其中hash_i()为hash函数,提供两种处理冲突的方法线性探测法和双重散列法。用的测试数据为100000以内的不重复随机数,

装填因子α=9000/11000,也就是9000个数放到11000个盒子里;

测试结果:数据较少时,双重散列法偏优,α=9000/11000时两种处理冲突方法得到的平均查找长度基本相当。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <hash_map.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
 
using namespace std;
 
#define ARRAY_SIZE 9000
 
#define HASH_LENGTH 11000
 
int hash_i(int i) {
    return (3*i)%HASH_LENGTH;
}
 
//template<class T>
 
 
int main(int argc, char* argv[]) {
 
     
    //int ai[]={22,41,53,46,30,13,01,67,32};
     
    //constractor the test random array ai[]
    srand((int)time(NULL));
    int ai[ARRAY_SIZE]={0};
    int i=0;
    int *hashtable = (int*)malloc(sizeof(int)*(HASH_LENGTH+1));
     
    for(i = 0; i < ARRAY_SIZE; i++) {
        int t = rand()%100000;
        int k;
        for(k = 0; k < ARRAY_SIZE; k++) {
            if(t == ai[k])
                break;
        }
         
        if(k != ARRAY_SIZE) continue;
         
        ai[i]=t;
    }
     
    //initial hashtable[]  
    for(i=0; i< HASH_LENGTH; i++) {
        hashtable[i]=-1;   
    }
     
    int k=1;
    int m = 1;
    for(i = 0;i < ARRAY_SIZE ;i++ ) {
        int n;
        printf("hash value%d=%d\n",i,n=hash_i(ai[i])); 
        if( hashtable[n] == -1 ) {
            hashtable[n]=ai[i];
        }
        else {
            int tmp1,tmp2;
#ifndef DOUBLE_HASHING
            //线性探测法
            //探测序列从不成功hash值后面逐个加1比较,即n,n+1,...HASH_LENGTH-1,0,1,..n-1
            do {
                tmp2 = (n+m)%HASH_LENGTH;
                if(hashtable[tmp2] == -1) {
                    hashtable[tmp2] = ai[i];
                    printf("tmp2=%d,try again total %d times\n",tmp2,k++);
                    break;
                }
            }while( tmp2 != n ,m++);
             
#else
            //双重散列法(double hashing)
            //h(key)为hash(key)
            //h1=(h(key)+i*i)%m
            //hi=(h(key)+i*h1(key))%m
            //m为hash表长,hi为第i次的散列值
            for(m = 0; m < HASH_LENGTH ;m++) {
                 
                tmp1 = (n+m*m)%HASH_LENGTH;
                tmp2 = (n+m*tmp1)%HASH_LENGTH;
                if(hashtable[tmp2] == -1) {
                    hashtable[tmp2]=ai[i];
                    printf("tmp2=%d,try again total %d times\n",tmp2,k++);
                    break;
                }  
            }
             
#endif
            if(m == HASH_LENGTH)
                printf("table is full!\n");
        }  
    }
     
    for(i = 0; i < HASH_LENGTH ;i++)
        printf("hashtable[%d]=%d\n",i,hashtable[i]);
     
    printf("不成功的asl=%.2f\n",(k-1)*1.0/ARRAY_SIZE);
     
    if(hashtable) {
        free(hashtable);
        hashtable = NULL;
    }  
 
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值