携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情
数组、链表、哈希表的优缺点
查找 | 插入和删除 | |
---|---|---|
数组(顺序表) | 容易 | 困难 |
链表 | 困难 | 容易 |
哈希表) | 容易 | 容易 |
哈希表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表
基本思想
哈希表的关键是使用哈希函数,将键 key 和值 value 映射到对应表的某个区块中。可以将算法思想分为两个部分:
-
向哈希表中插入一个关键字:
哈希函数决定该关键字的对应值应该存放到表中的哪个区块,并将对应值存放到该区块中
-
在哈希表中搜索一个关键字:
使用相同的哈希函数从哈希表中查找对应的区块,并在特定的区块搜索该关键字对应的值
哈希函数
将哈希表中元素的关键键值映射为元素存储位置的函数。
一般来说,哈希函数会满足以下几个条件:
- 哈希函数应该易于计算,并且尽量使计算出来的索引值均匀分布,这能减少哈希冲突
- 哈希函数计算得到的哈希值是一个固定长度的输出值
- 如果 Hash(key1) 不等于 Hash(key2),那么 key1、key2 一定不相等
- 如果 Hash(key1) 等于 Hash(key2),那么 key1、key2 可能相等,也可能不相等(会发生哈希碰撞)
在哈希表的实际应用中,关键字的类型除了数字类型,还有可能是字符串类型、浮点数类型、大整数类型,甚至还有可能是几种类型的组合。一般会将各种类型的关键字先转换为整数类型,再通过哈希函数,将其映射到哈希表中。
通常用到的哈希函数方法有:
- 直接定址法
- 除留余数法
- 平方取中法
- 基数转换法
- 数字分析法
- 折叠法
- 随机数法
- 乘积法
- 点积法
哈希碰撞
在计算hash地址的过程中会出现对于不同的关键字出现相同的哈希地址的情况,即key1 ≠ key2,但是f(key1) = f(key2),这种情况就是Hash 冲突。具有相同关键字的key1和key2称之为同义词。
通过优化哈希函数可以减少这种冲突的情况(如:均衡哈希函数),但是在通用条件下,考虑到于表格的长度有限及关键值(数据)的无限,这种冲突是不可避免的,所以就需要处理冲突。
解决冲突的方法
-
开放地址
开放地址法处理冲突的基本原则就是出现冲突后按照一定算法查找一个空位置存放
-
再哈希
再哈希法,就是出现冲突后采用其他的哈希函数计算,直到不再冲突为止
-
链地址
他是在出现冲突的地方存储一个链表,所有的同义词记录都存在其中。形象点说就行像是在出现冲突的地方直接把后续的值摞上去。例如HashMap,
-
建立公共溢出区
建立公共溢出区的基本思想是:假设哈希函数的值域是[1,m-1],则设向量HashTable[0...m-1]为基本表,每个分量存放一个记录,另外设向量OverTable[0...v]为溢出表,所有关键字和基本表中关键字为同义词的记录,不管它们由哈希函数得到的哈希地址是什么,一旦发生冲突,都填入溢出表。