文章目录

  • 一、二叉查找树(BST):不平衡
  • 二、平衡二叉树(AVL):旋转耗时
  • 三、红黑树:树太高
  • 由一个例子总结索引的特点
  • 基于哈希表实现的哈希索引
  • 高效的查找方式:二分查找
  • 基于二分查找思想的二叉查找树
  • 升级版的BST树:AVL 树
  • 四、B树:为磁盘而生
    • 让我们从空的5阶B-Tree开始,按照顺序插入这些数字:3, 8, 31, 11, 23, 29, 50, 28, 1, 2。
    • 删除操作
    • 总结
    • 下图是一个3阶B树的例子
  • 五、B+树
    • 构建B+树
    • 删除
  • 六、感受B+树的威力
    • B+ 树和 B 树的区别?
    • 为什么 B+ 树比 B 树更适合应用于数据库索引?
  • 七、总结

在MySQL中,无论是Innodb还是MyIsam,都使用了B+树作索引结构(这里不考虑hash等其他索引)。本文将从最普通的二叉查找树开始,逐步说明各种树解决的问题以及面临的新问题,从而说明MySQL为什么选择B+树作为索引结构。

一、二叉查找树(BST):不平衡

二叉查找树(BST,Binary Search Tree),也叫二叉排序树,在二叉树的基础上需要满足:任意节点的左子树上所有节点值不大于根节点的值,任意节点的右子树上所有节点值不小于根节点的值。如下是一棵BST
在这里插入图片描述
当需要快速查找时,将数据存储在BST是一种常见的选择,因为此时查询时间取决于树高,平均时间复杂度是O(lgn)。然而,BST可能长歪而变得不平衡,如下图所示,此时BST退化为链表,时间复杂度退化为O(n)
在这里插入图片描述

为了解决这个问题,引入了平衡二叉树。

二、平衡二叉树(AVL):旋转耗时

AVL树是严格的平衡二叉树,所有节点的左右子树高度差不能超过1;AVL树查找、插入和删除在平均和最坏情况下都是O(lgn)。

AVL实现平衡的关键在于旋转操作:插入和删除可能破坏二叉树的平衡,此时需要通过一次或多次树旋转来重新平衡这个树。 当插入数据时,最多只需要1次旋转(单旋转或双旋转)但是当删除数据时,会导致树失衡,AVL需要维护从被删除节点到根节点这条路径上所有节点的平衡,旋转的量级为O(lgn)。

由于旋转的耗时,AVL树在删除数据时效率很低;在删除操作较多时,维护平衡所需的代价可能高于其带来的好处,因此AVL实际使用并不广泛。

三、红黑树:树太高

与AVL树相比,红黑树并不追求严格的平衡,而是大致的平衡:只是确保从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。从实现来看,红黑树最大的特点是每个节点都属于两种颜色(红色或黑色)之一,且节点颜色的划分需要满足特定的规则(具体规则略)。红黑树示例如下:

对红黑树不了解的可以看红黑树的创建
在这里插入图片描述

在这里插入图片描述

与AVL树相比,红黑树的查询效率会有所下降,这是因为树的平衡性变差,高度更高。但红黑树的删除效率大大提高了,因为红黑树同时引入了颜色,当插入或删除数据时,只需要进行O(1)次数的旋转以及变色就能保证基本的平衡,不需要像AVL树进行O(lgn)次数的旋转。 总的来说,红黑树的统计性能高于AVL。

因此,在实际应用中,AVL树的使用相对较少,而红黑树的使用非常广泛。例如,C++中的map使用红黑树存储排序键值对

对于数据在内存中的情况,红黑树的表现是非常优异的。但是对于数据在磁盘等辅助存储设备中的情况(如MySQL等数据库),红黑树并不擅长,因为红黑树长得还是太高了。当数据在磁盘中时,磁盘IO会成为最大的性能瓶颈,设计的目标应该是尽量减少IO次数;而树的高度越高,增删改查所需要的IO次数也越多,会严重影响性能。

在这里插入图片描述

由一个例子总结索引的特点

加索引是数据库加速查询的一种方式,那么为什么用索引可以加快查询呢?

讲到索引,其实我们经常会听到一个图书馆的例子,图书馆里的书目繁杂,我们如何从若干本书里面找到一本我们想要的书呢?

