MySQL进阶之(四)InnoDB数据存储结构之行格式

四、InnoDB数据存储结构之行格式

  • 4.1 行格式的语法
  • 4.2 COMPACT 行格式
    • 4.2.1 记录的额外信息
      • 01、变长字段长度列表
      • 02、NULL 值列表
      • 03、记录头信息
    • 4.2.2 记录的真实数据
  • 4.3 Dynamic 和 Compressed 行格式
    • 4.3.1 字段的长度限制
    • 4.3.2 行溢出
    • 4.3.3 Dynamic 和 Compressed 行格式
  • 4.4 Redundant 行格式
    • 4.4.1 字段长度偏移列表
    • 4.4.2 记录头信息(record header)
    • 4.4.3 NULL 值处理

我们平时的数据都是以行记录为单位向表中插入数据的,这些记录在磁盘上的存放形式也被称为 行格式或者 记录格式。设计 InnoDB 存储引擎的大叔到现在为止设计了 4 中不同类型的行格式,分别是 COMPACT、REDUNDANT、DYNAMIC 和 COMPRESSED。随着时间的推移,它们可能会设计出更多的行格式,但是不管怎么变,这些行格式在原理上大体都是相同的。
——摘自《MySQL 是怎样运行的》

4.1 行格式的语法

我们可以在创建或者修改表的语句中指定记录所使用的行格式:

# 创建表时指定行格式
CREATE TABLE 表名(列的信息) ROW_FORMAT = 行格式名称
# 修改表的行格式
ALTER TABLE 表名 ROW_FORMAT = 行格式名称

4.2 COMPACT 行格式

COMPACT 表示紧凑的,在 MySQL 5.1 版本中,默认设置为 COMPACT 行格式。

一条完整的记录可以分为记录的额外信息记录的真实数据两大部分:
在这里插入图片描述

4.2.1 记录的额外信息

这部分信息时服务器为了更好地管理记录而不得不额外添加的一些信息。这些额外的信息分为三部分,分别是变长字段长度列表NULL 值列表记录头信息

01、变长字段长度列表

MySQL 支持一些变长的数据类型,比如 varchar(M)、varbinary(M)、text 类型、blob 类型,这些数据类型修饰列称为变长字段变长字段中存储多少字节的数据不是固定的,所以我们在存储真实数据的时候,需要顺便把这些数据占用的字节数也存起来。

也就是说,这些变长字段占用的存储空间分为两部分:

  • 真正的数据内容;
  • 该数据占用的字节数。

在 Compact 行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,且各变长字段的真实数据占用的字节数按照列的顺序逆序存放。

比如,创建一张表:

create table record_test_table(col1 varchar(8),col2 varchar(8) not null,col3 vhar(8),col4 varchar(8)
) charset=ascii row_format=Compact

并向表里插入数据:

insert into record_test_table(col1, col2, col3, col4)
values
('zhangsan', 'lisi', 'wangwu', 'songhk'),
('tong', 'chen', NULL, NULL);

因为 record_test_table 表中 col1、col2、col4 列都是 varchar(8) 类型的,所以这三个列的值的长度都会被存储在记录开头处。由于使用的是 ascii 字符集,所以每个字符只需要 1 个字节来进行编码:
在这里插入图片描述
又因为这些长度值需要按照列的顺序逆序存放,所以最后变长字段长度列表的字节串用十六进制表示的效果就是:06 04 08。

在这里插入图片描述

小贴士:并不是所有记录都有这个变长字段长度列表部分,如果表中所有的列都不是变长的数据类型或者所有列的值都是 NULL 的话,就不需要有变长字段长度列表(不冗余存储,节省存储空间)了。

02、NULL 值列表

一条记录中的某些列可能存储 NULL 值,如果把这些 NULL 值都放到 “记录的真实数据” 中存储会很占地方。所以,COMPACT 行格式把一条记录中值为 NULL 的列统一管理起来,存储到 NULL 值列表中。

为什么要定义 NULL 值列表呢?

之所以要存储 NULL 值,是因为数据都是需要对齐的,如果没有标注出来 NULL 值的位置,就有可能在查询数据的时候出现混乱的情况。如果使用一个特殊符号来代替 NULL 值放到对应的位置,虽然可以达到效果,但是大量的 NULL 值列会严重浪费空间,所以干脆就直接在行数据的头部开辟出一块空间,专门用来记录该行哪些数据是非空数据,哪些是空数据

⭐ 规定

