一、哈希表
1、名称
又称 散列表、 Hash table。哈希表就是根据关键吗的值而直接进校访问的数据结构
其实数组就是一张哈希表,数组的索引为key,数组的元素为value。
数据规模是dataSize, 哈希表的大小为tableSize
哈希表 是一种数据结构,它是使用哈希函数,也就是散列函数组织数据,将健 映射到特定的桶,支持快速插入和搜索
散列函数 取决于 健值的范围 和 桶的数量
哈希函数的设计思想是尽可能将键分配到桶中,理想情况下,完美的哈希函数将是键和桶之间的一对一映射。然而,在大多数情况下,哈希函数并不完美,它需要在桶的数量和桶的容量之间进行权衡。
2、哈希表能解决什么问题呢?
- 一般是用来快速判断一个元素是否出现集合里。
3、哈希碰撞
哈希碰撞有两种解决办法:
1、拉链法:拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。
2、线性探测法:使用线性探测法,一定要保证tableSize大于dataSize。我们需要依靠哈希表中的空位来解决碰撞问题。
以 将学生姓名映射到哈希表 为例:
hash function 哈希函数:把学生姓名直接映射到哈希表上的索引,然后就可以通过查询索引
表快速知道某位同学是否在这所学校里。
hash code: 是通过特定编码方式,可以将其他数据格式转化为不同的数值。这样就把学生名字映射为哈希表上的索引数字了。
哈希碰撞:小李和小王都映射到同一个索引表的位置上
拉链法:发生冲突的元素都被存储在链表中。即将小李和小王都存储在同一个索引表上。
线性探测法:冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。
3、哈希表常见的三种结构:
- 数组
- set(集合)
- map(映射)
总结一:六种容器
在C++语言中,set 分别提供了三种数据结构:
set
multiset
unordered_set在C++语言中,map 分别提供了三种数据结构:
map
multimap
unordered_map
总结二:底层实现
底层实现为哈希表:unordered_set、unordered_map
底层实现为红黑树:set,multiset,map,multimap 注意:只能删除和增加红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。
总结三:使用规律
当我们要使用集合来解决哈希问题的时候,
1、优先使用unordered_set,因为它的查询和增删效率是最优的,
2、如果需要集合是有序且没有重复的,那么就用set,
3、如果要求不仅有序还要有重复数据的话,那么就用multiset。虽然set、multiset 的底层实现是红黑树,不是哈希表,但是set、multiset 依然使用哈希函数来做映射,只不过底层的符号表使用了红黑树来存储数据,所以使用这些数据结构来解决映射问题的方法,我们依然称之为哈希法。map也是一样的道理。
总结四:数组&哈希
数组可以当做哈希表来用: 但是当哈希值比较少,特别分散,跨度非常大时,使用数组就造成空间的极大浪费
总结五:有序&无序
对哈希表的无序的理解:
1、什么是无序,什么是有序?
所谓有序和无序,是是否按关键字的输入顺序保存元素。
无序指的是不按你给的信息去排序,哈希表有一个哈希函数,通过哈希函数可以把 key 转为 index ,所以哈希表的底层其实是一个 array + list 链表。array 的 index 就是 key 经过哈希之后转换成的,然后再把 key 和 value 放进链表里。因此称之为无序。
无序的是unordered_map、 unordered_set。 采用迭代器遍历出来的元素是无序的, 这是因此底层实现数据结构为哈希表。
有序是指:使用迭代器遍历的时候,按照输入的顺序
比如:
unordered_set set1;
set set2;
在set1和 set2 中都输入 a b c则有: