HASH索引,AVL树,B树,B+树的区别?

news2025/5/21 7:27:39

1. 什么是 Hash

1.1 Hash 函数

Hash 本身其实是一个函数,又被称为散列函数,它可以大幅提高我们对数据的检索效率。因为它是散列的,所以在存储数据的时候,它也是无序的。

Hash 算法是通过某种确定性的算法(例如MD5,SHA1,SHA2,SHA3)将输入转变成输出,相同的输入结果永远会得到相同的输出。

1.2 Hash 碰撞

熟悉Java中 HashMap 的同学应该都知道,我们在往Map集合中存放元素的时候,它会先对要往集合中存放的元素的key值做一个哈希运算,从而确定它要存入的位置。理论上每一个对象都会存放在不同的地方,但当存放的对象越来越多时,有可能后来添加的元素的key值计算得出的结果与之前已经存入的元素的key的哈希值相等,这种现象就被称为哈希碰撞。当产生哈希碰撞的时候,我们会将后添加的元素与之前就已经存在的元素形成一个链表,当再次发生哈希碰撞时,就继续在链表尾部添加即可。

如下图所示,我们也可以采取这种方式将数据库中的数据以哈希的方式存储到哈希表中,可以看到h(k2)与h(k5) 就产生了哈希碰撞。

1.3 HashMap 的时间复杂度

我们知道,HashMap 其实就是一个数组,它是有下标的,我们在 查询/删除/修改 元素的时候,都可以直接通过哈希函数计算出来的哈希值精确到某个元素的位置,这里我们不考虑哈希碰撞形成的链表,因此 HashMap 的查询/删除/修改 元素的时间复杂度都是O(1),也就是常量级别的,可以说是非常非常快。

2. AVL树

2.1 简单了解AVL树

AVL树,其实也叫平衡二叉树,或叫平衡二叉搜索树,它通常满足一个特点,左子节点的值都比父节点小,右子节点的值都比父节点大,如下图所示

在这种情况下,我们去寻找数据91,只需要查找三次即可得出结果。

2.2 AVL树的时间复杂度

从上面我举得例子不难看出,在AVL树中查找数据时,每查找一次,砍掉一半的数据,再查找一次,再砍掉一半的数据,所以不难看出,AVL树的时间复杂度是 O(log2n)。

2.3 AVL树的缺点

AVL树时间复杂度虽然低,但也存在一些缺点,因为AVL树要保持高度的平衡,所以需要经常性旋转,旋转也是非常耗费时间,并且,随着数据越来越多,AVL树的深度也会越来越大,如下图所示,当数据达到31个的时候,树的高度已经有5层了。我们知道,每多一层,与磁盘就要多进行一次IO操作,非常耗费时间,所以我们就在想,能不能把树的高度降低一些,但同时又能存足量的元素呢?这就有了下面要说M叉树,也可以理解为B树。

3. B 树

经过了上面对AVL树的分析,我们也知道了,当树的叉越多时,存储的数据也越多,与磁盘交互的次数也越少,我们把上方的二叉树转换成三叉树,当然也可以转换成四叉树,五叉树都是可以的,这里我就以三叉树为例。

这个时候,我们还是能存储31个元素,并且树的高度由原来的5层降低到了4层,提高了我们数据的查找效率,这就是我们索引的雏形,我们就可以将数据库中的数据存储在树中,得到如下简易模型

上图中就是索引最开始形成的B树结构图,左上角也有标注,这个时候我们可以看到,在原始B树中,磁盘块1234这几个非根节点中还存放着数据呢,P1是地址值指向磁盘块2,并且里面记录的主键值都是小于26的;P3是地址值指向磁盘块4,里面记录的数据主键值都是大于35的;P2是地址值指向磁盘块3,里面记录的数据主键值都是在26与35之间的。下方的磁盘块2,3,4中都是同理,依次往下类推。

这种数据的存储方式和查找方式性能已经非常优秀了,但是还有一个缺点,我们将原来的2叉树转变成M多叉树,目的就是为了存储更多的数据,但大家看,在磁盘块2,3,4中,P1,P2,P3都是指针,不会占用多少空间,但8和12的data存储的是真实的数据,会占用部分磁盘空间,而且这个时候还有分成了三段,如果分的段更多,也会存储更多的数据,这就会导致我们无法存储更多的指针数据,违背了我们的初衷。于是,我们就可以对这个B树做进一步的升级(当然也不只是因为这一个原因,后面我们还会说到,这里先说这一点就)演化成了我们现在的 B+ 树结构。

4. B+ 树

如上图所示,就是从B树演化形成的 B+ 树,在 B+ 书中,我们舍弃了B书中非叶子节点也存储真实数据做法,将所有的真实数据全部存放在叶子节点中,这样我们的目录页就可以存放更多的指针数据。并在每一页都会添加一个数组,数组中记录着该页中的所有元素并按照从小到大的顺序排列。