我们根据图书馆系统检索,可以找到某本书对应的图书编号。

在基于书籍按照一定规则排列的前提下,我们可以根据图书编号找到这本书

例如,假设图书编号根据:

第几个书架 - 书架上第几个格子 - 从左到右数第几个位置

这样的规则编排,

我们就可以轻松的获取到我们想要的书籍。

你也许发现了,这个例子中,藏着两个信息:
在这里插入图片描述

基于哈希表实现的哈希索引

在这里插入图片描述
到这里我们遇到了一个问题,就是哈希表虽然从查找效率上满足了我们查找单个数据的要求,但是显然,当遇到范围查询时,由于哈希表本身的无序性,不利于指定范围查找。

也就是说,我们的需求增加了,我们希望数据的组织方式,既要有一定规则,又要有序。

在引出这种数据结构之前,我们首先来看一种查找方式:二分查找。

高效的查找方式:二分查找

二分查找的核心思想是给定一个 有序 的数组,在查找过程中采用跳跃式的方式查找,即先以有序数列的中点位置为比较对象,如果要查找的元素小于中点元素,则将待查序列缩小为左半部分,否则为右半部分。通过每次比较,将查找区间减少一半,直到找到所需元素。

在这里插入图片描述
在这里插入图片描述

基于二分查找思想的二叉查找树

二叉查找树(Binary Search Tree)即BST树是这样的一种数据结构,如下图:
在这里插入图片描述
在这里插入图片描述
但是当二叉树的构造变成这样时,

在这里插入图片描述
此时我们再查找 8 时,查找效率就沦为接近顺序遍历查找的效率。

显然这不是我们想要的,二叉查找树也需要 balance。

由于树是存储在磁盘中的,访问每个节点,都对应一次磁盘 I/O 操作(假设一个节点的大小「小于」操作系统的最小读写单位块的大小),也就是说树的高度就等于每次查询数据时磁盘 IO 操作的次数,所以树的高度越高,就会影响查询性能。 二叉查找树由于存在退化成链表的可能性,会使得查询操作的时间复杂度从 O(logn) 升为 O(n)。

升级版的BST树:AVL 树

我们对二叉查找树做个限制,限制必须满足任何节点的两个子树的最大差为 1,也是AVL 树的定义,这样我们的查找效率就有了一定的保障。

AVL 树 是一种自平衡二叉查找树(self-balancing binary search tree)。

当然,维护AVL 树也是需要一定开销的,即当树插入/更新/删除新的数据时假设破坏了树的平衡性,那么需要通过左旋和右旋来维护树的平衡。

当数据量很多时,同样也会出现二叉树过高的情况。

我们知道AVL 树的查找效率为 O(log n),也就是说,当树过高时,查找效率会下降。

另外由于我们的索引文件并不小,所以是存储在磁盘上的。文件系统需要从磁盘读取数据时,一般以页为单位进行读取,假设一个页内的数据过少,
那么操作系统就需要读取更多的页,涉及磁盘随机 I/O 访问的次数就更多。

将数据从磁盘读入内存涉及随机 I/O 的访问,是数据库里面成本最高的操作之一。

因而这种树高会随数据量增多急剧增加,每次更新数据又需要通过左旋和右旋维护平衡的二叉树,不太适合用于存储在磁盘上的索引文件。

在这里插入图片描述

四、B树:为磁盘而生

前面我们看到,虽然AVL树既有链表的快速插入与删除操作的特点,又有数组快速查找的优势,但是这并不是最符合磁盘读写特征的数据结构。

也就是说,我们要找到这样一种数据结构,能够有效的控制树高,那么我们把二叉树变成m叉树,也就是下图的这种数据结构:B 树。

B树是一种这样的数据结构:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,B树在保留二叉树预划分范围从而提升查询效率的思想的前提下,做了以下优化:

二叉树变成 m 叉树,这个 m 的大小可以根据单个页的大小做对应调整,从而使得一个页可以存储更多的数据,从磁盘中读取一个页可以读到的数据就更多,随机 IO 次数变少,大大提升效率。

但是我们看到,我们只能通过中序遍历查询全表,当进行范围查询时,可能会需要中序回溯。

让我们从空的5阶B-Tree开始,按照顺序插入这些数字:3, 8, 31, 11, 23, 29, 50, 28, 1, 2。

