排序和搜索(三)——hash查找之hash函数(1)

在之前的(一)顺序查找和(二)二分查找中我们都是基于数据在列表中存储的索引位置查找的,本文所要说的是基于hash表的查找

hash表】又名散列表,是一种根据关键码寻找值的数据映射结构。哈希表的每个位置,通常称为槽,对应存储一个项,由0开始,如图所示是一个size为10的哈希表,最初每个槽中没有值,均为None.

hash函数】又称为散列函数,是数据值与哈希表之间的映射函数。哈希函数接收数据值,返回值结余0和size-1之间的整数(槽名范围内),在上述哈希表中,返回的哈希值就必须介于0-9之间。下面介绍一下常见的哈希函数:

1)余数法

将数据值除以表的大小size,所得余数即为该数据值对应的槽的位置

H(item)=item%size

将数据25,38,46,12,31按照余数法插入到上述哈希表中,则有如下

25%10

5

38%10

8

46%10

6

12%10

2

31%10

1

 余数法存在的问题是,如果输入数据86,余数6,和46所在槽冲突。如果要避免冲突就要尽可能提供多点槽,这样又存在资源利用率不高,因此下面几种方法就是做到最大程度减少冲突

(2)分组求和法

 将项划分为相等大小的块(最后一块可能不是相等大小)。然后将这些块加在一起以求出散列值。例如,如果我们的项是电话号码 436-555-4601,我们将取出数字,并将它们分成2位数(43,65,55,46,01)43 + 65 + 55 + 46 + 01,我们得到 210。我们假设哈希表有 11 个槽,那么我们需要除以 11 。在这种情况下,210%11 为 1,因此电话号码 436-555-4601 散列到槽 1 。一些分组求和法会在求和之前每隔一个反转。对于上述示例,我们得到 43 + 56 + 55 + 64 + 01 = 219,其给出 219%11 = 10 

(3)平方取中法

首先求数据值得平方,然后提取一部分数字结果。例如,如果项是 44,我们将首先计算 44^2 = 1,936 。通过提取中间两个数字 93 ,我们得到 5(93%11)

 (4)利用ascii码(字符串)

对于字符串,求其散列值可以将字符串理解为一个字符构成的序列,而每个字符对应一个ascii值,因此字符串也可以理解为ascii的序列。利于求H('cat'),在ascii码中,


得出三个字符的ascii值后,相加99+97+116=312,再利用余数法求出散列值312%10=2,见【代码1】

值得注意的是,这种基于ascii码的哈希函数对于字符组成相同的得出的散列值是一样的,即同样存在冲突问题,例如利用【代码1】求出的‘team’和‘meat’相同。

解决方式:可采用字符位置座位权重,例如,cat可采用99*1+97*2+116*3==641,641%10=1,见【代码2】

【代码1】

#利用ascii码(字符串)
def hashSearchByAscii(str,tablesize):
    sum=0
    for s in str:
        sum=sum+ord(s)
    return sum%tablesize
print(hashSearchByAscii('cat',10))

【代码2】
#利用ascii码(字符串)+字符的位置权重
def hashSearchByAscii2(str,tablesize):
    sum=0
    for i in range(len(str)):
        sum=sum+ord(str[i])*(i+1)
    return sum%tablesize
print(hashSearchByAscii2('team',10))
print(hashSearchByAscii2('meat',10))
print(hashSearchByAscii2('cat',10))

猜你喜欢

转载自blog.csdn.net/brave_jcc/article/details/79499336