拓展

哈希算法

Python哈希查找,构建简单哈希表
http://blog.csdn.net/tingyun_say/article/details/51777159

def find(arr,j):
    len1=len(arr)
    hasharr=[0]*(len1+5)
    arr2=[0]*(len1+5)
    i=0
    while i<len1:
        a=arr[i]%17
        while arr2[a]!=0:
            a+=1
            if i == len1:
                i=0
        hasharr[a]=arr[i]
        arr2[a]=1
        i+=1
    print(hasharr)
    print('\n')
    print arr2
    
    
arr=[10,8,15,45,7,5,6,2,11,23,4,778,9,5,12]

len1=len(arr)
hasharr=[0]*(len1+5)
arr2=[0]*(len1+5)
i=0
while i<len1:
    a=arr[i]%17
    #print(a)
    while arr2[a]!=0:
        a+=1
        if i == len1:
            i=0
    hasharr[a]=arr[i]
    arr2[a]=1
    i+=1
print(hasharr)
print('\n')
print arr2


j=10
num=j%17
while num<(len1+5):
    if arr2[num]==1:
        if hasharr[num]==j:
            print('找到元素,在hash表位置:%s处'%num)
            num=len1+5
        else:
            num+=1
    else:
        print('不存在’)
        num=len1+5

一、数学定义中的哈希算法

由哈希算法计算出来的值,即哈希值

1、一个哈希算法的案例:
回忆小学数学,如何判断一个整数能否被3整除?(模三算法)
注意:模三算法第一次运行得到的值如果位数太多(导致仍然无法一眼判断出此值能否被三整除),可再次模三(递归),直至取得个位数,递归本身也是模三算法的一部分

2、结论:
哈希算法是一个特征算法,哈希值是一个特征值
特征值:即这个值能够反映出原始值的某个特征(比如“能否被3整除”这个特征)

3、哈希算法的特征:
1、不可逆(已知输出值,不可反向推算出输入值)
2、结果定长(在计算机里指的是所占用的字节数,在数学里指的是数字位数)
3、若算法确定,则结果唯一(数字指纹特性)

4、反例:
加一算法:f(x) = x + 1,不是哈希算法,因为可逆
加随机数算法:f(x) = x + random,不是哈希算法,因为算法确定时,结果不唯一(不是指纹)
平方算法:f(x) = x ^ 2,不是哈希算法,因为不定长

5、模三算法是一个“不好的哈希算法”,因为哈希值极易重复
好的哈希算法,重复概率小。
通过增加参数、计算逻辑复杂化等方式,可大幅减少重复率

二、计算机应用中的哈希算法

用处:
加密
验证
内存寻址(散列算法、散列值)
最开始的用处
1、加密:
用户输入密码,前端计算出hash值传递到后端,后端判断此值与数据库中保存的原密码的hash值是否一致。
若一致,则表示用户输入的是正确密码;反之是错误密码。
如此,在网络传输层和后端数据库中都不用保存原密码,而只需要保存hash值即可,确保了密码安全。即使黑客抓包或攻破后端数据库,也只能得到密码的hash值,而得不到原密码。
(根据不可逆特性,通过hash值无法计算出原密码。并且,好的hash算法重复率低,不易出现“客户输入错误密码,但hash值与正确密码一致,导致此错误密码仍能验证通过”的情况)

直接保存密码 效率高

定长,一方面计算机知道位数 提高效率 一方面要去计算降低效率

2、验证:
假设网站后端有一个文件(在计算机中,一切皆由二进制数字组成,因此可认为一切文件皆是数字)。网站管理员使用一个算法计算出此文件的hash值,并公布该hash值和该算法,当用户下载这个文件到本地之后,使用该算法重新计算一遍hash值,与网站管理员公布的hash值核对,若一致,则可认为该文件在传输过程中没有损坏、没有被黑客掉包。
(利用了哈希值的数字指纹特性)

3、内存寻址:
内存条由无数个内存颗粒组成,文件就保存在内存条的固定区域中。

3.1、住酒店的例子:
内存条就像一个酒店,每块内存区域就像酒店的一个房间,需要保存的数据就是客人,存数据的过程就是客人入住酒店,CPU就是酒店前台,负责管理所有房间。

3.1.1、传统方法:
客人张三(身份证号123456)入住酒店,酒店前台随机安排一个房间给张三。若第二天有人来酒店找张三(有一个程序需要寻找张三这个文件),只能一个一个房间找,效率低下。

3.1.2、哈希方法:
客人张三(身份证号123456)入住酒店,酒店前台根据某个hash算法,输入张三的身份证号,计算得到一个数字(假设为26),于是安排张三入住2楼第6个房间。若第二天有人来酒店找张三(有一个程序需要寻找张三这个文件),只需告知前台张三的身份证号,通过该算法直接就能找到张三的位置在2楼第6个房间,效率高。

3.2、实际应用中:
3.2.1、对于硬盘:
一个文件就是一个人,而文件名(字符串的本质是unicode编码,所以文件名也是数字)就是这个人的身份证号,根据特定算法,操作系统就可以快速找到文件在硬盘上的位置

3.2.2、对于内存条:
文件从硬盘被读入内存之后,是没有文件名的。因此操作系统会给这个文件赋予一个独一无二的值(称为key),通过key计算出hash值,通过hash值确定该文件在内存中的位置。当程序使用CPU寻址时,告知CPU所要找的key,CPU即可通过hash算法快速找到文件的确定位置。文件在内存中称之为value,一个key对应一个value。key-value,即:键值对。

要key值为何还要哈希值

单独位置存放哈希值

3.3、正因为哈希算法和哈希值可以用来排列文件、给文件定位,因此又称为散列算法、散列值。

4、需要注意的点:

4.1、键值对内存模型的实际运用中,实际上是新建了一个数组,hash值对应数组下标,该数组称为哈希表(散列表);

4.2、由于计算出hash值并不连续,因此哈希表中的大多数位置其实是空的。这也是键值对内存模型的缺点:占用内存太大,牺牲内存容量来换取寻址速度;

4.3、hash值不一定是十进制数,例如著名的MD5算法,计算出的hash值就是十六进制数;

4.4、hash值只能尽量避免重复,无法彻底杜绝重复。所以在实际运用中,总会出现两个key拥有同一个hash值的现象;

4.5、在内存寻址中,当hash值重复时,通常有三种方法来避免冲突

4.5.1、rehash法:顾名思义,换个算法重新hash一次,实际操作中并不会更换算法,但是会更换算法中的参数,使hash值不一致。缺点是rehash后所有文件需要重新排列一次,消耗CPU;

4.5.2、进位法:通过4.1可知,哈希表中大多数位置其实是空的。所以若hash值重复,可以将文件就近放在相邻的空区域中,若相邻的空区域也有文件,则继续寻找相邻的空区域,直至找到,缺点是后期寻址时有可能不能一次成功。

4.5.3、链表法:当hash值重复,将第N个文件放在对应的数组下标区域的下方(下方指的是C语言指针向Y轴负方向偏移一位),在第一个文件上增加一个指针指向第二个文件,在第二个文件上增加一个指针指向第三个文件……,以此类推,组成一个链。缺点是当删除链表上的某个文件时,链表断裂,需重新建立指针,内存模型过于复杂。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 语法:ipset [ OPTIONS ] COMMAND [ COMMAND-OPTIONS ]COMMANDS ...
    老夫刘某阅读 3,060评论 0 0
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,742评论 18 399
  • 好多天都没有更新了,这些天一直都在医院陪护长辈,医院的环境太杂闷,又一直想不到好的题材,再加上我实在是写作的水平...
    冯小小_阅读 1,020评论 0 2
  • 文:承水 云彩翻涌出让人难以捉摸的形状,让月亮假借太阳的光亮嵌在云朵的缝隙中重现,恍惚间有种感觉,云彩本就该拥有如...
    承水阅读 333评论 0 0
  • 时间总是推着我们不停的向前,你是否也有同感,我们来不及和身边的某些人好好道别,就可能再也不见了。很多时候我们不想道...
    伍果果伍611阅读 463评论 0 2