这一节主要讲很多方面非常重要的hash table等问题. 由于平时很少用到这些,基本都忘了。。。

怎样快速的在内存中插入、删除、和搜索呢? 这就需要哈希表了

这一节主要知识点是:1 简单的映射表和处理冲突方法     2.哈希函数的选择     3.开放寻址法(高级解决冲突方案)

1 简单的映射表和处理冲突方法

哈希表希望解决的一个典型问题是编译器内部的符号表,它的结构是:

每个记录有一个指针x指向这个记录,key[x]就是这个记录的关键字,然后后面就是一些具体数据。

如果我们想方便得进行增删查操作,这些数据应该如何组织呢?

最简单的方法:直接寻址表

这个方法当键值得范围相对较小的时候还是能够很好工作的。假设key都是从集合U{0,1,..,m-1}中得到的。

则可以建立一个表,T[0.. m-1]

简而言之,这个表就是当k=i时,就将其放在表T中第i个位置。表的其他位置留空就行了:如下图

直接寻址法有一个明显的问题,当U的范围很大时,就必须维持一个非常大的表,且实际上用到的可能很少!

而哈希表采用的另一种方法,它通过一个hash函数来映射k值(上面那个方法可以看做identical

mapping的函数)。 但是,这样就会出现不同键映射到相同槽内的方法,那应该怎么处理呢?

这里再给出一个简单方法:通过链表解决

这种方法最差情况就是所有元素都映射到了同一个槽里面,时间就是Θ(n),其实就是建了个链表

下面分析一下平均情况下链表法的性能,顺便引入一些概念:

做假设 哈希函数是简单均匀哈希(simple-uniform hashing),即每个键k 等可能的被hash到表T中的每个槽中,

且与其他键被哈希到什么位置无关

设n是表中key的个数,m是表槽的个数,定义表T的负载因子(load factor):

α = n/m = 平均每个槽中被映射的key的数量

然后给定key后,搜索成功与否的期望时间都是Θ(1+α)

2.哈希函数的选择

怎样选择一个好的hash函数呢?我们期望它具有的性质有下面两点:

  • 一个好的hash函数应该能够将keys均匀的映射到表的槽内
  • 键值的分布特性应该不影响这种均匀性质

选择的策略主要有两种:除法散列法  乘法散列法

除法散列法: 定义hash函数为 h(k) = k mod m

这种方法也有很多需要注意的: 不要选有很小除数的m. 比如如果选m是个偶数,假设所有的键值都是偶数的情况下,

那么所有的映射结果都只会在偶数槽呢,非常浪费,也违背了上面好的hash函数属性的第二条

另一个极端例子:假设m=2r,就是因子全都是最小的除数。如果k=1011000111011010,r-6,那么映射的结果

就是k的最后6位,这甚至都没有利用k的全部信息

所以这个方法中选择m的原则就是m选为质数且不能太接近2或者10的幂次

乘法散列法:设m=2r, 计算机是w-bit 长的字,然后定义哈希函数是

h(k) = (A*k mod 2w) rsh (w-r)

其中A是一个在(2w-1, 2w)范围内的奇数。

我们来分析这个哈希函数(A*k mod 2w)这一部分就是将乘法得到的结果只取一个字长 ,然后再

rsh w-r位,就刚好只保留了最大是m的结果,可以很好的映射到表中.

假设m=2^3, 字长w是7-bit ,考虑那个乘法过程:

这就像一个幸运大转轮一样,将A转k圈,得到最后的一个结果:

3.开放寻址法

所谓开放寻址法就是没有任何元素时存储在哈希表之外的。 那个当冲突发生时,开放寻址法通过一个探查(Probe)策略不断寻找表中的空槽

探查策略主要包括两种:线性探查   双哈希探查

线性探查使用的哈希函数时:

h(k,i) = (h(k,0)+i)mod m

简单来说,就是原始哈希函数如果映射到一个已经有元素的位置,就直接探查下一个,知道找到空槽。

但是这种方法会出现primary clustering: 某一块会被依次填满,导致映射到那一块时探查时间很长

双哈希探查的哈希函数是:

h(k,i) = (h1(k)+ i*h2(k))mod m

即使用两个哈希函数,当第一次哈希出现冲突时,使用第二个哈希函数做探查,直到找到空槽。

这种方法一般效果很好,但是h2(k)必须和m互质

下面对开放寻址法进行分析:

首先我们假设均匀哈希: 每个key的探查序列等可能的是m!种排列中的任意一种

定理:给定一个开放寻址的哈希表,负载因子α=n/m<1, 则不成功搜索时期望的探查次数最多是1/(1-α)

Proof:  第一次探查是有的,然后发生冲突的概率是n/m,发生冲突后就需要第二次探查了,第二次探查的

