哈希表查找(散列表查找)c++实现HashMap
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
哈希表查找(散列表查找)c++实现HashMap
算法思想:
哈希表
什么是哈希表
在前⾯讨论的各种结构(线性表、树等)中,记录在结构中的相对位置是随机的,和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进⾏⼀系列和关键字的⽐较。
这⼀类查找⽅法建⽴在“⽐较”的基础上。
在顺序查找时,⽐较的结果为“="与“!=”两种可能;
在折半查找、⼆叉排序树查找和B树查找时,⽐较的结果为“<"、"="和“>"3种可能。
查找的效率依赖于查找过程中所进⾏的⽐较次数。
理想的情况是希望不经过任何⽐较,⼀次存取便能得到所查记录,那就必须在记录的存储位置和它的关键字之间建⽴⼀个确定的对应关系f,使每个关键字和结构中⼀个惟⼀的存储位置相对应。
因⽽在查找时,只要根据这个对应关系f找到给定值K的像f(K)。
若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上,由此,不需要进⾏⽐较便可直接取得所查记录。
在此,我们称这个对应关系f为哈希( Hash)函数,按这个思想建⽴的表为哈希表。
哈希函数的构造⽅法
哈希函数是从关键字集合到地址集合的映像。
通常,关键字集合⽐较⼤,它的元素包括所有可能的关键字,⽽地址集合的元素仅为哈希表中的地址值。
哈希函数其实是⼀个压缩映像,那么这种情况就不可避免的产⽣冲突,那么在建造哈希表时不仅要设定⼀个好的哈希函数,还要设定⼀种处理冲突的⽅法。
(设定的哈希函数H(key)和处理冲突的⽅法将⼀组关键字映像到⼀个有限的连续的地址集上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表就是哈希表,映像的过程为哈希造表或散列,所得的存储位置称哈希地址或散列地址)
(1)直接定址法
取关键字或关键字的某个线性函数值为哈希地址。
即H(key)=key 或 H(key)=a*key+b (a,b为常数)。
举例1:统计1-100岁的⼈⼝,其中年龄作为关键字,哈希函数取关键字⾃⾝。
查找年龄25岁的⼈⼝有多少,则直接查表中第25项。
地址 01 02 03 ... 25 26 27 (100)
年龄 1 2 3 ... 25 26 27 ... ....
⼈数 3000 2000 (1050)
...
举例2:统计解放以后出⽣⼈⼝,其中年份作为关键字,哈希函数取关键字⾃⾝加⼀个常数H(key)=key+(-1948).查找1970年出⽣的⼈数,则直接查(1970-1948)=22项即可。
地址 01 02 03 ... 22 23 24 ...
年份 1949 1950 1951 (1970)
⼈数 (15000)
...
(2)数字分析法
若关键字是以r为基的数(如:以10为基的⼗进制数),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若⼲数位组成哈希地址。
举例:有80个记录,其关键字为8位⼗进制数,假设哈希表长,则可取两位⼗进制数组成哈希地址,为了尽量避免冲突,可先分析关键字。
8 1 3 4 6 5 3 2
8 1 3 7 2 2 4 2
8 1 3 8 7 4 2 2
8 1 3 0 1 3 6 7
8 1 3 2 2 8 1 7
8 1 3 3 8 9 6 7
8 1 3 5 4 1 5 7
8 1 3 6 8 5 3 7
8 1 4 1 9 3 5 5 ...........
经分析,发现第⼀位、第⼆位都是8,1,第三位只可能取3或4,第⼋位只可能取2,5或7,所以这四位不可取,那么对于第四、五、六、七位可看成是随机的,因此,可取其中任意两位,或取其中两位与另外两位的叠加求和舍去进位作为哈希地址。
(3)平⽅取中法
取关键字平⽅后的中间⼏位为哈希地址。
(较常⽤的⼀种)
举例:为BASIC源程序中的标识符键⼀个哈希表(假设BASIC语⾔允许的标识符为⼀个字母或者⼀个字母和⼀个数字两种情况,在计算机内可⽤两位⼋进制数表⽰字母和数字),假设表长为512=,则可取关键字平⽅后的中间9位⼆进制数为哈希地址。
(每3个⼆进制位可表⽰1位⼋进制位,即3个⼋进制位为9个⼆进制位)
A :01 (A的ASCII码值为65,65的⼋进制为101,取后两位表⽰关键字)
B:02 (B的ASCII码值为66,66的⼋进制为102,取后两位表⽰关键字)
...
Z:32(Z的ASCII码值为90,90的⼋进制为132,取后两位表⽰关键字)
...
0:60(0的ASCII码值为48,48的⼋进制为60,取后两位表⽰关键字)
...
9:71(9的ASCII码值为57,57的⼋进制为71,取后两位表⽰关键字)
记录关键字关键字的平⽅哈希地址(~)
A 0100 0010000 010
I 1100 1210000 210
P1 2061 4310541 310
Q2 2162 4741304 741
(4)折叠法
将关键字分割成位数相同的⼏部分(最后⼀部分的位数可不同),然后取这⼏部分的叠加和(舍去进位)作为哈希地址。
适⽤于关键字位数⽐较多,且关键字中每⼀位上数字分布⼤致均匀时。
举例:根据国际标准图书编号(ISBN)建⽴⼀个哈希表。
如⼀个国际标准图书编号 0-442-20586-4的哈希地址为:
5864 5864
4220 0224
+ 04 + 04
10088 6092
移位叠加间接叠加
H(key)=0088(将分割后的每⼀部分的最低位对齐) H(key)=6092(从⼀端向另⼀端沿分割界来回叠加)
(5)除留余数法
取关键字被某个不⼤于哈希表表长m的数p除后所得余数为哈希地址(p为素数)
H(key)=key MOD p,p<=m (最简单,最常⽤)p的选取很重要
⼀般情况,p可以选取为质数或者不包含⼩于20的质因数的合数(合数指⾃然数中除了能被1和本⾝整除外,还能被其他数(0除外)整除的数)。
(6)随机数法
选择⼀个随机函数,取关键字的随机函数值为它的哈希地址。
即H(key)=random(key),其中random为随机函数。
适⽤于关键字长度不等时。
总结:实际⼯作中根据情况不同选⽤的哈希函数不同,通常,考虑因素如下:
(1)计算哈希函数所需时间(包括硬件指令的因素)
(2)关键字的长度
(3)哈希表的⼤⼩
(4)关键字的分布情况
(5)记录的查找频率
常⽤冲突处理⽅法:
1.开放定址法:
⽅法: fi(key)=(f(key)+di) mod m,(di=1,2,3,4...,m−1)fi(key)=(f(key)+di) mod m,(di=1,2,3,4...,m−1)
线性探测:只要⼀旦发现冲突,就寻找下⼀个空的散列地址
⼆次探测:di=12,−12,22,−22,...,q2,−q2di=12,−12,22,−22,...,q2,−q2,⽬的是不让关键词集中在某块区域,产⽣堆积
随机探测:didi是⼀个随机数,但查询时需要设置和插⼊时相同的随机种⼦
2.再散列函数法:(再哈希法)
⽅法:fi(key)=RHi(key) (i=1,2,...k)fi(key)=RHi(key) (i=1,2,...k)
遇到冲突就重新采⽤⼀个散列函数计算新的存储位置,可以使关键字不产⽣聚集
3.链地址法(拉链)
⽅法:将所有关键字的同义词记录在⼀个单链表中,在散列表中只存储所有同义词表的头指针
4.建⽴⼀个公共溢出区法
⽅法:为所有冲突的关键字开辟⼀个公共的溢出区(表)来存放
适⽤于相对于基本表来说冲突数据很少的情况
实现⽅法:(哈希表采⽤数组存储,哈希函数构造和处理冲突的⽅法是除留余数法+开放定址法)
1/****
2* Hash Table
3*
4****/
5
6
7//#include "Global.h"
8 #include"stdafx.h"
9 #include <iostream>
10using namespace std;
11
12// HashTable Data Structure Definition
13// array hashtable
14#define tablesize 10
15 typedef int HashTable[tablesize];
16//hash function initialization way
17void Initial_HashTable(HashTable &ht)
18 {
19for (int i = 0; i < tablesize; i++)
20 ht[i] = 0;
21 }
22//search hashtable function
23int Search_HashTable(HashTable &ht,int key)
24 {
25int address = key%tablesize;
26int compare = 0;
27while (compare < tablesize&&ht[address] != key&&ht[address] != 0)
28 {
29 compare++;
30 address = (address+1)%tablesize;
31 }
32if (compare == 10 || ht[address] == 0)
33 cout << "can not find elem" << endl;
34return address;
35 }
36//insert hashtable function
37int Insert_HashTable(HashTable &ht,int key)
38 {
39int res = Search_HashTable(ht,key);
40if (ht[res] == 0)
41 {
42 ht[res] = key;
43return1;
44 }
45return0;
46 }
47//test function
48int main()
49 {
50int data[8] = { 25,36,39,47,20,58,16,35 };
51 HashTable ht;
52
53//initialization.
54 Initial_HashTable(ht);
55
56//insert datas.
57for (int i = 0; i < 8; i++)
58 {
59 cout << Insert_HashTable(ht, data[i]) << "";
60 }
61 cout << endl;
62
63//search.
64 cout << "25 : " << Search_HashTable(ht, 25) << endl;
65 cout << "35 : " << Search_HashTable(ht, 35) << endl;
66 cout << "145 : " << Search_HashTable(ht, 145) << endl;
67 system("pause");
68return0;
69 }。