在这里插入图片描述
对于5阶的B树每个结点最多存储4个key,所以对于3,8,31,11的新增(排序)很好理解
在这里插入图片描述
但是当我们新增23的时候,就会打破这种规则,所以我们需要对结点进行分裂,来保证定义2成立,分裂操作很简单, 将中间元素进行提取,充当父结点,左右元素一分为2,分别充当孩子结点。

在这里插入图片描述
我们继续新增29,50
在这里插入图片描述
新增到28的时候,又会出现分裂的动作,但是与第一次分裂不同,这个时候分裂出来的中间结点需要进行上升,然后左右元素,与父级上升的结点进行关联, 这样才能保证定义5成立:根结点到每个叶子结点的长度都相同

在这里插入图片描述
继续新增1,2

在这里插入图片描述
到这里就新增完成了,可以发现为了保证关键字不超过m-1,需要进行分裂,而分裂的操作需要保证根结点到任意叶子结点距离是相等的

删除操作

相对于新增操作,删除操作比新增要复杂一些,因为新增只涉及到分裂,但是删除会涉及到替换结点,借结点,合并结点等操作。这些操作的目的同样是为了保证结构满足定义

首先看替换结点,当我们要删除非叶子结点的时候,比如图上的29,我们使用它的前继或者后继的结点来替换它,这里前继/后继指的是, 中序遍历结果的前一个/后一个结点,而且在B树中,该结点必然是叶子结点,比如29的前继结点是28,后继结点是31。

当上面替换成功之后,我们就要把当前的叶子结点删掉,删除动作很简单,但是 当我们把关键字删掉之后,需要判断当前结点的关键字是否满足我们所说的至少有Math.ceil(m/2)-1个的要求,如果满足,删除成功,不满足时为了保证 满足这样的条件,我们看看兄弟结点有没有富裕(大于Math.ceil(m/2)-1)的关键字,给他借过来。这一步叫借结点。

那么合并结点就是当兄弟结点不足的时候,我们需要找兄弟结点来进行合并,从而满足B树的定义。

下面具体看下实现过程:
首先我们删除关键字8:因为是叶子结点,且删除后关键字满足 >=Math.ceil(m/2)-1 的条件

在这里插入图片描述

我们继续删除关键字29:首先找到他的前继结点关键字28来替换删除
在这里插入图片描述
删除之后我们会发现当前结点关键字已经不足2了,所以需要借结点或者合并结点,我们会发现,左兄弟结点是富裕的,所以可以向左兄弟结点借关键字。借的过程:父结点下移一个关键字,左兄弟结点上移一个关键字,从而使B树平衡。

在这里插入图片描述

在这里插入图片描述

删完29之后,我们再来删除关键字11,此时兄弟结点没有富裕的关键字来让该结点满足 >=Math.ceil(m/2)-1 的条件,所以需要进行结点合并, 这里我们选择合并左孩子来进行合并合并过程:将父结点关键字下移,到合并结点,失衡的被合并结点关键字插入到合并结点,父结点删除失衡结点。由于父结点是根结点,所以即使一个关键字也符合要求。

总结

在实现B树的过程中,有一点容易让人误解的是孩子结点与父亲结点的关系,实际上孩子是整个结点的孩子,而不是结点某个关键字的孩子。

在这里插入图片描述

但是孩子结点与父亲结点关键字之间是存在一定的关系的,比如父结点有两个关键字,那么就会有三个孩子,而父结点关键字所在的索引序号,比如下标是0, 那么孩子中下标为0的结点所有关键字都会小于父亲结点下标为0的关键字,如下图,这也是为什么使用二分可以找到相应关键字的原因。

在这里插入图片描述

下图是一个3阶B树的例子

在这里插入图片描述
B树的优势除了树矮小,还有对访问局部性原理的利用。所谓局部性原理,是指当一个数据被使用时,其附近的数据有较大概率在短时间内被使用。B树将键相近的数据存储在同一个节点当访问其中某个数据时,数据库会将该整个节点读到缓存中;当它临近的数据紧接着被访问时,可以直接在缓存中读取,无需进行磁盘IO;换句话说,B树的缓存命中率更高。

B树在数据库中有一些应用,如mongodb的索引使用了B树结构。但是在很多数据库应用中,使用了是B树的变种B+树。