概率是(n-1)/(m-1),如此重复下去。

而我们知道n-i/m-1 < n/m =α ,所以我们有 探查的期望次数是:

1+n/m(1+n-1/m-1(1+n-2/m-2(....(1+1/n-m+1)...))

≤ 1+ α(1+α(1+α(...(1+α)...))

≤1+α23+....

=∑INFi=0αi

=1/1-α

因为α是常数,则寻址次数也就是一个常数了。但要注意所谓的常数,比如表示半满的,则期望探查此时就是

1/(1-0.5)=2 。 当90%满时,期望探查次数就是1/(1-0.9)=10

 
 
 
标签: 算法基础

HashTable的更多相关文章

  1. HashSet HashTable 与 TreeSet

    HashSet<T>类 HashSet<T>类主要是设计用来做高性能集运算的,例如对两个集合求交集.并集.差集等.集合中包含一组不重复出现且无特性顺序的元素. HashSet& ...

  2. Javascript实现HashTable类

    散列算法可以尽快在数据结构中找出指定的一个值,因为可以通过Hash算法求出值的所在位置,存储和插入的时候都按照Hash算法放到指定位置. <script> function HashTab ...

  3. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  4. java面试题——HashMap和Hashtable 的区别

    一.HashMap 和Hashtable 的区别 我们先看2个类的定义 public class Hashtable extends Dictionary implements Map, Clonea ...

  5. Map集合及与Collection的区别、HashMap和HashTable的区别、Collections、

    特点:将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值. Map集合和Collection集合的区别 Map集合:成对出现 (情侣)                       ...

  6. HashTable初次体验

    用惯了数组.ArryList,初次接触到HashTable.Dictionary这种字典储存对于我来说简直就是高大上. 1.到底什么是HashTable HashTable就是哈希表,和数组一样,是一 ...

  7. HashMap和 Hashtable的比较

    Hashtable 和 HashMap的比较 1.  HashMap可以接受null(HashMap可以接受为null的键值(key)和值(value), HashTable不可以接受为null的键( ...

  8. hashMap和hashTable的区别

    每日总结,每天进步一点点 hashMap和hashTable的区别 1.父类:hashMap=>AbstractMap hashTable=>Dictionary 2.性能:hashMap ...

  9. SortedList和HashTable

    都是集合类,C#中同属命名空间System.Collections,“用于处理和表现类似keyvalue的键值对,其中key通常可用来快速查找,同时key是区分大小写:value用于存储对应于key的 ...

  10. Java Hashtable的实现

    先附源码: package java.util; import java.io.*; /** * This class implements a hash table, which maps keys ...

随机推荐

  1. 2136 Largest prime factor(打表)

    Problem Description Everybody knows any number can be combined by the prime number.Now, your task is ...

  2. 用grunt搭建自动化的web前端开发环境

    用grunt搭建自动化的web前端开发环境 jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用! 1. 前言 各位web前端开发 ...

  3. DynamicReports 导出Excel 例子

    import java.awt.Color; import java.io.FileOutputStream; import java.util.ArrayList; import java.util ...

  4. CSS3新功能简要

    1.CSS3 框架:    由 CSS3,您可以创建圆角.加入到该矩形阴影,使用图片绘制边框.例如 * border-radius -border-*-radius(top,left,right,bo ...

  5. Unobtrusive JavaScript 是什么?

    Unobtrusive JavaScript 是什么? <!--以下是常规Javascript下写出来的Ajax--><div id="test">< ...

  6. 【百度地图API】建立全国银行位置查询系统(一)——如何创建地图

    原文:[百度地图API]建立全国银行位置查询系统(一)--如何创建地图 <摘要>你将在第一章中学会以下知识: 如何创建一个网页文件 怎样利用百度地图API建立一张2D地图,以及3D地图 如 ...

  7. exit() _exit()

    图 C程序的启动与终止 差别: _exit()函数:直接使进程停止执行,清除其使用的内存空间,并销毁其在内核中的各种数据结构; exit()函 数则在这些基础上作了一些包装,在运行退出之前加了若干道工 ...

  8. C#操作 Advantage Database Server 数据库

    相关下载 http://devzone.advantagedatabase.com/dz/content.aspx?key=31 1.安装数据库: Advantage Database Server ...

  9. cocos2d 游戏开发实战

    文章转自:http://uliweb.clkg.org/tutorial/read/40 6   cocos2d 游戏开发实战 6.1   创建cocos2d项目 6.2   cocos2d v3 & ...

  10. EF结合SqlBulkCopy

    EF结合SqlBulkCopy在项目中的使用 这是我第一次写博客,由于水平有限,写不出什么好东西,还望见谅. 我现在参与的这个项目采用的是EF框架,方便了数据库的访问.但在实际中,发现项目中导入市县E ...