<转>哈希是什么?为什么哈希存取比较快?

哈希算法存取之所以快,是因为其 直接通过关键字key得到要存取的记录内存存储位置

试想这样的场景,你很想学太极拳,听说学校有个叫张三丰的人打得特别好,于
是你到学校学生处找人,学生处的工作人员可能会拿出学生名单,一个一个的查找,
最终告诉你,学校没这个人,并说张三丰几百年前就已经在武当山作古了。可如果你
找对了人,比如在操场上找那些爱运动的同学,人家会告诉你,"哦,你找张三丰呀,
有有有,我带你去。于是他把你带到了体育馆内,并告诉你,那个教大家打太极的小
伙子就是张三丰',原来"张三丰.是因为他太极拳打得好而得到的外号。
学生处的老师找张三丰,那就是顺序表查找,依赖的是姓名关键字的比较。而通
过爱好运动的同学询问时,没有遍历,没有比较,就凭他们"欲找太极'张三丰',必
在体育馆当中"的经验,直接告诉你位置。

也就是说,我们只需要通过某个函数f,使得

存储位置=f (关键字)

那样我们可以通过查找关键字不需要比较就可获得需要的记录的存储位置。这就
是一种新的存储技术一一散列技术(哈希算法)。

散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key 对应一个存储位置f (key)。

查找时,根据这个确定的对应关系找到给定值key 的映射f (key) ,若查找集合中存在这个记录,则必定在f (key) 的位置上。
这里我们把这种对应关系f 称为散列函数, 又称为哈希(Hash) 函数。按这个思想,采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)。 那么关键字对应的记录存储位置我们称为散列地址。

整个散列过程其实就是两步。
(1) 在存储时,通过散列函数计算记录的散列地址,并按此散列地址存储该记录。
(2) 当查找记录时,我们通过同样的散列函数计算记录的散列地址,按此散列地址访问该记录。由于存取用的是同一个散列函数, 因此结果当然也是相同的。

所以说,散列技术既是一种存储方法,也是一种查找方法。然而它与线性表、树、图等结构不同的是,前面几种结构,数据元素之间都存在某种逻辑关系,可以用
、连线图示表示出来,而散列技术的记录之间不存在什么逻辑关系,它只与关键字有关联。因此,散列主要是面向查找的存储结构。

我们时常会碰到两个关键字key1 != key2,但是却有f(key1) = f(key2),这种现象我们称为哈希冲突,如果没有哈希冲突,散列表是一种非常高效的查找数据结构,其时间复杂度为O(1);

简单通俗地理解Hash哈希存储

先来了解一下Hash的基本思路:

设要存储对象的个数为num, 那么我们就用len个内存单元来存储它们(len>=num); 以每个对象ki的关键字为自变量,用一个函数h(ki)来映射出ki的内存地址,也就是ki的下标,将ki对象的元素内容全部存入这个地址中就行了。这个就是Hash的基本思路。
Hash为什么这么想呢?换言之,为什么要用一个函数来映射出它们的地址单元呢?
This is a good question.明白了这个问题,Hash不再是问题。下面我就通俗易懂地向你来解答一下这个问题。
现在我要存储4个元素 13、 7、 14、 11

显然,我们可以用数组来存。也就是:a[1] = 13; a[2] = 7; a[3] = 14; a[4] = 11;

当然,我们也可以用Hash来存。下面给出一个简单的Hash存储:

先来确定那个函数。我们就用h(ki) = ki%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的妙处了。至此,刚才的问题也就得到了解答。至此,你也就彻底的明白了Hash了。

Hash冲突的处理

例:
假定一个待散列存储的线性表为(32,75,29,63,48,94,25,46,18,70),散列地址空间为HT[13]
若采用除留余数法构造散列函数和线性探测法处理冲突
试求出每一元素的初始散列地址和最终散列地址,画出最后得到的散列表,求出平均查找长度


<转>哈希是什么?为什么哈希存取比较快?_第1张图片

例:已知一组关键字为(26,36,41,38,44,15,68,12,06,51),用除余法构造散列函数,用线性探查法解决冲突构造这组关键字的散列表。
解答:

为了减少冲突,通常令装填因子α

由除余法的散列函数计算出的上述关键字序列的散列地址为(0,10,2,12,5,2,3,12,6,12)。

前5个关键字插入时,其相应的地址均为开放地址,故将它们直接插入T[0],T[10),T[2],T[12]和T[5]中。

当插入第6个关键字15时,其散列地址2(即h(15)=15%13=2)已被关键字41(15和41互为同义词)占用。

故探查h1=(2+1)%13=3,此地址开放,所以将15放入T[3]中。

当插入第7个关键字68时,其散列地址3已被非同义词15先占用,故将其插入到T[4]中。

当插入第8个关键字12时,散列地址12已被同义词38占用,故探查hl=(12+1)%13=0,而T[0]亦被26占用,再探查h2=(12+2)%13=1,此地址开放,可将12插入其中。

类似地,第9个关键字06直接插入T[6]中;而最后一个关键字51插人时,因探查的地址12,0,1,…,6均非空,故51插入T[7]中。

你可能感兴趣的:(<转>哈希是什么?为什么哈希存取比较快?)