将每个允许存储 NULL 的列对应一个二进制位,二进制位按照列的顺序逆序存放,格式如下:

  • 二进制位为 1 时,代表该列的值为 NULL
  • 二进制位为 0 时,代表该列的值不为 NULL

举个例子:字段 a、b、c,其中 a 是主键,在某一行中存储的数依次是 a = 1,b = null,c = 2。那么 COMPACT 行格式中的 NULL 值列表中存储的是:01。第一个 0 表示 c 的值不为 null,第二个 1 表示 b 是 null。这里需要注意以下,之所以没有 a 的值,是因为数据库会自动跳过主键,因为主键肯定是非 null 且唯一的,在 null 值列表的数据中就会自动跳过主键

record_test_table 的两条记录的 NULL 值列表为:

# 这里是上文中插入的两条数据
insert into record_test_table(col1, col2, col3, col4)
values
('zhangsan', 'lisi', 'wangwu', 'songhk'),
('tong', 'chen', NULL, NULL);

在这里插入图片描述

这样我们就可以回答问题了:MySQL 中的 NULL 值是怎么存储的?
答:NULL 值是由 NULL 值列表记录的,用列的二进制位逆序表示每行记录中的每一列是否为 NULL 值,0 代表不为 NULL,1 代表为 NULL 值。

假设现有一张表,其中有 4 个字段:col1、col2、col3、col4。向其插入一条记录:‘a’, NULL, NULL, ‘dd’,那么 NULL 值列表使用二进制位表示为:0 1 1 0,转化成十进制就是 06。

03、记录头信息

除了变长字段长度列表、NULL 值列表之外,还有一个记录头信息的部分,它是由固定的 5 字节组成,用于描述一些属性的。5 个字节也就是 40 个二进制位,不同的位代表不同的属性:
在这里插入图片描述
在这里插入图片描述
其中,重点来说几个属性。

属性一、delete_mask(删除标记)

这个属性标记着当前记录是否被删除,占用 1 个二进制位:

  • 值为 0:代表记录并没有被删除
  • 值为 1:代表记录被删除掉了

被删除的记录为什么还在页中存储呢?

这些被删除的记录不会从磁盘上移除,是因为一旦移除,其他的记录还需要在磁盘上重新排列,这会带来性能消耗

尤其是对聚簇索引的叶子节点来说,假设移除的是主键值为 1 的记录,那么整个聚簇索引的叶子节点都会因为这一条记录的删除全部重新排序,显然这样是不合适的。

所以,只是将这些删除的记录打一个删除标记,以区分正常记录和被删除的记录,所有被删除的记录会组成一个垃圾链表,它们所占用的空间被称为可重用空间,之后如果有新记录插入到表中时,可能会覆盖掉(复用)被删除的记录占用的存储空间。

这里需要注意:将 delete_flag 属性设置为 1 和将被删除的记录加入到垃圾链表中其实是分为两个阶段。

属性二、min_rec_mask(非叶子节点最小记录标记)

B+ 树的每层非叶子节点中的最小记录都会添加该标记,min_rec_mask 值为 1。如果我们自己插入的四条记录的 min_rec_mask 值都是 0,意味着它们都不是 B+ 树的非叶子节点中的最小记录。

属性三、record_type(记录类型)

这个属性表示当前记录的类型,一共有 4 种类型的记录:

  • 0:普通记录
  • 1:B+ 树非叶节点记录
  • 2:最小记录
  • 3:最大记录

再回过头来看:数据页结构和索引结构就可以理解当时的图中为什么表示的 record_type 值不一样了。

heap_no(在页中的相对位置)

这个属性表示当前记录在本页中的位置(设计 InnoDB 的大叔把记录一条一条亲密无间排列的结构称为堆,这个属性也表示在堆中的相对位置)

其中,值为 0 和 1 的记录分别代表最小和最大记录,这两条记录并不是我们自己插入的,所以有时候也称为伪记录或虚拟记录。

n_owned(每行记录数)

页目录中会将所有的记录分成若干个组,每个组中的最后一条记录的头信息中会存储该组一共有多少条记录,来作为 n_owned 字段的值,而其他记录的 n_owned 值都是 0。

next_record(记录的相对位置)

它表示从当前记录的真实数据到下一条记录的真实数据的地址偏移量

假设第一条记录的 next_record 值为 32,意味着从第一条记录的真实数据的地址处向后找 32 个字节就是下一条记录的真实数据。

注意:下一条记录指得并不是按照我们插入顺序的下一条记录,而是按照主键值由小到大的顺序的下一条记录

