一、哈希表(散列表hash table)定义算法
哈希表就是利用哈希算法(散列技术)将记录保存到一块连续的存储空间中,这块连续的存储空间就叫作哈希表或散列表。数据结构
散列技术就是根据记录的存储位置和它的关键字KEY创建一个肯定的对应关系F,使得每个关键字key对应一个存储位置F(key)。查找时根据这个肯定的对应关系找到给定值key的映射F(key)。函数
这个肯定的对应关系就叫作散列函数,又叫作哈希函数。关键字对应的记录存储位置叫作散列地址。性能
二、哈希表的查找步骤:搜索引擎
(1)、当存储时,经过散列函数计算出散列地址,而后按照散列地址将记录存储到散列表中。设计
(2)、当查找时,使用与存储时相同的散列函数计算出散列地址,按次散列地址访问该记录。指针
因此散列技术即便一种存储方法,又是一种查找方法。日志
三、哈希表与其余数据结构的区别(如线性表、树、图等)?排序
其余数据结构存储的数据元素之间存在某种逻辑关系,而哈希表的记录之间不存在任何逻辑关系,记录只和关键字存在关联。即一个关键字对应一个记录。哈希表存储的是键值对的形式。索引
哈希表的好处是查找速度快,查找时较其余数据结构简化了比较过程,提升了效率。但哈希表不具有不少常规数据结构的能力,如当一个关键字对应多个记录时,不适合用哈希表存储;同时哈希表也不适合范围查找,对与对记录排序、获取最大值最小值也不能获得。
散列冲突:当两个不一样的关键子key1和key2经过散列函数计算获得相同的散列地址时,这种现象就叫作冲突,引发冲突的关键字称为散列函数的同义词。
四、散列函数的构造方法
设计好的散列函数的原则:计算简单和散列地址分布均匀。
(1)、直接定址法:即取关键字的某个线性函数值做为散列地址。
散列函数公式:f(key) = a*key + b;(a、b为常数)
优势:简单、均匀、不会产生冲突。
缺点:须要事先直到关键字的分布状况,适合查找表小且连续的状况。
(2)、数字分析法:抽取关键字的一部分来计算散列地址的方法。
适合处理关键字位数比较大的状况,当事先知道关键字的分布且关键字的若干位分布均匀,这种方法适合。
(3)、平方取中法:取关键字平方的中间几位做为散列地址。
比较适合事先不知道关键字的分布,而关键字位数不是很大的状况。
(4)、折叠法:将关键字从左到右分红位数相同的几部分(最后一部分位数不够能够短些),而后将这几部分叠加求和,再根据哈希表表长,取后几位做为散列地址。
折叠法事先不知道关键字的分布,适合关键字位数较多的状况。
(5)、除留余数法:此方法是最经常使用的构造散列函数的方法,对于散列表长m的散列函数公式为:f(key) = key mod p (p<=m)
关键就是选择合适的p值,若表长为m,一般p为小于或等于表长(最好接近m)的最大质数或不包含小于20质因子的合数。
(6)、随机数法:取关键字的随机函数值做为散列地址。
当关键字的长度不等时,采用随机函数法比较合适。
五、处理散列冲突的方法
设计再好的散列函数也不可能彻底避免冲突的发生,因此要使用其余的方法来解决冲突。
(1)、开放定址法(闭哈希法):就是一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
开放定址法又分为三种方法:
线性探测法:散列函数的公式为f(key) = (f(key) + di) mod m;(di=一、二、三、........m-1)
di为位移量。线性探测法容易产生堆积现象,就是原来不是同义词的两个关键字在冲突计算过程当中获得相同的散列地址。
平方探测法:散列函数的公式为f(key) = (f(key) + di) mod m;(di=1^二、-1^二、2^二、-2^二、.........p^二、-p^2)(p<=m/2)。
随机探测法:位移量di采用随机函数计算获得。散列函数的公式为f(key) = (f(key) + di) mod m;(di是一个随机数列)。
(2)、再散列函数法:对于一个散列表来讲,事先准备多个散列函数。每当发生散列冲突时,就换一个散列函数计算散列地址,总会有一个能够解决冲突。这种方法使得关键字不产生汇集,相应的也增长了计算时间。
(3)、链地址法(开哈希法):就是将全部关键字为同义词的记录存储到一个单链表中,称次单链表为同义词子表,在散列表中只存储同义词子表的头指针(散列地址)。优势是不管有多少冲突,都是在当前位置给单链表增长节点的问题;缺点:查找时须要遍历单链表。链地址法不会产生任何堆积,于是具备更佳的平均查找性能。
(4)、公共溢出区法:创建一个公共溢出区来存储全部冲突的关键字(同义词)。
当查找时,经过给定的关键字经过散列函数计算出散列地址,先与基本表(散列表)的相应位置进行比较,若是相同,查找成功。不相等,则到溢出表中顺序查找。
六、散列表的查找性能
若是散列表没有发生冲突,散列表的查找性能最高,时间复杂度为O(1)。可是实际应用中,冲突是不可避免的。
散列表的平均查找长度取决那些因素?
1>、散列函数是否均匀
2>、处理冲突的方法:相同的关键字、相同的散列函数,但处理冲突的方法不一样,则会使平均查找长度不一样。线性探测法处理冲突可能会产生堆积(就是原来不是同义词的两个关键字在冲突计算过程当中获得相同的散列地址),显然没有平方探测法性能好,而链地址法处理冲突不会产生任何冲突,因此具备更佳的平均查找性能。
3>、散列表的装填因子:装填因子a=填入表中的记录个数/散列表表长。a标志着散列表的装满程度。当填入表中的记录越多,装填因子越大,产生冲突的可能性越大。因此:散列表的平均查找长度取决于装填因子,而不是取决于查找集合的记录个数。
总结:散列表(哈希表)是一种很是高效的查找数据结构,它与以前数据结构的查找不一样,它避免了关键字之间反复的比较。而是经过关键字直接查找到结果。散列表对于那些查找性能要求高,记录之间又没有任何要求的数据有很是好的实用性。
搜索引擎会经过日志文件把用户每次检索使用的全部检索串都记录下来,每一个查询串的长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但若是除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请你统计最热门的10个查询串,要求使用的内存不能超过1G。
分为两个步骤:首先统计query串的次数,而后在找出top10。
统计query串的次数:遍历全部检索串,采用hash表存储,key存储query串,value存储query串的次数。时间复杂度为O(N)。
找出top10:将哈希表建成小顶堆,而后用堆排序找出top10。