哈希表能够以极快的速度来查找、添加或删除元素(只须要数次的比较操做。)它比红黑树、二叉搜索树都要快得多。可是哈希表没有排序功能,相似的,如寻找最大值、最小值、中值这些行为都不能在哈希表中实现。数组
要想对一组元素作成哈希表形式的数据结构,这些元素须要知足两个条件:数据结构
A. 元素拥有本身的哈希值。函数
B. 两个元素能够判断出是否相等。指针
第二个条件比较容易实现,关键是第一个条件。在介绍哈希表前,将先介绍哈希值。code
哈希值是一个int类型的整数。每一个元素都应该有本身的哈希值,而且这个值是惟一的。即知足:blog
A. 若是元素a与元素b相等,则元素a的哈希值与元素b的哈希值相等。排序
B. 若是元素a与元素b不相等,则元素a的哈希值与元素b的哈希值不相等。内存
一般状况下,对于int,bool,double,string等语言自带的类型都有本身的哈希值,能够用它们的哈希函数来获取,不一样语言的哈希函数可能会不一样。string
若是是用户本身新建的类型,则须要提供计算此类型元素哈希值的哈希函数。hash
在哈希表中,咱们是经过某元素的哈希值来查找、添加或删除元素的。
有许多方法能够实现哈希表,这里将介绍两种:拉链法(separate chaining)和线性探测法(linear probing)。
从例子入手:
现有整数类型(int)的数组S:7,30,10,9,14,19,15,12,90,94,93,53,70。此数组的元素的哈希值与元素值相同,即7的哈希值是7;30的哈希值是30。
现建立一个有5个元素的数组A:(红色颜色只是为了与数组S的元素区分开来)
而后按顺序把数组S插入数组A中:
插入元素7:元素7的哈希值为7,7%5=2,所以插入到2号元素中;
插入元素30:元素30的哈希值为30,30%5=0,所以插入到0号元素中;
插入元素10:元素10的哈希值为10,10%5=0,所以插入到0号元素中,但0号元素已经有数值30了,故插到30后面,元素30的指针指向元素10。
如此类推,插入元素9:元素9的哈希值为9,9%5=4,所以插入到4号元素中...
所有元素添加完毕后:
如今,若是咱们要查找元素19:
元素19的哈希值为19,19%5=4,所以到4号元素去找;
4号元素的值为9,9!=19,去找9的指针指向的元素14;
14!=19,去找14的指针指向的元素19;
19==19,返回数值,查找完毕。
此过程只经历了3次比较!
今后例子中能够看出思路:
对于一个拥有N项元素的数组S,咱们须要创建一个含有M项元素的新数组A。
M的值能够本身来定,但若是M过大,则会出现不少空链,如上述例子中的1号链;
若是M太小,则会出现链太长的状况,若是链太长,则意味着比较次数变多。
通常建议M=N/5。
插入元素:
int j=S[i]的哈希值%5;
而后检查A[j]是否为空,若是空,A[j]=S[i]; 若是不为空,temp=A[j], A[j]=S[i], S[i].next=temp;
删除元素:先找出该元素,而后此元素的上一个元素的指针指向此元素的下一个元素,最后删除此元素。
拉链法有一个缺陷,就是很容易有些链过长,有些链太短,甚至是空链。这样会浪费内存和影响搜索速度。
从例子入手:
现有整数类型(int)的数组S:7,30,10,9,14,19,15,29,13,27。此数组的元素的哈希值与元素值相同,即7的哈希值是7;30的哈希值是30。
现建立一个含有14个元素的数组A:(上面那排数字是为了方便看哪一个元素是第几项元素)
而后按顺序把数组S插入数组A中:
插入元素7:元素7的哈希值为7,7%14=7,所以插入到7号元素中;
插入元素30:元素30的哈希值为30,30%14=2,所以插入到2号元素中;
插入元素10:元素10的哈希值为10,10%14=10,所以插入到10号元素中;
插入元素9:元素9的哈希值为9,9%14=9,所以插入到9号元素中;
插入元素14:元素14的哈希值为14,14%14=0,所以插入到0号元素中;
插入元素19:元素19的哈希值为19,19%14=5,所以插入到5号元素中;
插入元素15:元素15的哈希值为15,15%14=1,所以插入到1号元素中;
插入元素29:元素29的哈希值为29,29%14=1,但1号元素已经有数值15了,而后检查下一个元素(2号元素),但2号元素已经有数值30了,而后检查下一个元素(3号元素),3号元素为空,插入到3号元素:
插入元素13:元素13的哈希值为13,13%14=13,所以插入到13号元素中:
插入元素27:元素27的哈希值为27,27%14=13,但13号元素已经有数值13了,而后检查下一个元素(0号元素),但0号元素已经有数值14了,如此类推,找到4号元素为空,插入到4号元素:
若是咱们要查找元素29,元素29的哈希值为29,29%14=1,检查1号元素,15!=29;而后检查下一个元素(2号元素),30!=29;而后检查下一个元素(3号元素),29=29,返回数值,查找完毕。
今后例子中能够看出思路:
对于一个拥有N项元素的数组S,咱们须要创建一个含有M项元素的新数组A。
M必定要比N大。若是M过少,则搜索进行的比较次数增长,影响速度;若是过大,则太多空位没利用,形成内存浪费。
通常建议M=2*N。
插入元素i: 先获取i的哈希值%M,根据这个值插入到相应的位置中,若是位置有元素了,则插入到下一个位置,循环进行,直到位置是空的为止。
搜索元素:相似于插入元素,详细见上述例子。