例如上图,顶层目录页33记录了数据1,320,下方对应着页30与页33的地址值;中间目录页30中存储着 1,5,12,209,数据下方各自对应着该页的地址值;当我们想要查找(100,9,x)这条数据时,做判断,发现(100,9,x)的相关信息应存储在中间页30中,在进入中间页30寻找,经过判断发现该数据存放在页9中,根据对应的地址值找到页9,然后在页9中就可以获取到数据(100,9,x)了,不管查询那个数据,都是这样的一个过程,查询速度非常稳定,并且中间目录页不存储真实数据只存储地址值,可以存储更多的叶子节点页数据。

5. 为什么不采用哈希表存储数据呢?

这其实是一个面试题,刚才我们也分析过了,哈希表的时间复杂度为O(1),常量级别,是最快的,那么数据库存储数据时为什么不采用哈希表的形式存储呢?原因有以下几点:

(1)范围查找显得无力

如果我们采用哈希表的结构存储,你会发现,它只能满足我们对精准值得查找,当我们在数据库中加入了BETWEEN...AND...或IN这些范围查找关键字的时候,哈希表就没有优势了,而且哈希表还是乱序的,这就导致我们在进行范围查找时,时间复杂度为会从O(1)退化成O(n),而我们的树形结构时间复杂度稳定在O(log2n),这个时候我们就会发现,哈希表就没有优势了。

(2)排序浪费时间

因为哈希表是乱序存储,当我们需要进行ORDER BY 的时候,每次ORDER BY底层都要排一次序,而我们的树形结构在存储是就是有序的,不管什么时候取数据都省去了排序的时间。我们存储。

(3)不太支持联合索引

我们知道,B+树中是支持联合索引的,并会对多因进行排序,如果我们使用哈希表存储数据,当我们将字段C1与字段C2联合作为主键时,哈希存储就会把C1和C2作为一个整体计算哈希值,不会单个做哈希值计算。这样就乱套了,因为两个不一样的字段加在一起哈希值是可能相同的。

(4)索引列重复时效率低

我们知道计算哈希值就是为了避免哈希碰撞,如果一些字段肯定会出现碰撞,例如性别,年龄这些字段,那么哈希碰撞的概率就会非常大,它会遍历哈希桶中的每一个元素作比较,非常耗时,所以哈希索引通常不会用在容易出现重复的字段上。

6. 自适应 Hash 索引

在 InnoDB 引擎中,虽然本身不支持哈希索引,但是它提供了一个自适应的哈希索引,这个是默认开启的,当我们经常性地对数据库中的同一些数据做查询操作时,它就会将这些数据存放到哈希表中,以便我们以后更加快速的查找。

经过自适应哈希索引优化之后,之前我们需要进行一层层目录的查找,但是哈希表就可以让我们一步到位,省去检索的时间。

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

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

相关文章

恢复删除的文件,3个宝藏恢复方法分享!

在对电脑的操作过程中误删了文件怎么办?删除的文件还可以恢复吗?快救救孩子吧!一大堆重要文件被不小心删除了,真的很无助啊!” 在电脑逐渐成为人们工作和生活不可缺少的工具时,存储和删除文件也变得更为方便…

自动化安装系统(二)

利用PXE实现自动化安装 PXE简介 PXE:Preboot Excution Environment,预启动执行环境,是由Intel公司研发,基于Client/Server的网络模式,支持远程主机通过网络从远端服务器下载映像,并由此支持通过网络启动操…

iOS textView支持超链接跳转

