hash概念
哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。
搜索方法:可以进行少量的比较,1次或者2-3次从数据中得到要搜索的数据,是大量数据的搜索时间复杂度变成O(1)。
哈希函数hashfunc
可以通过哈希函数与存储表中的元素建立一亿映射的关系,可以通过此函数直接查找到该数据在哈希表中的位置。
插入元素
按照哈希函数的要求,讲较长的数据通过哈希函数映射出较短的数据,以用来存储该元素
搜索元素
通过需要搜索的元素的值来与哈希函数得到相应的映射数据,再根据哈希表和映射数据查找到该元素的位置。
常见的哈希函数
- 直接定址法:hash(key) = a*key +b ——以线性的方式直接定下地址
- 除留余数法:hash(key) = key % n ——以余数作为哈希地址
- 平方取中法:比如说123数据,平方为15129,取中间的12作为哈希地址
- 随机数法:hash(key) = random(key) random为随机数
- 数学分析法:存储一些有规律的数据,比如说电话号码。(先进行分析,在进行存储)
哈希冲突
当采用除留余数法进行哈希地址的取值时,先讲4,5,6,7,9存入哈希表之后,在当存44的时候,发现44的地方已经被占用,也就是说两个数据所计算出的哈希地址相同,这样就发生了哈希冲突
哈希冲突的解决办法—闭散列
闭散列—线性探测
插入
简单来说就是从发生冲突的地方向后查找,直到查找到可以存放位置,将其存放。如果查找到末尾还没有适当位置,从0的位置继续向后查找。
hash(key) = key % capacity
删除
采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他元素的搜索。比如删除元素4,如果直接删除掉,44查找起来可能会受影响。因此线性探测采用标记的伪删除法来删除一个元素。使用{EMPTY,EXIST,DELETE} 三个标志来表示。
扩容
负载因子 = 填入表中的元素 / 哈希表的长度
当负载因子大于等于0.7 时,进行扩容,扩容是需要重新对哈希元素进行存储。
闭散列—二次探测
显然二次探测就是使用除留余数法的余数的二次方进行依次向后探测。
插入
和线性探测插入方式相同
删除
和线性探测删除方式相同
扩容
负载因子 一般为0.5 时进行扩容。
闭散列代码实现
开散列
以哈希桶的形式,也就是说,哈希表内部存放着链表,这样可以使存放相同元素时。直接进行结点插入即可。
插入元素44的时候,哈希表的运行方式
删除
直接将结点删除即可
扩容
扩容时,也需要增大哈希桶的capacity,然后进行结点的重新排列。