目录

前言:

哈希:

哈希表:

哈希表组成:

哈希表实例:

哈希函数:

TIPS:

总结


前言:

如果此时我要你默写一个有一百位的数字,你要如何做才能保证不会漏写呢?我们有一种方法很好用:直接数我们写的数字有没有100个就好了,而这种把长的信息串压缩起来的方法就叫做哈希。

哈希:

哈希算法是一种将任意长度的信息压缩到一个固定长度的摘要信息的算法。哈希算法将原始数据映射成一段长度固定、内容任意的二进制字符串,该字符串通常称为哈希值、消息摘要或数字指纹。

注意点:有人看到了哈希可以转换信息的优点,便认为哈希就是加密其实这种思想是错误的

因为加密是可逆的,而哈希是不可逆的,我们可以通过加密过的文件解密得到本体,但是无法通过哈希值得到本体。 

举例:

  网站账户的密码存储就是一个典型的哈希过程。当我们创建一个网站账户时,通常会设置一个密码。为确保安全性,网站通常会先使用哈希算法将密码字符串转换成一个哈希值,并将这个哈希值存储在服务器上。这样,即使黑客攻击了网站,也无法得到我们的明文密码。我们输入密码登录时,网站会再次对我们输入的密码进行哈希,然后将结果与存储的哈希值进行比较。如果结果匹配,则认为密码正确,允许我们登录。

举个简单的例子,假设我们在某个网站注册时,设置的密码为 “password123”,网站使用SHA256算法将其哈希成 “d3c59d25033dbf980d29554025c23a75” 并存储在服务器上。当我们登录时,我们输入密码 “password123”,网站再次使用SHA256算法将其哈希成 “d3c59d25033dbf980d29554025c23a75”,并发现与之前存储的哈希值相同,于是认为我们输入的密码是正确的,允许我们登录。由于哈希算法的不可逆性,黑客即使获取了存储的哈希值,也无法反向推导得到我们的密码。

哈希表:

而我们基于哈希这种算法,设计了一种数据结构:哈希表(散列表)

哈希表是一种基于哈希算法实现的数据结构,也称为散列表。哈希表通过将元素的关键字映射到表中一个位置来支持高效的元素查找、插入和删除操作。哈希表通常由数组和哈希函数两部分组成。数组用于存储元素,哈希函数则将元素的关键字映射到数组中一个位置。

哈希表的查找操作非常快速,因为不需要对所有元素进行遍历,只需要先通过哈希函数计算出元素在数组中的位置,然后直接访问该位置即可。哈希表支持的插入和删除操作也非常高效,通常只需要做一次哈希计算和一次数组访问。

然而,哈希表的性能也受到哈希冲突(多个元素被映射到同一个位置)的影响。为解决哈希冲突,通常会使用一些常用的解决方法,比如开放地址法和链表法。

哈希表在现实中有广泛的应用,比如编译器符号表、字典、缓存、数据库索引等。哈希表不仅具有高效的数据操作特性,还具有空间效率高、易于扩展、支持动态增删的优点。

哈希表组成:

哈希表由两部分组成:数组和哈希函数。

  • 1. 数组:哈希表通常由一个数组来实现,它用于存储元素。数组的大小取决于哈希表需要存储多少元素。
  • 2. 哈希函数:哈希函数是将元素关键字转换为数组下标的映射函数。哈希函数的设计非常关键,因为它的好坏直接影响哈希表的性能。哈希函数应该能够将关键字均匀地散布到数组中,并且产生最小的冲突。

除了数组和哈希函数,哈希表还可能包含链表(或其他数据结构),用于解决哈希冲突。基于链表的哈希表通常称为哈希链表,当多个元素被哈希到同一个数组下标时,它们可以被放置在同一个链表中。

需要注意的是,哈希表并不保证元素的顺序,因此在使用哈希表时,不能依赖元素的顺序,而是要根据元素的关键字来进行数据操作。

哈希表实例:

在这里我们用实图解决一下什么是用链表解决的哈希值:
假设我们需要存储各种动物下的蛋需要我们归类,我们一般会想直接用数组存储:

但是这就有一个问题:每一次寻找蛋都需要我们遍历数组,因为我们并不知道哪一个下标存储的是哪一个蛋。

这个时候有的聪明的人就提出了:那我记忆一下不就好了,0是鸡蛋,1是乌龟蛋,2是鸵鸟蛋。。。。。我们下次找蛋的时候直接查询一下这个记录,不就不用遍历数组了,也就是我下次要找乌龟蛋,我就直接找乌龟蛋的记录:乌龟蛋的对应的下标是1,那我直接提取数组中下标是1的蛋不就好了。

而这种把一个文本转化成为另外一个文本,方便我们使用的过程,就是哈希

但是如果再下一个鸡蛋呢?它不就与第一个位置的鸡蛋冲突了?我们把这种冲突叫做哈希冲突(哈希冲突是指多个不同的元素被哈希函数映射到同一个数组下标的情况)