将某些文字变成高量可以点击的超链接核心功能代码 attri.addAttribute(NSAttributedString.Key.link, value:NSURL.init(string: "dctt:p/userPrivacy.html")!, range: NSRange.init(location: s.count - 4, length: 4) )textView.linkTextAttributes [NSAttributed…

解密 AI 客服;在不同硬件设备上运行大型语言模型的可能性

🦉 AI新闻 🚀 微软必应首席执行官称必应聊天优于OpenAI的GPT-4,但成本更高 摘要:微软必应的首席执行官米哈伊尔・帕拉欣表示,必应聊天表现优于OpenAI的GPT-4,但使用了更高成本的检索增强推理技术。必应聊…

C语言的使用技巧--在IO操作中的移位和快速配置

在WB32F103(ARM cortex m3内核,96Mhz)的gpio初始化中有一段代码,充分的结合了硬件特征并使用C语言的技巧来快速的配置对应的GPIO的功能,堪称经典和楷模,代码异常简洁,执行速度快,配置…

【Qt6】QWindow类可以做什么

原来的水文标题是“用 VS Code 搞 Qt6”,想想还是直接改为“Qt6”,反正这个用不用 VS Code 也能搞。虽然我知道大伙伴们都很讨厌 CMake,但毕竟这厮几乎成了 C 的玩家规范了。Qt 也算识大体,支持用 CMake 来构建程序。所以&#xf…

“心理健康人工智能产学研创新联盟”揭牌成立|深兰科技

8月14日上午,“2023树洞救援年会”在上海举行,会上举行了“心理健康人工智能产学研创新联盟”的签约和揭牌仪式。“树洞行动救援团”创始人深兰科技科学院智能科学首席科学家、荷兰阿姆斯特丹自由大学人工智能系终身教授黄智生,深兰科技集团创…

ElementUI 树形表格的使用以及表单嵌套树形表格的校验问题等汇总

目录 一、树形表格如何添加序号体现层级关系 二、树形表格展开收缩图标位置放置,设置指定列 三、表单嵌套树形表格的校验问题以及如何给校验rules传参 普通表格绑定如下:这种方法只能校验表格的第一层,树形需要递归设置子级节点prop。 树…

RFID如何在汽车混流生产中进行车辆跟踪?

在汽车混流生产中,RFID技术可以对每个车辆进行唯一标识,从而实现车辆生产全程跟踪。实时确定车辆的位置、状态和生产过程,生产管理系统就能够对生产流程进行实时监控和管理,及时发现和解决问题,提高生产效率和质量。 焊…

SpringBoot之HandlerInterceptor拦截器的使用

😀前言 本篇博文是关于拦截器-HandlerInterceptor的使用,希望你能够喜欢 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动…

对发卡涡(Hairpin vortex)初步认识

对发卡涡(Hairpin vortex)初步认识 Hairpin vortex是一种在流体动力学中常见的涡旋结构。它通常形成在流体中的强烈剪切区域,例如在河流、管道或飞机翼等流体流动中。Hairpin vortex的形状类似于一个发夹弯曲的形状,因此得名&…

(7)(7.1) 使用航点和事件规划任务

文章目录 前言 7.1.1 设置Home位置 7.1.2 视频:制作并保存多路点任务 7.1.3 视频:加载已保存的多航点任务 7.1.4 使用说明 7.1.5 提示 7.1.6 自动网格 7.1.7 任务指令 7.1.8 任务结束 7.1.9 任务重置 7.1.10 MIS_OPTIONS 7.1.11 任务再出发 …

【三维重建】【深度学习】【数据集】基于COLMAP制作自己的NeuS(DTU格式)数据集

【三维重建】【深度学习】【数据集】基于COLMAP制作自己的NeuS(DTU格式)数据集 提示:最近开始在【三维重建】方面进行研究,记录相关知识点,分享学习中遇到的问题已经解决的方法。 文章目录 【三维重建】【深度学习】【数据集】基于COLMAP制作自己的NeuS(DTU格式)数据集前言下载…

浅析3D打印技术

目录 1.3D打印的概念 2.3D打印的发展过程 3.3D打印的应用领域 4.3D打印带来的技术变革 1.3D打印的概念 3D打印是一种制造技术,它使用逐层堆叠材料的方式来创建物体。与传统的加工方法相比,3D打印具有很多优势。 在3D打印中,一种叫做CAD&am…

深度解读智能化编码的技术架构与实践案例

向更智能、更兼容演进。 陈高星|演讲者 大家好,我是阿里云视频云的陈高星,今天和大家分享的主题是“多”维演进:智能化编码架构的研究与实践。 本次分享分为四部分:首先是视频编码与增强方向的业界趋势,其…

Apple Watch 9和Apple Watch 8功能差异对比:预期升级浅析

每年的这个时候,我们都会想知道Apple Watch Series 9和Apple Watch Series 8之间会有什么不同。随着苹果下一代智能手表预计将于9月上市,我们渴望了解该公司即将进行的升级。 Apple Watch Series 8是目前最好的智能手表,但根据Apple Watch Series 9的改进,它可能会成为我们…

为什么C语言全局变量初始化元素必须是常量,而局部变量可以不是常量

前言 &#xff08;1&#xff09;今天看到一个有意思的问题&#xff0c;在交流群中&#xff0c;一位网友问&#xff0c;全局变量为什么不能给变量。会出现initializer element is not constant报错&#xff0c;代码如下 #include <stdio.h>int a 1; int b a1; //这里会报…

Zabbix-6.4.4 邮箱告警SMS告警配置

目录 ​------------------------- # 邮箱告警 ---------------------------------- 1.安装mailx与postfix软件包 2.修改mailx配置文件 3. 创建文件夹 4. 编写mail-send.sh脚本 5. 将该脚本赋予执行权限 6. 进入web界面进行设置—> Alerts —> Media Types 7. 添…

C++11并发与多线程笔记(3)线程传参详解,detach()大坑,成员函数做线程函数

C11并发与多线程笔记&#xff08;3&#xff09;线程传参详解&#xff0c;detach 大坑&#xff0c;成员函数做线程函数 1、传递临时对象作为线程参数1.1 要避免的陷阱11.2 要避免的陷阱21.3 总结 2、临时对象作为线程参数2.1 线程id概念2.2 临时对象构造时机抓捕 3、传递类对象…

数据结构算法--3快速排序

快速排序比冒泡排序&#xff0c;选择排序&#xff0c;插入排序速度都快 快速排序思路&#xff1a; ^取一个元素P&#xff0c;(第一个元素)&#xff0c;使元素P归位。 ^列表被P分成了两部分&#xff0c;左边都比P小&#xff0c;右边都比P大。 ^递归完成排序。 过程: 把5拿出…