前言
系列文章传送门:.
【数据结构系列 1】数组入门详解
【数据结构系列 2】栈入门详解
【数据结构系列 3】队列入门详解
【数据结构系列 4】链表入门详解
【数据结构系列 5】哈希表入门详解
【数据结构系列 6】树入门详解
一、哈希表简介
1、哈希表定义
散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。
数据存储地址:index=fun(key)
看完上面的介绍是不是依然感到很迷惑呢?
让我来换一个通俗易懂的说法吧,假如现在我们有一个数组int arr[5],有两个数据{2,5},我们要在数组里面存储这两个数的话可以直接按顺序在arr[0]和arr[1]存储2,5;也可以选择规定一个函数y=x%5,x代表我们要存储的数据,y代表存储在数组中的索引,这样的话数字2的存储位置就变成了arr[2],数字5存储的位置就变成了arr[0]。
对比前面的顺序存储,后面这种散列存储的方式有什么优点呢?
那就是查询速度极快,比如我们需要查询数组中是否有数字2,正常的做法就是从头遍历数组,需要比对三个数;当采用哈希函数存储的时候我们可以通过计算数字存储地址直接找到对应的位置,一次就能判断数组中是否有某个数以及数字的地址,这个特点在数据多的时候更为明显。这就是哈希表的最大特点:非常快速的查询。
2、哈希函数
定义
在上面的例子中我们已经知道,像y=x%5这样的将数据映射到地址的函数我们称之为哈希函数。
哈希函数的构造
- 直接定址法
取关键字或关键字的某个线性函数值为散列地址。
即 H(key) = key 或 H(key) = a*key + b,其中a和b为常数。
- 除留余数法
取关键字被某个不大于散列表长度 m 的数 p 求余,得到的作为散列地址。
即 H(key) = key % p, p < m。
比如
- 数字分析法
当关键字的位数大于地址的位数,对关键字的各位分布进行分析,选出分布均匀的任意几位作为散列地址。
仅适用于所有关键字都已知的情况下,根据实际应用确定要选取的部分,尽量避免发生冲突。
比如
- 平方取中法
先计算出关键字值的平方,然后取平方值中间几位作为散列地址。
随机分布的关键字,得到的散列地址也是随机分布的。
比如
- 折叠法(叠加法)
将关键字分为位数相同的几部分,然后取这几部分的叠加和(舍去进位)作为散列地址。
用于关键字位数较多,并且关键字中每一位上数字分布大致均匀。
- 随机数法
选择一个随机函数,把关键字的随机函数值作为它的哈希值。
通常当关键字的长度不等时用这种方法。
3、哈希冲突
细心的兄弟应该已经想到一个问题了,那就是会不会有多个key映射的地址是一样的呢?
答案是会的,并且会引发哈希冲突,如果不采取办法解决那么这个地址就只能是被最新存储的数据覆盖了。正是因为有这种情况的出现,就有了哈希冲突的解决方法。
开放地址法
-
用开放定址法解决冲突的做法是: 当冲突发生时,使用某种探测技术在散列表中形成一个探测序列。
-
沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。
-
查找时探测到开放的地址则表明表中无待查的关键字,即查找失败。
按照形成探查序列的方法不同,可将开放定址法区分为线性探查法、二次探查法、双重散列法等。
链地址法
-
链地址法的做法是:将所有关键字对应的存储空间相同的数据结点链接在同一个单链表中。
-
若选定的散列表长度为 m,则可将散列表定义为一个由 m 个头指针组成的指针数组 T[0…m-1] 。
-
凡是散列地址为 i 的结点,均插入到以 T[i] 为头指针的单链表中。
-
T 中各分量的初值均应为空指针。
二、哈希表的应用
1、c++库hash_map的使用
了解了哈希表的基础知识以后不免想要练习一下,在实际工作中如果能够有一个现成的封装工具那就再好不过了。这里用到了c++ STL库中的hash_map简单的做了一个数据的插入和删除,hash_map和map的使用极其相似,但是在新的c++标准里面已经不建议使用该类了,仅作为简单了解即可。
#include <hash_map>
#include <iostream>
using namespace std;
typedef pair <int, int> int_pair;
int main()
{
hash_map <int, int> my_map;
my_map.insert(int_pair(1, 10));
my_map.insert(int_pair(2, 20));
my_map.insert(int_pair(3, 30));
auto it = my_map.find(2);
cout << "The element of hash_map my_map with a key of 2 is: "
<< it->second << "." << endl;
// If no match is found for the key, end( ) is returned
it = my_map.find(4);
if (it == my_map.end())
cout << "The hash_map my_map doesn't have an element "
<< "with a key of 4." << endl;
else
cout << "The element of hash_map my_map with a key of 4 is: "
<< it->second << "." << endl;
system("pause");
return 0;
}
点赞的小伙伴免费赠送一次我老婆的拔罐哦!
-----------------------------------------------------------------------------------------------------------------------------------------------------
❤️❤️❤️ 如果本文对你有所帮助,请不要忘了点赞、关注、收藏一键三连哦!!! ❤️❤️❤️
-----------------------------------------------------------------------------------------------------------------------------------------------------