目录
一,哈希表的定义
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
——百度百科
哈希表能够根据关键字快速定位到具体的值,通常用来提高算法效率。
构造函数:
unordered_map ( size_type n = N,const hasher& hf = hasher(),const key_equal& eql = key_equal(),const allocator_type& alloc = allocator_type() );
哈希表的构造方法:
- 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。(常用)
- 数字分析法:选择不容易发生冲突的部分进行哈希表构造。(如:学号后半部分)
- 平方取中法:当无法确定关键字里的哪里分布相对均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为散列地址。(这是由于平方之后中间几个值和关键字的每一位都相关,所以不同关键字更容易产生不同的地址)
- 取随机数法:使用一个随机函数,取关键字的随机值作为散列地址。(常用于关键字长度不同的场景)
- 除留取余法:取关键字被某个不大于散列表表长 n 的数 m 除后所得的余数 p 为散列地址。这种方式也可以在用过其他方法后再使用。(对 m 的选择很重要,一般取素数或者直接用 n。)
二,哈希表的常用函数
hash.begin():指向容器内第一个元素的迭代器。
hash.end():指向容器内最后一个元素的后一个位置的迭代器。
hash.find():可以通过key查找一个元素,返回的是迭代器类型。
hash.bucket():以key值寻找元素在容器中的位置。
hash.clear():删除容器内所有元素。
hash.count():某个key值对应的map(value)值的数量。(注:哈希表是不允许存在重复元素的,所以返回的值总是0或是1)
hash.empty():判断哈希表是否为空,如为空则为真,返回的是bool值。
hash.erase():可以删除哈希表中指定位置的元素。
hash.insert():能够向哈希表的指定位置插入元素。
hash.size():返回的是哈希表的元素个数。
hash.swap():交换两个哈希表的内容,其类型必须一致,但大小可以不同。
三,哈希表的适用题目
1.判断数组内是否有重复数字出现
2.求数组交集
3.两数之和
4....
四,哈希冲突
哈希表可能产生冲突的原因:有时不同的 Key关键字通过哈希函数可能会得到相同的地址,在操作时可能会对数据造成覆盖、丢失。之所以产生冲突是由于哈希函数有时对不同的 Key 计算之后获得了相同的地址。
五,哈希冲突的解决方法
常用的解决哈希冲突的方法有:
- 开放定址法:在根据关键字查找哈希之后,如果发现这个地址已经有值了,就不能放在这个地址,否则会覆盖掉之前的映射。可以对计算出来的地址进行一个探测再哈希,比如往后移动一个地址,如果该地址空着就可以使用;如果超过容器最大长度,则可以对总长度取余。这里移动的地址是产生冲突时的增列序量。
- 再散列函数法:如果产生哈希冲突后,可以使用关键字的其他部分继续计算,如果还是有冲突,则继续使用其他部分再计算地址。改方法的缺点则是效率较低,时间较长。
- 链地址法:对关键字重复的哈希地址,来做一个链表。在很多高级语言的实现当中,都是使用这种方式处理冲突。
- 建立一个公共溢出区:是建立一个公共溢出区,当产生哈希冲突时,把新的地址放在公共溢出区里。
个人整理学习用,欢迎讨论与修正。