并且,InnoDB 底层规定 Infimum 记录(最小记录)的下一条记录就是当前页中主键值最小的记录,而当前页中主键值最大的记录指向的下一条记录就是 Supremum 记录(最大记录)。用箭头指向代替地址偏移量来表示 next_record:
在这里插入图片描述
下面来分别演示一下删除一条记录的操作增加一条记录的操作

⭐ 删除一条记录的操作

根据上图所示,假设删除第 2 条记录:

# 删除主键值为2的记录
delete from page_demo where c1 = 2;

删除后,整个链表也会跟着变化:

  1. 把第二条记录的 delete_mask 值设置为 1,而并没有从存储空间中移除;
  2. 把第二条记录的 next_record 值设置为 0,意味着没有下一条记录了;
  3. 第一条记录的 next_record 指向第三条记录;
  4. 最大记录的 n_owned 值从 5 变成了 4。
    在这里插入图片描述

⭐ 增加一条记录的操作

在 “删除一条记录的操作” 中,主键值为 2 的记录被删除了(变成了垃圾链表),但是存储空间并没有被回收。现在要把这条数据再次插入:

# 新增主键值为2的记录
insert into page_demo values(2, 200, 'tong');

新插入的数据,因为指定了主键值为 2,所以按照聚簇索引结构这条记录会按照顺序插入原来第 2 条记录的位置,因为原来被删除的第 2 条记录并没有被真实删除,仍然占有空间,所以这次新插入的数据会复用原有的空间。链表也会发生变化:

  1. 第 2 条记录的 delete_mask 的值变为 0;
  2. 第 2 条记录的 next_record 的值变为 32;
  3. 第 1 条记录的 next_record 指向第 2 条记录,第 2 条记录的 next_record 指向第 3 条记录;
  4. 最大记录的 n_owned的值从 4 => 5。
    在这里插入图片描述

所以,不论我们怎么对页中的记录做增删改操作,InnoDB 始终会维护一条记录的单链表,链表中的各个节点是按照主键值由小到大的顺序连接起来的。

4.2.2 记录的真实数据

记录的真实数据,除了我们自定义的列的数据之外,MySQL 会为每个记录默认地添加一些列(隐藏列):

列名是否必须占用空间描述
DB_ROW_ID6字节行ID,唯一标识一条记录
DB_TRX_ID6字节事务ID
DB_ROLL_PTR7字节回滚指针

为了方便看,就把它们都写成小写的:row_id、transaction_id、roll_pointer。

在 InnoDB 表中,InnoDB 表的主键生成策略是这样的:

  1. 优先使用用户自定义的主键作为主键;
  2. 如果用户没有定义主键,则选取一个不允许存储 NULL 值的 UNIQUE 键作为主键;
  3. 如果表中连不允许存储 NULL 值的 UNIQUE 键都没有定义,则会为表默认添加一个名为 row_id 的隐藏列作为主键。

举个例子:

现创建一张表 mytest:

create table mytest(col1 varchar(10),col2 varchar(10),col3 char(10),col4 varchar(10)
)engine=innodb charset=latin1 row_format=compact

并向表中插入三条数据:

insert into mytest values
('a', 'bb', 'bb', 'ccc'),
('d', 'ee', 'ee', 'fff'),
('d', NULL, NULL, 'fff');

找到存储文件 mytest.idb 的位置,用 notepad++ dakai,建议安装一个解析插件,将乱码文件解析成十进制的数据格式:
在这里插入图片描述
在这里插入图片描述
解析第一行记录如下:
由于 col3 列是定长,所以不计入变长字段长度列表中。
在这里插入图片描述
第二行的数据同第一行,这里就不一一列举了。

第三行的数据中有 NULL 值,所以在存储上与第一行、第二行有些差异:
在这里插入图片描述

至于 transaction_id 和 roll_pointer,暂时还没学到哩,等学到时候会做笔记的呀~

4.3 Dynamic 和 Compressed 行格式

4.3.1 字段的长度限制

char 与 varchar 的区别如下:
在这里插入图片描述
也就是说,一个 varchar 类型的字段,最大容量为 65535 个字节。

现在已经存在了一张表,分别查看 MySQL 8.0.26 版本和 MySQL 5.7.34 版本的默认字符集:
在这里插入图片描述
在这里插入图片描述
由此可见,MySQL 8.0.26 字符集默认采用 utf8mb4,MySQL 5.7.34 字符集默认采用 utf8。这两者的区别就是:

  1. utf8:使用 3 个字节表示字符;
  2. utf8mb4:使用 4 个字节表示字符,可以存储一些 emoji 表情等。

