一、啥是哈希表
哈希表又称散列表,其实就是和数组、链表一样的是一种数据结构,在你从来没有接触过这个概念的时候,觉得神秘而不可探测,其实就是一纸老虎,人狠话不多,先上一个相对官方的概念定义:
散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。建立了关键字与存储位置的映射关系,公式如下:
存储位置 = f(关键字)
这里把这种对应关系f称为散列函数,又称为哈希(Hash)函数。
采用散列技术将记录存在在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表。那么,关键字对应的记录存储位置称为散列地址。
散列技术既是一种存储方法也是一种查找方法。散列技术的记录之间不存在什么逻辑关系,它只与关键字有关,因此,散列主要是面向查找的存储结构。
人狠话不多,直接例子:
例1:现在我要你存储4个元素 13 7 14 11,你将如何存储???
答:显然,我们可以用数组来存。也就是:a[1] = 13; a[2] = 7; a[3] = 14; a[4] = 11;
当然,我们也可以用Hash来存。下面给出一个简单的Hash存储:
先来确定那个函数。我们就用h(key) = key%5;(这个函数不用纠结,我们现在的目的是了解为什么要有这么一个函数)。那么
对于第一个元素 h(13) = 13%5 = 3; 也就是说13的下标为3;即Hash[3] = 13;
对于第二个元素 h(7) = 7 % 5 = 2; 也就是说7的下标为2; 即Hash[2] = 7;
同理,Hash[4] = 14; Hash[1] = 11;
好了,存现在是存好了。但是,这并没有体现出Hash的妙处,现在我要你查找11这个元素是否存在。你会怎么做呢?
当然,对于数组来说,那是相当的简单,一个for循环就可以了。也就是说我们要找4次。这是很笨的办法,因为为了找一个数需要把整个序列循环一遍才行,太慢!
下面我们来用Hash找一下:
首先,我们将要找的元素11代入刚才的函数中来映射出它所在的地址单元。也就是h(11) = 11%5 = 1 了。下面我们来比较一下Hash[1]?=11, 这个问题就很简单了。
也就是说我们就找了1次。我咧个去, 这个就是Hash的妙处了。
那么,怎么设计哈希函数呢,上边的mod 5,我还mod 8 呢,是不是很气?接下来咱们就看看哈希函数的设计
二、哈希函数的设计
1 直接定址法
取关键字或者关键字的某个线性函数为Hash地址,即address(key)=a*key+b;如知道学生的学号从2000开始,最大为4000,则可以将address(key)=key-2000作为Hash地址。
2 平方取中法
对关键字进行平方运算,然后取结果的中间几位作为Hash地址。假如有以下关键字序列{421,423,436},平方之后的结果为{177241,178929,190096},那么可以取中间的两位数{72,89,00}作为Hash地址。
3 折叠法
将关键字拆分成几部分,然后将这几部分组合在一起,以特定的方式进行转化形成Hash地址。假如知道图书的ISBN号为8903-241-23,可以将address(key)=89+03+24