五、B+树

基于以上的缺陷,又诞生了一种新的优化B树的树: B+ 树

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

B+树在定义上似乎没有官方的定义,从论坛上看,目前还是对定义存在两点争论:
其一:B+Tree是否B-Tree一样是结点有M-1个关键字拥有M棵子树,还是M个关键字拥有M颗子树。
其二:内部结点的索引值使用最大值还是最小值。

不过上述的争论对于实现并没有大的影响,我们可以自己去定义。所以这里选用百度百科上对B+树的描述:
(1)每个结点至多有m个子女;
(2)除根结点外,每个结点至少有[m/2]个子女,根结点至少有两个子女;
(3)有k个子女的结点必有k个关键字。

下面是实现的树(貌似根结点可以有一个关键字,但是这里还是引用k个子女的结点必有k个关键字 这条逻辑)。
在这里插入图片描述
从上面B+树的图可以看出与B-树相比,非叶子结点不存储数据,仅充当索引结点,其次是所有的数据都存储在叶子结点上, 且叶子结点利用指针形成单链表(双向链表,笔误)。通过这些特征我们可以得知:

  • 1.由于B+树内部结点不存储数据,所以树更加矮,内部结点在相同大小的磁盘页能存储更多,一次性读入内存的关键字也会更多,减少IO操作
  • 2.由于B+树内部结点不存储数据,所以查询全部落入叶子结点,所以相对B树查询更加稳定
  • 3.由于B+树叶子结点使用指针链接成链表,所以相对与B-树,其范围查询更加高效,因为B-树中范围查询 需要对B-树进行中序遍历,所以效率会低

注:B-Tree稳定不代表一定会快,如果是随机访问或者单一查询,有可能B树更快(数据存储在距离根结点越近则越快), 同理IO操作也不一定比B+Tree多。这也是为什么非关系型数据库不选用B+Tree的原因,因为非关系型数据库通常都是单一查询, 不需要遍历匹配。还需要注意的是,B+Tree与B-Tree一样,当按照key值的大小顺序插入分裂时,每个叶子结点的存储效率只有50%,如下图,我们会发现2与3之间不能再插入其他的正整数, 也就造成了空间的浪费

在这里插入图片描述

构建B+树

仍以5阶为例,来构建5阶B+树。通过B+树的定义,我们可以知道,其结点最多有5个关键字,最少有[5/2]=3个关键字。这里假设存储的关键字为3, 8, 31, 11, 23, 29, 50, 28,1, 2,来看如何构建。

首先定义一颗空树,然后依次新增,新增流程如下:依次插入3, 8, 31, 11, 23
在这里插入图片描述

此时结点关键字已经达到M个的要求,如果再继续新增29时,会同B树一样,需要进行分裂。但是与B树分裂存在一些区别, 如下图,关键字上升的过程中,关键字并未从原来的结点中移除(B树中会被移除),其次根结点形成时,上升了两个关键字, 来保证k个子女的结点必有k个关键字的要求(我见到也有根结点有一个关键字的博文,这里感觉不打紧,所以就不纠结), 最后就是叶子结点之间利用形成单向链表

在这里插入图片描述
继续新增50。这一步相对与B树同样存在一些特殊步骤,更新内部的索引结点,插入50之前,31是最大值,索引结点存储11,31表明 目前31对应子树关键字范围在(11,31]之间,但是插入50之后,沿路的索引值也需要进行更新
在这里插入图片描述
最后插入28,1,2,这次插入无需更新沿路的索引结点,因为其并未打破索引的范围规则

在这里插入图片描述
通过新增的流程,我们会发现,相比较B树,插入逻辑要复杂一些。复杂在当插入结点打破索引规则时, 需要更新沿路索引,其次对于分裂的叶子结点需要形成一个单向链表

删除

新增操作之后继续看删除的流程,我们依次删除50,23,28,1,2。

删除50后,虽然结点多于最小关键字个数,但是索引结点的平衡被打破,即不存在50的索引,所以需要更新索引结点。
在这里插入图片描述
删除23的过程中,即没有打破索引,也没有导致结点关键字少于最小关键字个数,所以整棵树并没有大的改动, 但是当我们删除28的时候,结点最关键字小于最小关键字个数。此时就需要借结点或者合并结点。针对删除28,我们会发现,他的左兄弟结点关键字个数大于最小关键字个数,所以可以借用,借用过程:借用左兄弟最大关键字或者右兄弟最小关键字,如果是借用左兄弟,则更新左兄弟对应父结点的索引值(因为最大关键字被借走), 如果借用右兄弟则更新当前结点对应父结点的索引值(因为借过来的肯定比当前索引值大)