说明:统一采用 MySQL 8.0.26 版本来进行接下来的操作。

采用默认字符集 utf8mb4
在这里插入图片描述

报错提示:字段长度最大不能超过 16383,因为 8.0.26 版本默认字符集为 utf8mb4,也就是说,一个字符等于 4 个字节,那么,16383 * 4 = 65532,还差 3 个字节才等于 65535。反过来,65535 除以 4 结果等于 1633.75,由于字段长度不能带小数,将其四舍五入改为 16384:
在这里插入图片描述
显然还是不能超过 16383 的,所以字符集 utf8mb4 允许的最大长度为 16382

那么,那 3 个字节跑哪里了呢?

16383 * 4 = 65532,65535 - 65532 = 3。实际上,每一行记录除了存储真实数据之外,还有记录的额外信息中默认会有变长字段长度列表(2 字节)和 NULL 值列表(1 字节)。所以,如果该 varchar 类型的的列没有 NOT NULL 属性,每一行记录都会默认空出来 3 个字节:存储变长字段长度列表和 NULL 值的标识,实际最多只能存储 65532 个字节的数据。

采用字符集 utf8

由上文可知,需要预留 3 个字节:65535 - 3 = 65532,65532 / 3 = 21844。

重复上述验证步骤:
在这里插入图片描述
由此可知,字符集 utf8 字段的最大长度限制为 21844

采用 ascii 字符集

由上述推断可知,ascii 字符集允许存储字段的最大长度为 65532

4.3.2 行溢出

根据上文所说的单个字段的最大长度根据不同的字符集,会有不同的限制,8.0.26 默认采用 utf8mb4字符集(4 个字节表示一个字符),最大容量为 65532 字节。

而 InnoDB 中一个数据页的大小是 16 KB,16 * 1024 = 16386 个字节,也就是说,一个 varchar 的容量远远大于一个数据页的大小,这样就可能出现一个页存储不下一行记录的情况,这种情况就叫做行溢出

在 Compact 和 Redundant 行格式中,对于占用存储空间非常大的列,在记录的真实数据处只会存储该列的一部分数据(768 个前缀字节),把剩余的数据分散存储在其他的页中,这叫作分页存储

然后记录的真实数据处用 20 个字节存储指向这些分散页的地址(这 20 个字节中还包括存储了分散在各个页中的真实数据占用的字节数),从而可以找到剩余数据所在的页,这称为页的扩展,如下图所示:
在这里插入图片描述

4.3.3 Dynamic 和 Compressed 行格式

在MySQL 8.0中,默认行格式就是 Dynamic,Dynamic、Compressed 行格式和 Compact 行格式类似,只不过在处理行溢出数据时方式不同:

  • Compact 和 Redundant 两种格式会在记录的真实数据处存储一部分数据(存放768个前缀字节)。

  • Compressed 和 Dynamic 两种行格式不会在记录的真实数据处存储列真实数据的前 768 字节,而是把所有的数据都存储到溢出页中,只在记录的真实数据处存储指向这些溢出页的地址(20 字节),实际的数据都存放在 Off Page(溢出页)中:
    在这里插入图片描述

Compressed 和 Dynamic 行格式的区别:Compressed 行格式在 Dynamic 的基础上优化了一层,存储在其中的行数据会以 zlib 的算法进行压缩,因此对于 BLOB、TEXT、VARCHAR 这类大长度类型的数据能够进行非常有效的存储。

4.4 Redundant 行格式

Redundant 是 MySQL5.0 版本之前 InnoDB 的行记录存储格式,MySQL 5.0 支持 Redundant 是为了兼容之前版本的页格式。

我们可以直接修改表的行格式为 Redundant:

alter table record_test_table row_rormat=Redundant;

Redundant 行格式存储格式:在这里插入图片描述

对比 Compact 行格式主要有两大处不同:

  1. Compact 是变长字段长度列表,Redundant 是字段长度偏移列表。
  2. Compact 有 NULL 值列表,Redundant 没有 NULL 值列表。

4.4.1 字段长度偏移列表

为什么说 Redundant 行格式会有冗余说法?

因为 Redundant 行格式的字段长度偏移列表会将该行记录中所有列(包括隐藏列)的长度信息都按照逆序存储起来。

偏移两个字,意味着 Redundant 行格式计算列值的长度的方式不像 Compact 行格式那么直观,它是采用两个相邻数值的差值来计算各个列值的长度

