您的位置:首页 > 其它

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

2013-11-25 18:21 281 查看
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
== -1 ) {
hashtable
=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

9f8f
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