哈希表的简单实现
HashTable算法概要:
哈希表示表示集合和字典的另外一种有效的方法,通过将关键码映射到表中
某个位置来存储元素,然后根据关键码用同样的方式直接访问。
1、有限的连续地址,可以用数组来表示。
2、Hash函数采用除留余数法。
3、处理冲突的方法,用开放地址法,实现线性探测再散列法,
二次探测再散列法,随即探测再散列法,后两种方法有一些对条件的限制。
4、给定一系列的键值,分配一个数组,用哈希函数处理地址,在哈希函数中调用
冲突处理函数。
5、查找函数。
哈希表的类定义代码如下:
class HashT{ public: HashT(){} //构造函数 ~HashT(){} //析构函数 //哈希函数 void HashLFun(int key[],int keysize,int dest[],int destsize,int mod); //哈希函数,算法采用除留余数法 void HashQFun(int key[],int keysize,int dest[],int destsize,int mod); //哈希函数,算法采用除留余数法 //处理冲突函数 int HashLinearPro(int H0,int i,int mod); //线性探测再散列法 int HashQuadraticPro(int me,int H0,int mod,int flag); //二次探测再散列法 };
哈希函数根据处理冲突的方法不同,分为两个。
哈希函数(除留余数法)算法:采用线性探查再散列法
1、传入键值数组、模值和目标数组。
2、要处理一批键值,所以应该使用一个循环。
3、采用除留余数法求第一次的地址值。
4、判断是否产生了冲突,如果产生冲突,就调用冲突处理函数,寻找下一个可用的地址。
算法代码如下:
void HashT::HashLFun(int key[],int keysize,int dest[],int destsize,int mod) { int destnum; for(int i=0;i<keysize;i++) //处理这个键值序列 { destnum=key[i]%mod; int fuben=destnum; //记录当前值,用于循环 if(dest[destnum]==0) { //如果该数组值等于0,说明没有发生冲突,则将该键值插入到该数组 dest[destnum]=key[i]; } else { int count=i; //保存i的值,不改变原程序中i的值 //否则发生了冲突,调用冲突处理函数,将key值赋值给下一个合适的位置 while(dest[destnum]!=0) //如果冲突,继续循环处理 { destnum=HashLinearPro(destnum,count,mod); if(destnum!=fuben) //如果i值小于总的大小,就继续增加探测 count++; else cout<<"表中不存在可以存储该键值的位置"<<endl; } //while循环之后,说明找到了这个位置 dest[destnum]=key[i]; } } }
采用二次探查法解决冲突的算法代码如下:
void HashT::HashQFun(int key[],int keysize,int dest[],int destsize,int mod) { int destnum; for(int i=0;i<keysize;i++) //处理这个键值序列 { destnum=key[i]%mod; int fuben=destnum; if(dest[destnum]==0) { //如果该数组值等于0,说明没有发生冲突,则将该键值插入到该数组 dest[destnum]=key[i]; } else { int count=1; int flag=0; //设定一个调用次数的标记 //否则发生了冲突,调用冲突处理函数,将key值赋值给下一个合适的位置 while(dest[destnum]!=0) //如果冲突,继续循环处理 { flag++; //调用次数加1 destnum=HashQuadraticPro(count,destnum,mod,flag); //if(count<destsize) //如果i值小于总的大小,就继续增加探测 //count++; //这个地方不严谨,应该可以回到最初的位置 //else //cout<<"表中不存在可以存储该键值的位置"<<endl; if(flag%2==0){ //如果循环若干次后又回到原来的位置,说明没有可插入的位置 count++; } else if(destnum==fuben) { cout<<key[i]<<"在表中没有合适的插入位置"<<endl; } else ; //否则什么都不做 } //while循环之后,说明找到了这个位置 dest[destnum]=key[i]; } } }
哈希函数中很重要的一个部分就是冲突处理函数,这里写出最常用的两个处理方法,线性探查再散列法和二次探查再散列法:
算法的代码如下:
int HashT::HashLinearPro(int H0,int i,int mod) { int destnum; destnum=(H0+i)%mod; return destnum; }
int HashT::HashQuadraticPro(int me,int H0,int mod,int flag) { int destnum; if(flag%2==1) { destnum=(H0+me*me)%mod; //这里的i应该为me } else { destnum=(H0-me*me)%mod; } return destnum; }
二次探查再散列法,需要设置征服号,这里设置一个flag值,进行判断。