在这里插入图片描述
继续删除1,2。在删除2的过程中,结点关键字个数少于最小关键字个数,此时兄弟结点的关键字个数无法外借(因为已经是最少关键字), 此时进行合并,合并流程:如果合并之后根结点孩子不足2,则移除根结点,合并结点充当根结点,如果合并之后,根结点孩子大于等于2, 则将被合并结点对应父结点的索引值移除。

在这里插入图片描述

六、感受B+树的威力

前面说到,B树/B+树与红黑树等二叉树相比,最大的优势在于树高更小。实际上,对于Innodb的B+索引来说,树的高度一般在2-4层。下面来进行一些具体的估算。

树的高度是由阶数决定的,阶数越大树越矮;而阶数的大小又取决于每个节点可以存储多少条记录。Innodb中每个节点使用一个页(page),页的大小为16KB,其中元数据只占大约128字节左右(包括文件管理头信息、页面头信息等等),大多数空间都用来存储数据。

在这里插入图片描述

B+ 树和 B 树的区别?

在这里插入图片描述

为什么 B+ 树比 B 树更适合应用于数据库索引?

在这里插入图片描述

七、总结

在这里插入图片描述

之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESP32入门开发·VScode空白项目搭建·点亮一颗LED灯

目录 1. 环境搭建 2. 创建项目 3. 调试相关介绍 4. 代码编写 4.1 包含头文件 4.2 引脚配置 4.3 设置输出电平 4.4 延时函数 4.5 调试 1. 环境搭建 默认已经搭建好环境,如果未搭建好可参考: ESP32入门开发Windows平台下开发环境的搭建…

ONLYOFFICE AI 智能体上线!与编辑器、新的 AI 提供商等进行智能交互

ONLYOFFICE AI 插件​迎来重要更新,带来了新功能和更智能的交互体验。随着 AI 智能体(现为测试版)的上线、带来更多 AI 提供商支持以及其他新功能,AI 插件已经成为功能强大的文档智能助理。 关于 ONLYOFFICE ONLYOFFICE 文档是多…

【C++进阶学习】第十一弹——C++11(上)——右值引用和移动语义

前言: 前面我们已经将C的重点语法讲的大差不差了,但是在C11版本之后,又出来了很多新的语法,其中有一些作用还是非常大的,今天我们就先来学习其中一个很重要的点——右值引用以及它所扩展的移动定义 目录 一、左值引用和…

【IoTDB】363万点/秒写入!IoTDB凭何领跑工业时序数据库赛道?

【作者主页】Francek Chen 【专栏介绍】⌈⌈⌈大数据与数据库应用⌋⌋⌋ 大数据是规模庞大、类型多样且增长迅速的数据集合,需特殊技术处理分析以挖掘价值。数据库作为数据管理的关键工具,具备高效存储、精准查询与安全维护能力。二者紧密结合&#xff0…

IEEE 2025 | 重磅开源!SLAM框架用“法向量+LRU缓存”,将三维重建效率飙升72%!

一、前言 当前研究领域在基于扩散模型的文本到图像生成技术方面取得了显著进展,尤其在视觉条件控制方面。然而,现有方法(如ControlNet)在组合多个视觉条件时存在明显不足,主要表现为独立控制分支在去噪过程中容易引入…

无人机遥控器教练模式技术要点

一、技术要点1.控制权仲裁机制:核心功能:清晰定义主控权归属逻辑(默认为学员,但教练随时可接管)。切换方式:通常通过教练遥控器上的物理开关(瞬时或锁定型)或软件按钮触发。切换逻辑…

【跨服务器的数据自动化下载--安装公钥,免密下载】

跨服务器的数据自动化下载功能介绍:上代码:发现好久没写csdn了,说多了都是泪~~ 以后会更新一些自动化工作的脚本or 小tricks,欢迎交流。分享一个最近在业务上写的较为实用的自动化脚本,可以批量从远端服务器下载指定数…

