目录
哈希概念
哈希冲突
如何解决哈希冲突?
闭散列
开散列/哈希桶(链地址法)
负载因子
哈希概念
哈希:
- 一种高效用来搜索的数据结构。
- 哈希利用某一种函数使元素的存储位置与它的关键码之间建立一个映射关系,方便查找元素。
- 哈希中建立这种映射关系的函数叫做哈希函数,也叫做散列函数。
- 散列函数就是计算元素在哈希中所存储的位置,通过该函数来存放元素。
小例子:手机通序录对联系人的分配,通讯录根据人名的首字母对联系人进行分类存储。这种就是哈希存储。通序录通过名字的首字母与联系人之间产生一种映射关系
哈希冲突
- 哈希的底层是一个数组实现的,叫做哈希表(散列表)
- 通过哈希函数计算元素在哈希中存储的下标
- 不可避免的的是,哈希函数计算出来的存储位置很有可能会与之前计算出来的其他元素的存储位置一样,但该位置不为空,这种现象叫做哈希冲突。
如何解决哈希冲突?
闭散列
从发生哈希冲突的位置开始查找“下一个”空位置,俩种查找方式:
- 线性探测:从发生哈希冲突的位置接着往下查找,如果查找到末尾也没有发现空位置就会哈希表的起始位置继续查找,找到空位置即查找结束。
- 二次探测:不是探测俩次,而是当发生哈希冲突时,该元素的位置会被重新计算,H(i)=H(0)+i^2或者H(i)=H(0)-i^2 该表达式意思:本次哈希地址=前一次哈希地址+2*i, i是第几次线性探测 线性探测的优点:当发生哈希冲突时,查找下一个空位方便 缺点:如果发生哈希冲突,冲突的元素容易连成一片
- 赋予每一个空间一个状态标记 当空间被元素占取,则标记为EXIT,空间为空,则标记为EMPTY。
开散列/哈希桶(链地址法)
- 数组+链表的集合 数组中每个元素都是链表,每个链表都是发生发生哈希冲突的元素
- 如何使用?
(1)insert
- 利用哈希函数计算出桶号
- 创造节点
- 头插进入哈希桶中
(2)扩容
- new开辟空间
- 把旧桶中的链表一一取下,计算新的桶号,头插到新桶中
- 释放旧桶
(3)find
- 通过哈希函数计算出需要查找的元素所对应的桶号
- 检测该元素是否在该桶的链表中
(4)earse
- 通过find函数查看所删除的元素是否存在
- 如果存在,通过哈希函数计算出需要删除元素所对应的桶号,找到元素并删除
负载因子
负载因子:已存储元素个数/哈希表长度
为了减少哈希冲突,提高哈希性能,这里引入了负载因子的概念。当哈希表存储了一定元素时,发生扩容,并重新计算元素间的映射关系。
为什么扩容之后,不直接使用memcpy把旧表中的元素拷贝到新表中?
哈希是一个存在位置映射关系的表,当表的容量发生变化时,意味着表中的元素会重新计算表中的位置