比如第一行记录的字段长度偏移列表(逆序)是:

2B 25 1F 1B 13 0C 06

因为它是按照逆序排列的,所以按照顺序排列就是:

06 0C 13 1B 1F 25 2B

可以看出有三个隐藏列和四个字段列。

按照两个相邻数值的差值来计算各个字段列值的长度的如下表所示:

在这里插入图片描述

4.4.2 记录头信息(record header)

不同于 Compact 行格式,Redundant 行格式中的记录头信息固定占用 6 个字节(48 位),每位的含义如下:

在这里插入图片描述
与 Compact 行格式的记录头信息对比来看,有两处不同:

  1. Redundant 行格式多了 n_field 和 1byte_offs_flag 这两个属性。
  2. Redundant 行格式没有 record_type 这个属性。

其中两个属性的含义:

  • n_field 代表一行中列的数量,占用 10 位,所以 MySQL5.0 之前的版本最多只能包含 1023 个列。

  • 1byte_offs_flags 属性定义了字段长度偏移列表占用 1 个字节,还是 2 个字节(使用 127 作为分界点是因为:127 二进制表示为 01111111,第一位为 NULL 比特位,用来标记是否为 NULL)。
    当记录的真实数据占用的字节数不大于 127 时,占用 1 字节;
    当记录的真实数据占用的字节数大于 127,但不大于 32767 时,占用 2 字节;
    当记录的真实数据大于 32767 时,这部分的数据被存放到溢出页中,使用 2 字节来存储梅格列对应的偏移量。

4.4.3 NULL 值处理

因为 Redundant 行格式没有 NULL 值列表,所以在字段长度偏移列表中对各列对应的偏移量做了一些特殊处理:将列对应的偏移量值的第一个比特位作为是否为 NULL 的依据,该比特位也可以称之为 NULL 比特位

也就是说,在解析一条记录的某个列时,首先看一下该列对应的偏移量的 NULL 比特位是否为 1,如果为 1,那么该列的值就是 NULL,否则就不是 NULL。

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

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

相关文章

【Flutter 】get-cli init报错处理

报错内容 get init 命令跳出,报错内如下 Select which type of project you want to creat Synchronous waiting using dart:cli waitFor Unhandled exceotion . Dart WaitforEvent is deprecated and disabled by default. This feature will be fully removed in Dart 3.4 …

【定岗定编】某度假村酒店客房部定岗定编管理咨询项目纪实

该度假村酒店由于地域广阔,将客服部分为了四个不同区域,这样就导致了在不同的区域员工的接待量不均衡的状况,引起了员工的强烈不满。如何合理地配置客户部人员以及如何合理地鉴定员工的工作量成为该酒店所面临的两大难题。让我们来看看在人力…

vulhub中ThinkPHP5 SQL注入漏洞 敏感信息泄露

漏洞原理 传入的某参数在绑定编译指令的时候又没有安全处理,预编译的时候导致SQL异常报错。然而thinkphp5默认开启debug模式,在漏洞环境下构造错误的SQL语法会泄漏数据库账户和密码 启动后,访问http://your-ip/index.php?ids[]1&ids[]2…

即插即用篇 | YOLOv8 引入 NAM 注意力机制 | 《NAM: Normalization-based Attention Module》

论文名称:《NAM: Normalization-based Attention Module》 论文地址:https://arxiv.org/pdf/2111.12419.pdf 代码地址:https://github.com/Christian-lyc/NAM 文章目录 1 原理2 源代码3 添加方式4 模型 yaml 文件template-backbone.yamltemplate-small.yamltemplate-large…

C++之类型转换

C语言中的类型转换 在C语言中, 如果赋值运算符左右两侧类型不同, 或者形参与实参类型不匹配, 或者返回值类型与 接收返回值类型不一致时, 就需要发生类型转化, C语言中总共有两种形式的类型转换: 隐式类型转换和显式类型转换 1. 隐式类型转化是关联度很强, 意义相近的类型之间…

【CSP试题回顾】201512-2-消除类游戏

CSP-201512-2-消除类游戏 解题思路 输入棋盘大小和颜色: 首先,程序从标准输入读取两个整数n和m,分别代表棋盘的行数和列数。然后,程序读取接下来的n行输入,每行包含m个整数,代表棋盘上每个方格中的棋子颜色。 初始化…

[蓝桥杯 2017 省 A] 油漆面积 Java代码及一些个人理解