C++-->stl: list的使用

前言list的认识list是可以在固定时间(O(1))内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中&#xff0…

本地WSL部署接入 whisper + ollama qwen3:14b 总结字幕

1. 实现功能 M4-1 接入 whisper ollama qwen3:14b 总结字幕 自动下载视频元数据如果有字幕,只下载字幕使用 ollama 的 qwen3:14b 对字幕内容进行总结 2.运行效果 source /root/anaconda3/bin/activate ytdlp 🔍 正在提取视频元数据… 📝 正在…

《Linux运维总结:Shell脚本高级特性之变量间接调用》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:Linux运维实战总结 一、变量间接调用 在Shell脚本中,变量间接调用是一种高级特性,它允许你通过另一个变量的值来动态地访问…

ABP VNext + Akka.NET:高并发处理与分布式计算

ABP VNext Akka.NET:高并发处理与分布式计算 🚀 用 Actor 模型把高并发写入“分片→串行化”,把锁与竞态压力转回到代码层面的可控顺序处理;依托 Cluster.Sharding 横向扩容,Persistence 宕机可恢复,Strea…

[激光原理与应用-250]:理论 - 几何光学 - 透镜成像的优缺点,以及如克服缺点

透镜成像是光学系统中应用最广泛的技术,其通过折射原理将物体信息转换为图像,但存在像差、环境敏感等固有缺陷。以下是透镜成像的优缺点及针对性改进方案:一、透镜成像的核心优点高效集光能力透镜通过曲面设计将分散光线聚焦到一点&#xff0…

测试匠谈 | AI语音合成之大模型性能优化实践

「测试匠谈」是优测云服务平台倾心打造的内容专栏,汇集腾讯各大产品的顶尖技术大咖,为大家倾囊相授开发测试领域的知识技能与实践,让测试工作变得更加轻松高效。 本期嘉宾介绍 Soren,腾讯TEG技术事业群质量工程师,负责…

用天气预测理解分类算法-从出门看天气到逻辑回归

一、生活中的决策难题:周末郊游的「天气判断」 周末计划郊游时,你是不是总会打开天气预报反复确认?看到 "25℃、微风、无雨" 就兴奋收拾行李,看到 "35℃、暴雨" 就果断取消计划。这个判断过程,其…

HTTPS服务

HTTPS服务 一、常见的端口 http ------ 80 明文 https ------ 443 数据加密 dns ------ 53 ssh ------ 22 telent ------ 23 HTTPS http ssl或者tls (安全模式) 二、原理: c(客户端…

【Android笔记】Android 自定义 TextView 实现垂直渐变字体颜色(支持 XML 配置)

Android 自定义 TextView 实现垂直渐变字体颜色(支持 XML 配置) 在 Android UI 设计中,字体颜色的渐变效果能让界面看起来更加精致与现代。常见的渐变有从左到右、从上到下等方向,但 Android 的 TextView 默认并不支持垂直渐变。…

CANopen Magic调试软件使用

一、软件安装与硬件连接1.1 系统要求操作系统:Windows 7/10/11 (64位)硬件接口:支持Vector/PEAK/IXXAT等主流CAN卡推荐配置:4GB内存,2GHz以上CPU1.2 安装步骤运行安装包CANopen_Magic_Setup.exe选择安装组件(默认全选&…

前端css学习笔记3:伪类选择器与伪元素选择器

本文为个人学习总结,如有谬误欢迎指正。前端知识众多,后续将继续记录其他知识点! 目录 前言 一、伪类选择器 1.概念 2.动态选择器(用户交互) 3.结构伪类 :first-child:选择所有兄弟元素的…

深入探索 PDF 数据提取:PyMuPDF 与 pdfplumber 的对比与实战

在数据处理和分析领域,PDF 文件常常包含丰富的文本、表格和图形信息。然而,从 PDF 中提取这些数据并非易事,尤其是当需要保留格式和颜色信息时。幸运的是,Python 社区提供了多个强大的库来帮助我们完成这项任务,其中最…

Springboot注册过滤器的三种方式(Order 排序)

一、使用 Component Order(简单但不够灵活) 适用于全局过滤器,无需手动注册,Spring Boot 会自动扫描并注册。 Component Order(1) // 数字越小,优先级越高 public class AuthFilter implements Filter {Autowired /…