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

news2024/12/30 1:41:51

目录

前言:

哈希: 

哈希表:

哈希表组成:

哈希表实例:

哈希函数:

 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,但是我们可以不断的实验所有的数字,肯定能够找到一个加密串跟这个串相等,那么我们就得到了密码。

总结

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/675624.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jenkins安装手册

Jenkins安装手册 一、前期准备工作 因为我是在Windows系统上连接Linux服务器以及需要把在Windows系统下载的安装包上传到Linux系统,所以需要用到两个工具---putty 和FileZilla。 Putty是一个免费的、Windows 32平台下的telnet、rlogin和ssh客户端,但是…

IDEA新UI速览,成了VS Code的样子?

IntelliJ IDEA 2023.1 现已发布。此版本包括对新 UI 的改进,根据从用户那里收到的反馈进行了彻底改造。此外还实现了性能增强,从而在打开项目时更快地导入 Maven 和更早地使用 IDE 功能。由于采用了 background commit checks,新版本提供了简…

【首发】随身wifi编译/使用ffmpeg方法,包含openwrt和debian

目录 1.硬件改造 2.软件改造 3.下一步计划 背景是23年4月入了随身wifi的坑后,发现除了硬件上的改造,软件的可玩性也很大,网上可以找到不少打印机,直播推流,甚至家庭智能硬件的改造教程。笔者是因为改造遥控小车&…

【前端】Element-UI和Element-Plus的区别

文章目录 对移动端支持区别框架区别开发中使用的区别el-tableel-dialogel-buttonel-date-pickerel-iconechartsIcon图标库变化了组件的插槽slot使用变化了新增组件 来源 对移动端支持区别 Element-UI对应Element2:基本不支持手机版 Element-Plus对应Element3&…

chatgpt赋能python:Python生成A到Z的SEO

Python 生成A到Z的SEO Python 是一种简单易学、功能强大的编程语言,它不仅可用于数据分析、机器学习等领域,还可以用于 SEO 工作中的自动化。在 SEO 中,我们常需要生成不同字母序列来作为页面的标题标签(Title Tag)&a…

Unencode

打开得到一串密文,看题目形式应该也是一个编码格式 果然是,直接利用网上工具解码就得到flag Uuencode编码 稍微了解了一下Uuencode编码的方式: Uuencode是二进制信息和文字信息之间的转换编码,也就是机器和人眼识读的转换。Uuenco…

从MVC到MVVC:软件架构的演变和迭代

文章目录 1.引言介绍MVC和MVVC架构1. MVC架构2. MVVC架构 2.MVC架构什么是MVC架构MVC的组成部分及其作用1. 模型(Model)2. 视图(View)3. 控制器(Controller) MVC的优点和缺点 3.MVVC架构什么是MVVC架构1. 模型(Model)2. 视图(View)3. 视图模型(View Model) MVVC的组成部分及其作…

2022(一等奖)B22基于时空大数据的多维分析与传统二维分析相结合的大气污染变化研究方法探索

作品介绍 1 作品背景及研究对象 1.1 背景及必要性介绍 2022年春节期间,山东及多地的部分省市明确了禁放烟花爆竹的规定,直接表明了当今大气污染变化的严峻形势,燃放烟花爆竹会严重影响空气环境质量,加剧雾霾天气,产生…

【Linux】CentOS7 设定虚拟机时间为本机当前地区时间的简单操作

目录 情景系统环境操作 情景 新安装的虚拟机时间和当前本地系统时间不一致,现在想要将虚拟机和本机地区的时间调节为一致。 系统环境 CentOS Linux 7 系统界面大致如此。 操作 点击虚拟机界面左上角的 Applications 选项, 选择System-Tools-- Sett…

熵、KL散度和交叉熵

首先我们需要知道,所有的模型都可以看作是一个概率分布模型,包括人脑进行图像分类时也可以看作是一种完美的模型 1、信息量 如果学过通信应该知道香农定义了信息量的的概念,我们能够理解一件事情信息量很大或者很小,但是如何用数…

操作系统 - 进程和线程

✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。 🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心&…

陈香菲九价疫苗接种sop

前文 什么时间 正常时间 ● 正常接种按照接种时间,需要在2023-06-28 08:00-17:00 前往指定卫生院预防接种门诊进行接种。 时间异议 ● 正常来说如果接种时间内来大姨妈或者最近有服用一些药物的话是不能进行接种的,具体药物品…

chatgpt赋能python:Python爬虫防屏蔽策略及技巧

Python爬虫防屏蔽策略及技巧 介绍 爬虫作为一种数据采集工具,越来越广泛地应用于众多领域,包括搜索引擎优化(SEO)、产品分析、市场调研等等。然而,随着爬虫数量的不断增加,许多网站已经采取了多种方法来屏…

【Spring Cloud Stream 消息驱动】 —— 每天一点小知识

💧 S p r i n g C l o u d S t r e a m 消息驱动 \color{#FF1493}{Spring Cloud Stream 消息驱动} SpringCloudStream消息驱动💧 🌷 仰望天空,妳我亦是行人.✨ 🦄 个人主页——微风撞见云的博客&#x1f390…

ECharts数据可视化

目录 第一章 什么是ECharts 第二章 搭建环境 2.1 Echarts的下载 2.2 Visual Studio Code下载 第三章 一个简单的可视化展示 第四章 Echarts组件 4.1 标题 4.2 提示框 4.3 工具栏 4.4 图例 4.5 时间轴 4.6 数据区域缩放 4.6.1 滑动条型数据区域缩放 4.6.2 内置型…

chatgpt赋能python:烧录单片机程序:Python的力量

烧录单片机程序:Python的力量 随着技术的发展和人类渴求的不断追求,电子设备的普及程度越来越高。在一个电子设备内部,单片机的应用非常广泛。然而,单片机作为计算机的重要组成部分,也需要相对应的程序来实现不同的功…

实战:Gradle构建工具实践-2023.6.22(测试成功)

实战:Gradle构建工具实践-2023.6.22(测试成功) 目录 推荐文章 https://www.yuque.com/xyy-onlyone/aevhhf?# 《玩转Typora》 实验环境 gitlab/gitlab-ce:15.0.3-ce.0 jenkins/jenkins:2.346.3-2-lts-jdk11 gradle-7.6.1 openjdk 11.0.18实验软件 链接&#xff1…

x-s参数逆向

x-s参数逆向[2023.6.22] 1.提要 众所周知,此次的加密逻辑进入一个叫window._webmsxyw()的函数里面 该函数是封装在一个自执行函数内部,并添加到了window属性里,下面是两种获取思路。 2.扣环境 扣环境的话,只需要在jsdom的docu…

内存耗尽后Redis会发生什么?

作为一台服务器来说,内存并不是无限的,所以总会存在内存耗尽的情况,那么当 Redis 服务器的内存耗尽后,如果继续执行请求命令,Redis 会如何处理呢? 内存回收 使用Redis 服务时,很多情况下某些键…

2023 node 接入腾讯云短信服务,实现发送短信功能

1、在 腾讯云开通短信服务,并申请签名和正文模板 腾讯云短信 https://console.cloud.tencent.com/smsv2 a、签名即是短信的开头。例如 【腾讯云短信】xxxxxxx; b、正文模板即短信内容, 变量部分使用{1}, 数字从1开始累推。例如&a…