解决哈希冲突的方法主要有以下两种:

1. 链表法:将哈希表中冲突的元素放在同一个桶(数组位置)下,并通过链表(或其他数据结构)进行连接。当查询元素时,首先使用哈希函数计算出元素对应的桶,然后遍历该桶中的链表,找到对应的元素。链表法可以解决冲突,但在链表过长时查找效率会降低。

2. 开放地址法:在发生哈希冲突时,通过重新计算哈希函数并找到下一个可用的桶。不同的开放地址法有不同的决策方法来决定下一个可用的桶,比如线性探测、二次探测和双重哈希等。开放地址法相对于链表法来说,具有更好的内存缓存性能,但适用于装载因子比较小(大于0.7时,性能开始下降)的哈希表。

一些其他的解决哈希冲突的方法还包括:再哈希法、伪随机序列法、公共溢出区法等。这些方法各有优缺点,选择合适的解决哈希冲突的方法需要根据实际应用场景和数据规模进行权衡。

链表法:

但是用链表来解决哈希冲突也有一定的危险性:可能会出现数据都集中在几个链上的情况,那么哈希表快速查找的功能岂不是基本丧失了?因此在实际开发中我们不会使用这种方法进行存储。

 开放地址法:
如果此时在下一个蛋,这个蛋的位置上已经有旧蛋了,那么我们就再找一个空间就好了。

不过这种方法还是会让相同的数据聚集在一起,因此我们的开放地址法这个寻址的过程,我们又设计了二次探测方法。

以上只是一个演示,让我们更好的理解哈希函数,但实际生活中我们通常不会以汉字这种形式来做哈希函数的结果。

哈希函数:

哈希函数是哈希表存储和查找的核心,它的好坏决定了哈希表的性能。一个好的哈希函数应该具有以下特点:

1. 高效:哈希函数的计算速度应该非常快,否则就会降低哈希表的性能。
2. 均匀:哈希函数应该将元素的关键字均匀地散布到哈希表中不同的数组下标中,以避免哈希冲突。
3. 独特:哈希函数计算出来的哈希值应该尽可能的独特,以防止不同元素在哈希表中映射到同一个数组下标,并且哈希冲突的概率要尽可能小。

如果哈希函数设计得好,就可以在常数时间内计算出对应元素的哈希值,并将元素存储到相应的位置中。而如果哈希函数不好,就可能导致冲突严重、存储效率低下,或者查询、插入或删除元素的性能变得非常低。

在实际应用中,哈希函数也需要考虑到哈希表的负载因子、元素的数据类型和数据分布等因素。一些常见的哈希函数包括:简单取模法、乘法哈希法、SHA哈希法等。

1. 简单取模法:这是一种最简单的哈希函数,它的计算公式是将元素关键字除以哈希表的大小,然后将余数作为该元素的哈希值。简单取模法的优点是计算速度快,但如果哈希表的大小和元素的数目不匹配,就容易产生哈希冲突。为了减少冲突,在选择哈希表的大小时应该选择一个质数。

2. 乘法哈希法:这种哈希函数计算元素哈希值的公式是:h(k) = floor(m * (kA mod 1)),其中k是元素关键字,A是一个介于0和1之间的常数,m是哈希表的大小,"floor"表示向下取整。这种方法相对于简单取模法来说,生成的哈希值更加分散,冲突率更低。

3. SHA哈希法:SHA(Secure Hash Algorithm,安全哈希算法)是一种加密哈希函数,通常用于对数据进行不可逆的加密处理。SHA算法产生的哈希值通常是固定长度的,同时它生成的哈希值是基于输入数据唯一的,即使输入数据稍有变化,也会产生截然不同的哈希值。基于SHA哈希函数的哈希表在安全性和随机性方面都具有很好的性质,但计算相对较慢,不适用于哈希表中元素较多的情况。

TIPS:

虽然我们把一个数字经过哈希加密之后无法逆向得到原来的数字,但是我们还是可以通过撞库的方式来得到这个数字(这里我们采用的是SHA256加密):

撞库这种手法很简单,就是暴力测试,就好比你想蹭到邻居家里的WIFI,那么你就有两种方式:1.直接去要密码。2.暴力测试,尝试所有可能的密码,直到密码正确为止。

而这种暴力测试所有密码,就是撞库。

加密后:

不断进行撞库:

也就是说虽然我们没有办法通过已经加密后的字符串来解密出数字1234,但是我们可以不断的实验所有的数字,肯定能够找到一个加密串跟这个串相等,那么我们就得到了密码。

总结

哈希算法是一个归类的算法,而由它组建起来的哈希表更是一个极其重要的数据结构,在很多高级语言中都有实现,因此我们要掌握好他的底层原理,才可以更好的运用这种数据结构形式。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