[蓝桥杯 2017 省 A] 油漆面积 题目描述 X 星球的一批考古机器人正在一片废墟上考古。 该区域的地面坚硬如石、平整如镜。 管理人员为方便,建立了标准的直角坐标系。 每个机器人都各有特长、身怀绝技。它们感兴趣的内容也不相同。 经过各种测量,每个…

【论文速读】 | AI驱动修复:漏洞自动化修复的未来

本次分享论文为:AI-powered patching: the future of automated vulnerability fixes 基本信息 原文作者:Jan Nowakowski, Jan Keller 作者单位:Google Security Engineering 关键词:AI, 安全性漏洞, 自动化修复, LLM, sanitiz…

Objective-C blocks 概要

1.block的使用 1.1什么是block? Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数。 “带有自动变量”在Blocks中表现为“截取自动变量" “匿名函数”就是“不带名称的函数” 块,封装了函数调用及调用…

全方位碾压chatGPT4的全球最强模型Claude 3发布!速通指南在此!保姆级教学拿脚都能学会!

🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏《Spring 狂野之旅:从入门到入魔》 &a…

Android开发岗还不会这些问题,温故而知新

前言 前前后后经历过大项目、小项目,跨平台,小程序,Nodejs服务等等,目前在做的Rom开发,定制各种手机中的奇葩需求,从应用层到Framework层,再到C层,再到驱动,最终到Linux&…

MybatisPlus入门详解

一、MyBatisPlus 简介 1.1 创建新模块 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency> 由于mp并未被收录到idea的系统内置配置,无法…

Solidity Uniswap V2 Pair中添加流动性

添加流动性的功能的用户入口&#xff0c;UniswapV2在UniswapV2Router中实现&#xff0c;它用来计算新的流动性并发行LP-Token&#xff0c;流动性管理简单地视为LP-Token管理。当你为一个pair增加流动性时&#xff0c;合约会创造LP Token;当你移除流动性时&#xff0c;LP-Token就…

【debug】element-ui时间控件回显后不可编辑且显示为空

问题&#xff1a;使用element-ui的时间控件回显数据&#xff0c;编辑数据没有反应&#xff1a;点时间和“确认”按钮都没反应。 输入框中会显示数据&#xff0c;但提交时的校验显示为空。 <el-form-item label"开始时间" prop"limitStartTime"><…

局部最小值问题

局部最小值问题&#xff1a; 条件&#xff1a;n个数的无序数组 array&#xff0c;相邻两个数一定不相等&#xff0c;找出其中的一个局部最小值。 如果array[0]< array[1] ,返回 array[0];如果array[n-1]<array[n-2]&#xff0c;返回array[n-1];其他的位置需要满足 array[…

xss.haozi.me:0X0D

alert(1) -> 记住要回车一下-->是js的一个注释符但是只能用在最前面前面有一个空格都不行

【LeetCode】升级打怪之路 Day 14:二叉树的遍历

今日题目&#xff1a; 144. 二叉树的前序遍历94. 二叉树的中序遍历145. 二叉树的后序遍历102. 二叉树的层序遍历107. 二叉树的层序遍历 II199. 二叉树的右视图637. 二叉树的层平均值429. N 叉树的层序遍历515. 在每个树行中找最大值116. 填充每个节点的下一个右侧节点指针117. …

【YOLO v5 v7 v8 v9小目标改进】RevCol:解决深度学习信息从低层(输入)传递至高层(输出)的过程中,信息会逐层丢失问题

RevCol&#xff1a;解决深度学习信息从低层&#xff08;输入&#xff09;传递至高层&#xff08;输出&#xff09;的过程中&#xff0c;信息会逐层丢失问题 学习解耦表示可逆列网络&#xff08;RevCol&#xff09;子特征1&#xff1a;多级可逆单元子特征2&#xff1a;可逆列架构…

ARM电源策略单元Power Policy Unit

本规范描述了电源策略单元&#xff08;PPU&#xff09;架构。它定义了PPU架构的1.1版本。 PPU规范的1.1版本增加了操作模式支持。这使得能够为功能或更高粒度的电源控制原因提供组件特定的电源模式支持。 在本文档中&#xff0c;对PPU或PPU的引用指的是实现了此PPU架构的设备…

十四、重写与多态

重写、多态 上一讲是&#xff0c;子类对父类横向上的扩展 这一讲是&#xff0c;子类对父类纵向上的扩展 方法重写 使用override关键字重写父类的方法 将父类原本方法的逻辑更新成新版本的逻辑 注&#xff1a;仅能重写可见的父类成员&#xff0c;并且重写要保持签名一致。 签名一…