【夜深人静写数据结构与算法 | 第八篇】哈希算法与哈希表相关推荐

  1. 数据结构与算法--第17篇(查找算法)

    数据结构与算法 一,查找算法 1,简介: 2,顺序查找: 3,二分查找: 4,插值查找: 5,斐波那契(黄金分割法)查找: 一,查找算法 1,简介: 查找算法:常分为四种: 顺序查找(线性查找): 二 ...

  2. 算法笔记--八个常见排序算法总结

    一. 分类描述 1. 插入排序 直接插入排序:算法简单,稳定,适用于数据量小的情况 希尔排序:直接插入排序的改进版,不稳定,对于待排序序列的不同情况效率相近 2. 交换排序 冒泡排序:算法简单,稳定, ...

  3. 【手写 Vue2.x 源码】第二十八篇 - diff 算法-问题分析与 patch 优化

    一,前言 首先,对 6 月的更文内容做一下简单回顾: Vue2.x 源码环境的搭建 Vue2.x 初始化流程介绍 对象的单层.深层劫持 数组的单层.深层劫持 数据代理的实现 对象.数组数据变化的观测 ...

  4. 【数据结构与算法】第二篇:算法部分

    系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录 前言 一.程序的时间和空间复杂度分析 (1)理解算法时间复杂度的表示法 ( ...

  5. Interview:算法岗位面试—上海某公司算法岗位(偏机器学习,互联网金融行业)技术面试考点之数据结构相关考察点—斐波那契数列、八皇后问题、两种LCS问题

    ML岗位面试:上海某公司算法岗位(偏机器学习,互联网金融行业)技术面试考点之数据结构相关考察点-斐波那契数列.八皇后问题.两种LCS问题 Interview:算法岗位面试-上海某公司算法岗位(偏机器学 ...

  6. 【数据结构与算法】起始篇

    持续学习&持续更新中- 守破离 [数据结构与算法]起始篇 什么是数据结构和算法 什么是数据结构 什么是算法 为什么要学习数据结构和算法1 为什么要学习数据结构和算法2 为什么要学习数据结构和算 ...

  7. 《夜深人静写算法》总纲

    文章目录 <夜深人静写算法>总纲 零.十年磨一剑 一.动态规划 二.图论 三.数论 四.计算几何 五.字符串匹配 六.高级数据结构 七.杂项算法 <夜深人静写算法>总纲 零.十 ...

  8. 数据结构与算法 / 回溯算法(八皇后、0 - 1 背包)

    回溯算法,顾名思义,就是在没有得到最优解的前提下,不断的返回至前面的岔路口位置,重新选择,直至遍历了所有的情况或者得到的预期最优解的情况下再结束. 与贪心算法不同的是,回溯算法理论上是可以得到最优解, ...

  9. 从零开始写项目第八篇【将未完成的项目发布在Tomcat上】

    tags: 从零开发项目, title: 从零开始写项目第八篇[将未完成的项目发布在Tomcat上] 将项目打包成war包 我使用的是Maven来构建项目的,因此打war包也是非常方便的. 参考链接: ...

最新文章

  1. pytest_01-环境准备与入门
  2. 如何禁用win7的ASLR
  3. 总结 | “卷积”其实没那么难以理解
  4. 又拍云 php5月18号那,又拍云每月免费CDN空间和流量
  5. 等保2.0标准发布一周年,行业用户如何有效落实合规建设
  6. 12.整数转罗马数字-LeetCode
  7. excel中如何批量将所有的网址设为超链接
  8. robots笔记以免忘记
  9. postman传各种类型的数组格式
  10. realme系统服务器代码,解锁BL之后,Realme正式开放源代码
  11. 有关电脑新手入门教程,电脑入门基础知识有哪些?
  12. 机器学习-随机森林之回归
  13. 批处理 使用Win7照片查看器
  14. 关于格林尼治时间(GMT)和DateTime相互转换的分享
  15. linux tc 限制带宽,使用TC 对LINUX服务器网卡进行带宽限制的办法
  16. 基于asp.net车辆管理调度系统的设计与实现
  17. 学习编程,应该从哪里开始学习呢?
  18. 【软考笔记】1. 计算机原理与体系结构
  19. redis expire key 过期不删除
  20. 华为ac控制器web配置手册_31、堂堂华为企业级AP怎么还不如家用TP的速度”快“呢?(优化篇)...

热门文章

  1. linux下删除木目录的方法,rmdir/rm删除目录的区别
  2. 在RadASM中导入masm32项目和win32汇编odbc示例
  3. 基于FPGA的DPSK/QPSK调制
  4. excel处理几十万行数据_excel中十多万条数据应如何处理?
  5. android 类微信相册
  6. linux组播程序收包丢帧,Linux KVM SRIOV欺骗数据包丢帧
  7. EV代码签名证书是什么?和单位代码签名证书有何不同?
  8. light动名词_初中英语语法学习:动名词专项训练
  9. 人工智能焦虑:从起跑线上开始的AI教育
  10. c语言半壁江山回调函数,2021福建事业单位考试综合应用能力试题(C类):拿下“综合C”半壁江山...