diff --git a/README.md b/README.md index 464c4897..0f34e8e1 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,6 @@ 目录按《剑指 Offer 第二版》编排,在牛客网的在线编程中出现的题目都已经 AC。 -> [2016 校招真题题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/2016%20校招真题题解.md) - -未完成 - # 网络 > [计算机网络](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机网络.md) diff --git a/notes/MySQL.md b/notes/MySQL.md index e83bb6a0..f0fe5704 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -1,227 +1,249 @@ -* [存储引擎](#存储引擎) +* [Ĵ](#Ĵ) + * [1. ԭ](#1-ԭ) + * [2. һ](#2-һ) + * [3. ](#3-) + * [4. ־](#4-־) +* [洢](#洢) * [1. InnoDB](#1-innodb) * [2. MyISAM](#2-myisam) - * [3. InnoDB 与 MyISAM 的比较](#3-innodb-与-myisam-的比较) -* [数据类型](#数据类型) - * [1. 整型](#1-整型) - * [2. 浮点数](#2-浮点数) - * [3. 字符串](#3-字符串) - * [4. 时间和日期](#4-时间和日期) -* [索引](#索引) - * [1. 索引分类](#1-索引分类) - * [1.1 B-Tree 索引](#11-b-tree-索引) - * [1.2 哈希索引](#12-哈希索引) - * [1.3. 空间索引数据(R-Tree)](#13-空间索引数据(r-tree)) - * [1.4 全文索引](#14-全文索引) - * [2. 索引的优点](#2-索引的优点) - * [3. 索引优化](#3-索引优化) - * [3.1 独立的列](#31-独立的列) - * [3.2 前缀索引](#32-前缀索引) - * [3.3 多列索引](#33-多列索引) - * [3.4 索引列的顺序](#34-索引列的顺序) - * [3.5 聚簇索引](#35-聚簇索引) - * [3.6 覆盖索引](#36-覆盖索引) - * [4. B-Tree 和 B+Tree 原理](#4-b-tree-和-b+tree-原理) + * [3. InnoDB MyISAM ıȽ](#3-innodb--myisam-ıȽ) +* [](#) + * [1. ](#1-) + * [2. ](#2-) + * [3. ַ](#3-ַ) + * [4. ʱ](#4-ʱ) +* [](#) + * [1. ](#1-) + * [1.1 B-Tree ](#11-b-tree-) + * [1.2 ϣ](#12-ϣ) + * [1.3. ռݣR-Tree](#13-ռݣr-tree) + * [1.4 ȫ](#14-ȫ) + * [2. ŵ](#2-ŵ) + * [3. Ż](#3-Ż) + * [3.1 ](#31-) + * [3.2 ǰ׺](#32-ǰ׺) + * [3.3 ](#33-) + * [3.4 е˳](#34-е˳) + * [3.5 ۴](#35-۴) + * [3.6 ](#36-) + * [4. B-Tree B+Tree ԭ](#4-b-tree--b+tree-ԭ) * [4. 1 B-Tree](#4-1-b-tree) * [4.2 B+Tree](#42-b+tree) - * [4.3 带有顺序访问指针的 B+Tree](#43-带有顺序访问指针的-b+tree) - * [4.4 为什么使用 B-Tree 和 B+Tree](#44-为什么使用-b-tree-和-b+tree) -* [查询性能优化](#查询性能优化) + * [4.3 ˳ָ B+Tree](#43-˳ָ-b+tree) + * [4.4 Ϊʲôʹ B-Tree B+Tree](#44-Ϊʲôʹ-b-tree--b+tree) +* [ѯŻ](#ѯŻ) * [1. Explain](#1-explain) - * [2. 减少返回的列](#2-减少返回的列) - * [3. 减少返回的行](#3-减少返回的行) - * [4. 拆分大的 DELETE 或 INSERT 语句](#4-拆分大的-delete-或-insert-语句) -* [分库与分表](#分库与分表) -* [故障转移和故障恢复](#故障转移和故障恢复) - * [1. 故障转移](#1-故障转移) - * [2. 故障恢复](#2-故障恢复) -* [参考资料](#参考资料) + * [2. ٷص](#2-ٷص) + * [3. ٷص](#3-ٷص) + * [4. ִ DELETE INSERT ](#4-ִ-delete--insert-) +* [ֱֿ](#ֱֿ) +* [תƺ͹ϻָ](#תƺ͹ϻָ) + * [1. ת](#1-ת) + * [2. ϻָ](#2-ϻָ) +* [ο](#ο) +# Ĵ -# 存储引擎 +## 1. ԭ + +ҪôִУҪôִС + +## 2. һ + +ִǰ󶼱һ״̬ + +## 3. + +񵥶ִУӰ졣 + +## 4. ־ + +ʹϵͳϣִеĽҲܶʧ + +# 洢 ## 1. InnoDB -InnoDB 是 MySQL 的默认事务型引擎,只有在需要 InnoDB 不支持的特性时,才考虑使用其它存储引擎。 +InnoDB MySQL Ĭ棬ֻҪ InnoDB ֵ֧ʱſʹ洢档 -采用 MVCC 来支持高并发,并且实现了四个标准的隔离级别,默认级别是可重复读。 + MVCC ָ֧߲ʵĸ׼ĸ뼶Ĭϼǿظ -表是基于聚簇索引建立的,它对主键的查询性能有很高的提升。 +ǻھ۴ģIJѯкܸߵ -内部做了很多优化,包括从磁盘读取数据时采用的可预测性读,能够自动在内存中创建 hash 索引以加速读操作的自适应哈希索引,以及能够加速插入操作的插入缓冲区等。 +ڲ˺ܶŻӴ̶ȡʱõĿԤԶܹԶڴд hash ԼٶӦϣԼܹٲIJ뻺ȡ -通过一些机制和工具支持真正的热备份。 +ͨһЩƺ͹֧ȱݡ ## 2. MyISAM -MyISAM 提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等。但 MyISAM 不支持事务和行级锁,而且奔溃后无法安全恢复。 +MyISAM ṩ˴ԣȫѹռ亯GISȡ MyISAM ֧мұ޷ȫָ -只能对整张表加锁,而不是针对行。 +ֻܶűС -可以手工或者自动执行检查和修复操作,但是和事务恢复以及奔溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。 +ֹԶִм޸ǺָԼָͬܵһЩݶʧ޸Ƿdzġ -可以包含动态或者静态的行。 +԰̬߾̬С -如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机奔溃时会造成索引损坏,需要执行修复操作。 +ָ DELAY_KEY_WRITE ѡÿ޸ִʱ޸ĵд̣ǻдڴеļֻ߹رձʱŻὫӦдַ̡ʽԼдܣݿʱ𻵣Ҫִ޸ -如果表在创建并导入数据以后,不会再进行修改操作,那么这样的表适合采用 MyISAM 压缩表。 +ڴԺ󣬲ٽ޸IJôıʺϲ MyISAM ѹ -对于只读数据,或者表比较小、可以容忍修复操作,则依然可以继续使用 MyISAM。 +ֻݣ߱ȽС޸ȻԼʹ MyISAM -MyISAM 设计简单,数据以紧密格式存储,所以在某些场景下性能很好。 +MyISAM Ƽ򵥣Խܸʽ洢ijЩܺܺá -## 3. InnoDB 与 MyISAM 的比较 +## 3. InnoDB MyISAM ıȽ -**事务** +**** -InnoDB 是事务型的。 +InnoDB ͵ġ -**备份** +**** -InnoDB 支持在线热备份。 +InnoDB ֧ȱݡ -**奔溃恢复** +**ָ** -MyISAM 奔溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。 +MyISAM 𻵵ĸʱ InnoDB ߺܶ࣬һָٶҲ -**并发** +**** -MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。 +MyISAM ֱֻ֧ InnoDB ֧м -**其它特性** +**** -MyISAM 支持全文索引,地理空间索引; +MyISAM ֧ȫռ -# 数据类型 +# -## 1. 整型 +## 1. -TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 64 位存储空间,一般情况下越小的列越好。 +TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT ֱʹ 8, 16, 24, 64 λ洢ռ䣬һԽСԽá -INT(11) 中的数字只是规定了交互工具显示字符的个数,对于存储和计算来说是没有意义的。 +INT(11) еֻǹ涨˽ʾַĸڴ洢ͼ˵ûġ -## 2. 浮点数 +## 2. -FLOAT 和 DOUBLE 为浮点类型,DECIMAL 为高精度小数类型。CPU 原生支持浮点运算,但是不支持 DECIMAl 类型的计算,因此 DECIMAL 的计算比浮点类型需要更高的代价。 +FLOAT DOUBLE ΪͣDECIMAL Ϊ߾С͡CPU ԭָ֧㣬Dz֧ DECIMAl ͵ļ㣬 DECIMAL ļȸҪߵĴۡ -FLOAT、DOUBLE 和 DECIMAL 都可以指定列宽,例如 DECIMAL(18, 9) 表示总共 18 位,取 9 位存储小数部分,剩下 9 位存储整数部分。 +FLOATDOUBLE DECIMAL ָп DECIMAL(18, 9) ʾܹ 18 λȡ 9 λ洢С֣ʣ 9 λ洢֡ -## 3. 字符串 +## 3. ַ -主要有 CHAR 和 VARCHAR 两种类型,一种是定长的,一种是变长的。 +Ҫ CHAR VARCHAR ͣһǶģһDZ䳤ġ -VARCHAR 这种变长类型能够节省空间,因为只需要存储必要的内容。但是在执行 UPDATE 时可能会使行变得比原来长,当超出一个页所能容纳的大小时,就要执行额外的操作,MyISAM 会将行拆成不同的片段存储,而 InnoDB 则需要分裂页来使行放进页内。 +VARCHAR ֱ䳤ܹʡռ䣬ΪֻҪ洢Ҫݡִ UPDATE ʱܻʹбñԭһҳɵĴСʱҪִжIJMyISAM ὫвɲͬƬδ洢 InnoDB ҪҳʹзŽҳڡ -VARCHAR 会保留字符串末尾的空格,而 CHAR 会删除。 +VARCHAR ᱣַĩβĿո񣬶 CHAR ɾ -## 4. 时间和日期 +## 4. ʱ -MySQL 提供了两种相似的日期时间类型:DATATIME 和 TIMESTAMP。 +MySQL ṩƵʱͣDATATIME TIMESTAMP **DATATIME** -能够保存从 1001 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。 +ܹ 1001 굽 9999 ںʱ䣬Ϊ룬ʹ 8 ֽڵĴ洢ռ䡣 -它与时区无关。 +ʱ޹ء -默认情况下,MySQL 以一种可排序的、无歧义的格式显示 DATATIME 值,例如“2008-01016 22:37:08”,这是 ANSI 标准定义的日期和时间表示方法。 +Ĭ£MySQL һֿġĸʽʾ DATATIME ֵ硰2008-01016 22:37:08 ANSI ׼ںʱʾ **TIMESTAMP** -和 UNIX 时间戳相同,保存从 1970 年 1 月 1 日午夜(格林威治时间)以来的秒数,使用 4 个字节,只能表示从 1970 年 到 2038 年。 + UNIX ʱͬ 1970 1 1 ҹʱ䣩ʹ 4 ֽڣֻܱʾ 1970 2038 ꡣ -它和时区有关。 +ʱйء -MySQL 提供了 FROM_UNIXTIME() 函数把 Unxi 时间戳转换为日期,并提供了 UNIX_TIMESTAMP() 函数把日期转换为 Unix 时间戳。 +MySQL ṩ FROM_UNIXTIME() Unxi ʱתΪڣṩ UNIX_TIMESTAMP() תΪ Unix ʱ -默认情况下,如果插入时没有指定 TIMESTAMP 列的值,会将这个值设置为当前时间。 +Ĭ£ʱûָ TIMESTAMP еֵὫֵΪǰʱ䡣 -应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高。 +Ӧþʹ TIMESTAMPΪ DATETIME ռЧʸߡ -# 索引 +# -索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。 +ڴ洢ʵֵģڷʵֵģԲͬ洢вͬͺʵ֡ -索引能够轻易将查询性能提升几个数量级。 +ܹ׽ѯ -对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效。对于中到大型的表,索引就非常有效。但是对于特大型的表,建立和使用索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。 +ڷdzСı󲿷¼򵥵ȫɨȽЧе͵ıͷdzЧǶش͵ıʹĴ۽֮£ҪõһֱֳּҪѯһݣһ¼һ¼ƥ䣬ʹ÷ -## 1. 索引分类 +## 1. -### 1.1 B-Tree 索引 +### 1.1 B-Tree -B-Tree 索引是大多数 MySQL 存储引擎的默认索引类型。 +B-Tree Ǵ MySQL 洢Ĭ͡ -因为不再需要进行全表扫描,只需要对树进行搜索即可,因此查找速度快很多。 +ΪҪȫɨ裬ֻҪɣ˲ٶȿܶࡣ -可以指定多个列作为索引列,多个索引列共同组成键。B-Tree 索引适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。 +ָΪУйͬɼB-Tree ȫֵֵΧͼǰ׺ңмǰ׺ֻǰ׺ҡ -除了用于查找,还可以用于排序和分组。 +ڲңͷ顣 -如果不是按照索引列的顺序进行查找,则无法使用索引。 +ǰе˳вң޷ʹ -### 1.2 哈希索引 +### 1.2 ϣ -基于哈希表实现,优点是查找非常快。 +ڹϣʵ֣ŵDzҷdz졣 -在 MySQL 中只有 Memory 引擎显式支持哈希索引。 + MySQL ֻ Memory ʽֹ֧ϣ -InnoDB 引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B-Tree 索引之上再创建一个哈希索引,这样就让 B-Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。 +InnoDB һĹܽСӦϣijֵʹõķdzƵʱ B-Tree ֮ٴһϣ B-Tree йϣһЩŵ㣬ٵĹϣҡ -限制:哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能影响并不明显;无法用于分组与排序;只支持精确查找,无法用于部分查找和范围查找;如果哈希冲突很多,查找速度会变得很慢。 +ƣϣֻϣֵָ룬洢ֵֶԲʹеֵȡСڴееٶȺܿ죬Դ󲿷һӰ첢ԣ޷ڷֻ֧־ȷң޷ڲֲҺͷΧңϣͻܶ࣬ٶȻú -### 1.3. 空间索引数据(R-Tree) +### 1.3. ռݣR-Tree -MyISAM 存储引擎支持空间索引,可以用于地理数据存储。 +MyISAM 洢ֿ֧ռڵݴ洢 -空间索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。 +ռάݣЧʹάϲѯ -### 1.4 全文索引 +### 1.4 ȫ -MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较索引中的值。 +MyISAM 洢֧ȫڲıеĹؼʣֱӱȽеֵ -使用 MATCH AGAINST,而不是普通的 WHERE。 +ʹ MATCH AGAINSTͨ WHERE -## 2. 索引的优点 +## 2. ŵ -- 大大减少了服务器需要扫描的数据量; +- ˷Ҫɨ -- 帮助服务器避免进行排序和创建临时表; +- ʹʱ -- 将随机 I/O 变为顺序 I/O。 +- I/O Ϊ˳ I/O -## 3. 索引优化 +## 3. Ż -### 3.1 独立的列 +### 3.1 -在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引。 +ڽвѯʱвDZʽһ֣ҲǺIJ޷ʹ -例如下面的查询不能使用 actor_id 列的索引: +IJѯʹ actor_id е ```sql SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5; ``` -### 3.2 前缀索引 +### 3.2 ǰ׺ -对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。 + BLOBTEXT VARCHAR ͵Уʹǰ׺ֻʼIJַ -对于前缀长度的选取需要根据 **索引选择性** 来确定:不重复的索引值和记录总数的比值。选择性越高,查询效率也越高。最大值为 1 ,此时每个记录都有唯一的索引与其对应。 +ǰ׺ȵѡȡҪ **ѡ** ȷظֵͼ¼ıֵѡԽߣѯЧҲԽߡֵΪ 1 ʱÿ¼ΨһӦ -### 3.3 多列索引 +### 3.3 -在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。例如下面的语句中,最好把 actor_id 和 file_id 设置为多列索引。 +ҪʹöΪвѯʱʹöʹöܸáУð actor_id file_id Ϊ ```sql SELECT file_id, actor_ id FROM sakila.film_actor WhERE actor_id = 1 OR film_id = 1; ``` -### 3.4 索引列的顺序 +### 3.4 е˳ -让选择性最强的索引列放在前面,例如下面显示的结果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。 +ѡǿзǰ棬ʾĽ customer_id ѡԱ staff_id ߣð customer_id зڶǰ档 ```sql SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity, @@ -236,107 +258,107 @@ customer_id_selectivity: 0.0373 COUNT(*): 16049 ``` -### 3.5 聚簇索引 +### 3.5 ۴ ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b9e9ae8c-e216-4c01-b267-a50dbeb98fa4.jpg) -聚簇索引并不是一种索引类型,而是一种数据存储方式。 +۴һͣһݴ洢ʽ -术语“聚簇”表示数据行和相邻的键值紧密地存储在一起,InnoDB 的聚簇索引的数据行存放在 B-Tree 的叶子页中。 +۴ءʾкڵļֵܵش洢һInnoDB ľ۴д B-Tree ҶҳС -因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。 +Ϊ޷дͬĵطһֻһ۴ -**优点** +**ŵ** -1. 可以把相关数据保存在一起,减少 I/O 操作; -2. 因为数据保存在 B-Tree 中,因此数据访问更快。 +1. ԰ݱһ𣬼 I/O +2. Ϊݱ B-Tree Уݷʸ졣 -**缺点** +**ȱ** -1. 聚簇索引最大限度提高了 I/O 密集型应用的性能,但是如果数据全部放在内存,就没必要用聚簇索引。 -2. 插入速度严重依赖于插入顺序,按主键的顺序插入是最快的。 -3. 更新操作代价很高,因为每个被更新的行都会移动到新的位置。 -4. 当插入到某个已满的页中,存储引擎会将该页分裂成两个页面来容纳该行,页分裂会导致表占用更多的磁盘空间。 -5. 如果行比较稀疏,或者由于页分裂导致数据存储不连续时,聚簇索引可能导致全表扫描速度变慢。 +1. ۴޶ I/O ܼӦõܣȫڴ棬ûҪþ۴ +2. ٶڲ˳򣬰˳ġ +3. ²ۺܸߣΪÿµжƶµλá +4. 뵽ijҳУ洢ὫҳѳҳɸУҳѻᵼ±ռøĴ̿ռ䡣 +5. бȽϡ裬ҳѵݴ洢ʱ۴ܵȫɨٶȱ -### 3.6 覆盖索引 +### 3.6 -索引包含所有需要查询的字段的值。 +Ҫѯֶεֵ -## 4. B-Tree 和 B+Tree 原理 +## 4. B-Tree B+Tree ԭ ### 4. 1 B-Tree ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg) -为了描述 B-Tree,首先定义一条数据记录为一个二元组 [key, data],key 为记录的键,data 为数据记录除 key 外的数据。 +Ϊ B-Treeȶһݼ¼ΪһԪ [key, data]key Ϊ¼ļdata Ϊݼ¼ key ݡ -B-Tree 是满足下列条件的数据结构: +B-Tree ݽṹ -- 所有叶节点具有相同的深度,也就是说 B-Tree 是平衡的; -- 一个节点中的 key 从左到右非递减排列; -- 如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的所有 key 大于 keyi 且小于 keyi+1。 +- ҶڵͬȣҲ˵ B-Tree ƽģ +- һڵе key ҷǵݼУ +- ijָ key ֱ keyi keyi+1ҲΪ nullָָڵ key keyi С keyi+1 -在 B-Tree 中按 key 检索数据的算法非常直观:首先从根节点进行二分查找,如果找到则返回对应节点的 data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或找到 null 指针,前者查找成功,后者查找失败。 + B-Tree а key ݵ㷨dzֱۣȴӸڵжֲңҵ򷵻ضӦڵ dataӦָָĽڵݹвңֱҵڵҵ null ָ룬ǰ߲ҳɹ߲ʧܡ -由于插入删除新的数据记录会破坏 B-Tree 的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持 B-Tree 性质。 +ڲɾµݼ¼ƻ B-Tree ʣڲɾʱҪһѡϲתƵȲԱ B-Tree ʡ ### 4.2 B+Tree ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg) -与 B-Tree 相比,B+Tree 有以下不同点: + B-Tree ȣB+Tree ²ͬ㣺 -- 每个节点的指针上限为 2d 而不是 2d+1; -- 内节点不存储 data,只存储 key,叶子节点不存储指针。 +- ÿڵָΪ 2d 2d+1 +- ڽڵ㲻洢 dataֻ洢 keyҶӽڵ㲻洢ָ롣 -### 4.3 带有顺序访问指针的 B+Tree +### 4.3 ˳ָ B+Tree ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg) -一般在数据库系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 基础上进行了优化,在叶子节点增加了顺序访问指针,做这个优化的目的是为了提高区间访问的性能。 +һݿϵͳļϵͳʹõ B+Tree ṹھ B+Tree ϽŻҶӽڵ˳ָ룬ŻĿΪʵܡ -### 4.4 为什么使用 B-Tree 和 B+Tree +### 4.4 Ϊʲôʹ B-Tree B+Tree -红黑树等数据结构也可以用来实现索引,但是文件系统及数据库系统普遍采用 B-/+Tree 作为索引结构。 +ݽṹҲʵļϵͳݿϵͳձ B-/+Tree Ϊṹ -页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页得大小通常为 4k),主存和磁盘以页为单位交换数据。 +ҳǼ洢߼飬Ӳϵͳʹ̴洢ָΪĴСȵĿ飬ÿ洢ΪһҳϵͳУҳôСͨΪ 4kʹҳΪλݡ -一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。为了减少磁盘 I/O,磁盘往往不是严格按需读取,而是每次都会预读。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次 I/O 就可以完全载入。B-Tree 中一次检索最多需要 h-1 次 I/O(根节点常驻内存),渐进复杂度为 O(h)=O(logdN)。一般实际应用中,出度 d 是非常大的数字,通常超过 100,因此 h 非常小(通常不超过 3)。而红黑树这种结构,h 明显要深的多。并且于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,效率明显比 B-Tree 差很多。 +һ˵Ҳܴ󣬲ȫ洢ڴУļʽ洢ĴϡΪ˼ٴ I/OϸȡÿζԤǼѧľֲԭһݱõʱ丽Ҳͨϱʹáݿϵͳ˴ԤԭһڵĴСΪһҳÿڵֻҪһ I/O Ϳȫ롣B-Tree һμҪ h-1 I/Oڵ㳣פڴ棩ӶΪ O(h)=O(logdN)һʵӦУ d Ƿdz֣ͨ 100 h dzСͨ 3ֽṹh ҪĶࡣ߼ϺܽĽڵ㣨ӣϿܺԶ޷þֲԣЧԱ B-Tree ܶࡣ -B+Tree 更适合外存索引,原因和内节点出度 d 有关。由于 B+Tree 内节点去掉了 data 域,因此可以拥有更大的出度,拥有更好的性能。 +B+Tree ʺԭڽڵ d йء B+Tree ڽڵȥ data ˿ӵиijȣӵиõܡ -# 查询性能优化 +# ѯŻ ## 1. Explain -用来分析 SQL 语句,分析结果中比较重要的字段有: + SQL 䣬бȽҪֶУ -- select_type : 查询类型,有简单查询、联合查询和子查询 +- select_type : ѯͣм򵥲ѯϲѯӲѯ -- key : 使用的索引 +- key : ʹõ -- rows : 扫描的行数 +- rows : ɨ -## 2. 减少返回的列 +## 2. ٷص -慢查询主要是因为访问了过多数据,除了访问过多行之外,也包括访问过多列。 +ѯҪΪ˹ݣ˷ʹ֮⣬ҲʹС -最好不要使用 SELECT * 语句,要根据需要选择查询的列。 +òҪʹ SELECT * 䣬ҪҪѡѯС -## 3. 减少返回的行 +## 3. ٷص -最好使用 LIMIT 语句来取出想要的那些行。 +ʹ LIMIT ȡҪЩС -还可以建立索引来减少条件语句的全表扫描。例如对于下面的语句,不适用索引的情况下需要进行全表扫描,而使用索引只需要扫描几行记录即可,使用 Explain 语句可以通过观察 rows 字段来看出这种差异。 +Խȫɨ衣䣬Ҫȫɨ裬ʹֻҪɨ輸м¼ɣʹ Explain ͨ۲ rows ֲֶ졣 ```sql SELECT * FROM sakila.film_actor WHERE film_id = 1; ``` -## 4. 拆分大的 DELETE 或 INSERT 语句 +## 4. ִ DELETE INSERT -如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。 +һִеĻһסܶݡռ־ľϵͳԴܶСĵҪIJѯ ```sql DELEFT FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH); @@ -349,74 +371,74 @@ do { } while rows_affected > 0 ``` -# 分库与分表 +# ֱֿ -**1. 分表与分区的不同** +**1. ֱIJͬ** -分表,就是讲一张表分成多个小表,这些小表拥有不同的表名;而分区是将一张表的数据分为多个区块,这些区块可以存储在同一个磁盘上,也可以存储在不同的磁盘上,这种方式下表仍然只有一个。 +ֱǽһűֳɶСЩСӵвͬıǽһűݷΪ飬ЩԴ洢ͬһϣҲԴ洢ڲͬĴϣַʽ±Ȼֻһ -**2. 使用分库与分表的原因** +**2. ʹ÷ֱֿԭ** -随着时间和业务的发展,数据库中的表会越来越多,并且表中的数据量也会越来越大,那么读写操作的开销也会随着增大。 +ʱҵķչݿеıԽԽ࣬ұеҲԽԽôдĿҲ -**3. 垂直切分** +**3. ֱз** -将表按功能模块、关系密切程度划分出来,部署到不同的库上。例如,我们会建立商品数据库 payDB、用户数据库 userDB 等,分别用来存储项目与商品有关的表和与用户有关的表。 +ģ顢ϵг̶Ȼֳ𵽲ͬĿϡ磬ǻὨƷݿ payDBûݿ userDB ȣֱ洢ĿƷйصıûйصı -**4. 水平切分** +**4. ˮƽз** -把表中的数据按照某种规则存储到多个结构相同的表中,例如按 id 的散列值、性别等进行划分, +ѱеݰijֹ洢ṹͬıУ簴 id ɢֵԱȽл֣ -**5. 垂直切分与水平切分的选择** +**5. ֱзˮƽзֵѡ** -如果数据库中的表太多,并且项目各项业务逻辑清晰,那么垂直切分是首选。 +ݿеı̫࣬Ŀҵ߼ôֱзѡ -如果数据库的表不多,但是单表的数据量很大,应该选择水平切分。 +ݿı࣬ǵܴӦѡˮƽз֡ -**6. 水平切分的实现方式** +**6. ˮƽзֵʵַʽ** -最简单的是使用 merge 存储引擎。 +򵥵ʹ merge 洢档 -**7. 分库与分表存在的问题** +**7. ֱֿڵ** -(1) 事务问题 +(1) -在执行分库分表之后,由于数据存储到了不同的库上,数据库事务管理出现了困难。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价;如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。 +ִзֱֿ֮ݴ洢˲ͬĿϣݿѡݿⱾķֲʽȥִ񣬽ܴۣ߰ӦóȥЭƣγɳ߼ϵֻɱ̷ĸ -(2) 跨库跨表连接问题 +(2) -在执行了分库分表之后,难以避免会将原本逻辑关联性很强的数据划分到不同的表、不同的库上。这时,表的连接操作将受到限制,我们无法连接位于不同分库的表,也无法连接分表粒度不同的表,导致原本只需要一次查询就能够完成的业务需要进行多次才能完成。 +ִ˷ֱֿ֮ԱὫԭ߼ԺǿݻֵͬıͬĿϡʱӲܵƣ޷λڲֿͬıҲ޷ӷֱȲͬıԭֻҪһβѯܹɵҵҪжβɡ -# 故障转移和故障恢复 +# תƺ͹ϻָ -故障转移也叫做切换,当主库出现故障时就切换到备库,使备库成为主库。故障恢复顾名思义就是从故障中恢复过来,并且保证数据的正确性。 +תҲлֹʱл⣬ʹΪ⡣ϻָ˼Ǵӹлָұ֤ݵȷԡ -## 1. 故障转移 +## 1. ת -**1.1 提升备库或切换角色** +**1.1 лɫ** -提升一台备库为主库,或者在一个主-主复制结构中调整主动和被动角色。 +һ̨Ϊ⣬һ-ƽṹеͱɫ -**1.2 虚拟 IP 地址和 IP 托管** +**1.2 IP ַ IP й** -为 MySQL 实例指定一个逻辑 IP 地址,当 MySQL 实例失效时,可以将 IP 地址转移到另一台 MySQL 服务器上。 +Ϊ MySQL ʵָһ߼ IP ַ MySQL ʵʧЧʱԽ IP ַתƵһ̨ MySQL ϡ -**1.3 中间件解决方案** +**1.3 м** -通过代理,可以路由流量到可以使用的服务器上。 +ͨ·ʹõķϡ ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fabd5fa0-b75e-48d0-9e2c-31471945ceb9.jpg) -**1.4 在应用中处理故障转移** +**1.4 Ӧдת** -将故障转移整合到应用中可能导致应用变得太过笨拙。 +תϵӦпܵӦñ̫׾ -## 2. 故障恢复 +## 2. ϻָ -# 参考资料 +# ο -- 高性能 MySQL -- [MySQL 索引背后的数据结构及算法原理 ](http://blog.codinglabs.org/articles/theory-of-mysql-index.html) -- [MySQL 索引优化全攻略 ](http://www.runoob.com/w3cnote/mysql-index.html) -- [20+ 条 MySQL 性能优化的最佳经验 ](https://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html) +- MySQL +- [MySQL ݽṹ㷨ԭ ](http://blog.codinglabs.org/articles/theory-of-mysql-index.html) +- [MySQL Żȫ ](http://www.runoob.com/w3cnote/mysql-index.html) +- [20+ MySQL ŻѾ ](https://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html) diff --git a/notes/算法.md b/notes/算法.md index c2d4fa60..f738b9c8 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -18,63 +18,63 @@ * [5. union-find 㷨ıȽ](#5--union-find-㷨ıȽ) * [ڶ ](#ڶ-) * [㷨](#㷨) - * [Լ](#Լ) - * [ѡ](#ѡ) - * [](#) - * [ѡͲıȽ](#ѡͲıȽ) - * [ϣ](#ϣ) + * [1. Լ](#1-Լ) + * [2. ѡ](#2-ѡ) + * [3. ](#3-) + * [4. ѡͲıȽ](#4-ѡͲıȽ) + * [5. ϣ](#5-ϣ) * [鲢](#鲢) - * [鲢](#鲢) - * [Զ¹鲢](#Զ¹鲢) - * [ԵϹ鲢](#ԵϹ鲢) + * [1. 鲢](#1-鲢) + * [2. Զ¹鲢](#2-Զ¹鲢) + * [3. ԵϹ鲢](#3-ԵϹ鲢) * [](#) - * [㷨](#㷨) - * [з](#з) - * [ܷ](#ܷ) - * [㷨Ľ](#㷨Ľ) - * [л](#л) - * [ȡ](#ȡ) - * [з](#з) + * [1. 㷨](#1-㷨) + * [2. з](#2-з) + * [3. ܷ](#3-ܷ) + * [4. 㷨Ľ](#4-㷨Ľ) + * [4.1 л](#41-л) + * [4.2 ȡ](#42-ȡ) + * [4.3 з](#43-з) * [ȶ](#ȶ) - * [](#) - * [ϸ³](#ϸ³) - * [Ԫ](#Ԫ) - * [ɾԪ](#ɾԪ) - * [](#) - * [](#) + * [1. ](#1-) + * [2. ϸ³](#2-ϸ³) + * [3. Ԫ](#3-Ԫ) + * [4. ɾԪ](#4-ɾԪ) + * [5. ](#5-) + * [6. ](#6-) * [Ӧ](#Ӧ) - * [㷨ıȽ](#㷨ıȽ) - * [Java 㷨ʵ](#java-㷨ʵ) - * [зֵĿѡ㷨](#зֵĿѡ㷨) + * [1. 㷨ıȽ](#1-㷨ıȽ) + * [2. Java 㷨ʵ](#2-java-㷨ʵ) + * [3. зֵĿѡ㷨](#3-зֵĿѡ㷨) * [ ](#-) * [ű](#ű) - * [API](#api) - * [ű](#ű) - * [ʵ](#ʵ) - * [Ķֲ](#Ķֲ) - * [Զֲҵķ](#Զֲҵķ) + * [1. API](#1-api) + * [2. ű](#2-ű) + * [3. ʵ](#3-ʵ) + * [4. Ķֲ](#4-Ķֲ) + * [5. Զֲҵķ](#5-Զֲҵķ) * [](#) - * [get()](#get) - * [put()](#put) - * [](#) - * [floor()](#floor) - * [rank()](#rank) - * [min()](#min) - * [deleteMin()](#deletemin) - * [delete()](#delete) - * [keys()](#keys) - * [ܷ](#ܷ) + * [1. get()](#1-get) + * [2. put()](#2-put) + * [3. ](#3-) + * [4. floor()](#4-floor) + * [5. rank()](#5-rank) + * [6. min()](#6-min) + * [7. deleteMin()](#7-deletemin) + * [8. delete()](#8-delete) + * [9. keys()](#9-keys) + * [10. ܷ](#10-ܷ) * [ƽ](#ƽ) * [2-3 ](#2-3-) - * [](#) - * [](#) + * [1. ](#1-) + * [2. ](#2-) * [ڶ](#ڶ) - * [ת](#ת) - * [ת](#ת) - * [ɫת](#ɫת) - * [](#) - * [ɾС](#ɾС) - * [](#) + * [1. ת](#1-ת) + * [2. ת](#2-ת) + * [3. ɫת](#3-ɫת) + * [4. ](#4-) + * [5. ɾС](#5-ɾС) + * [6. ](#6-) * [ɢб](#ɢб) * [ɢк](#ɢк) * [ɢб](#ɢб) @@ -96,12 +96,10 @@ ### 1. ʵ + ```java public class ResizeArrayStack implements Iterable { - - // Ҫ Object Ȼתֱͣʹ new Item[1]; private Item[] a = (Item[]) new Object[1]; - // ջеԪظ private int N = 0; public void push(Item item) { @@ -158,6 +156,12 @@ public class ResizeArrayStack implements Iterable { } ``` +ʵʹ˷ͣJava ֱӴ飬ֻʹת + +```java +Item[] arr = (Item[]) new Object[N]; +``` + ### 2. ʵ Ҫʹͷ巨ʵ֣Ϊͷ巨ѹջԪĿͷ next ָָǰһѹջԪأڵԪʹͿǰһѹջԪسΪջԪء @@ -497,7 +501,7 @@ public class WeightedQuickUnionUF { ## 㷨 -### Լ +### 1. Լ ԪҪʵ Java Comparable ӿڣýӿ compareTo() @@ -517,7 +521,7 @@ private void exch(Comparable[] a, int i, int j){ } ``` -### ѡ +### 2. ѡ ҵеСԪأȻĵһԪؽλáȻٴʣµԪҵСԪأĵڶԪؽλáϽIJֱ @@ -540,7 +544,7 @@ public class Selection { ѡҪ \~N2/2 αȽϺ \~N νʱ޹أصʹһѾҲҪôıȽϺͽ -### +### 3. һԪز뵽Уʹò֮ҲġҲÿԪأÿβ֮󲿵ġ @@ -563,11 +567,11 @@ public class Insertion { ڲСģرЧ -### ѡͲıȽ +### 4. ѡͲıȽ ظ飬ѡʱƽģ֮һСij -### ϣ +### 5. ϣ ڴģ飬ΪֻܽڵԪأҪԪشһƵһˣҪܶβ @@ -605,7 +609,7 @@ public class Shell { ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dcf265ad-fe35-424d-b4b7-d149cdf239f4.png) -### 鲢 +### 1. 鲢 ```java public class MergeSort { @@ -628,7 +632,7 @@ public class MergeSort { } ``` -### Զ¹鲢 +### 2. Զ¹鲢 ```java public static void sort(Comparable[] a) { @@ -653,7 +657,7 @@ public class MergeSort { ΪСĵݹƵʹòС齫øߵܡ -### ԵϹ鲢 +### 3. ԵϹ鲢 ȹ鲢Щ΢飬ȻɶԹ鲢õ顣 @@ -673,7 +677,7 @@ public class MergeSort { ## -### 㷨 +### 1. 㷨 鲢Ϊֱ򣬲鲢ʹ򣻿ͨһзԪؽΪ飬СڵзԪأڵзԪأҲͽˡ @@ -695,7 +699,7 @@ public class QuickSort { } ``` -### з +### 2. з ȡ a[lo] ΪзԪأȻɨֱҵһڵԪأٴҶɨҵһСڵԪأԪأϼ̣ͿԱָ֤ԪضзԪأָ j ҲԪضСзԪءָʱзԪ a[lo] ҲԪ a[j] Ȼ󷵻 j ɡ @@ -716,7 +720,7 @@ public class QuickSort { } ``` -### ܷ +### 3. ܷ ԭ򣬲Ҫ飬ǵݹҪջ @@ -724,17 +728,17 @@ public class QuickSort { £һδСԪз֣ڶδӵڶСԪз֣㡣ҪȽ N2/2Ϊ˷ֹʼģڽпʱҪ顣 -### 㷨Ľ +### 4. 㷨Ľ -#### л +#### 4.1 л ΪСҲԼС飬ȿܸãСпл -#### ȡ +#### 4.2 ȡ õÿζȡλΪзԪأǼλĴۺܸߡǷȡ 3 ԪزСеԪΪзԪصЧá -#### з +#### 4.3 з дظԪص飬ԽзΪֱ֣ӦСڡںʹзԪء @@ -764,7 +768,7 @@ public class Quick3Way { ȶҪڴԪء -### +### 1. 壺һŶÿڵ㶼ڵӽڵ㡣 @@ -801,7 +805,7 @@ public class MaxPQ { } ``` -### ϸ³ +### 2. ϸ³ ڶУһڵȸڵôҪڵ㡣󻹿ܱµĸڵҪϵؽбȽϺͽֲΪϸ @@ -828,7 +832,7 @@ private void sink(int k) { } ``` -### Ԫ +### 3. Ԫ ԪطŵĩβȻϸʵλá @@ -839,7 +843,7 @@ public void insert(Key v) { } ``` -### ɾԪ +### 4. ɾԪ 鶥ɾԪأһԪطŵˣԪ³ʵλá @@ -853,9 +857,9 @@ public Key delMax() { } ``` -### +### 5. -ڶѿԺ׵õԪزɾϵؽֲԵõһݼСԪغ͵ǰһԪؽλãҲɾôͿԵõһβͷĵݼУһС˺ʹö򣬲Ҷԭ򣬲ռöռ䡣 +ڶѿԺ׵õԪزɾϵؽֲԵõһݼСԪغ͵ǰһԪؽλãҲɾôͿԵõһβͷĵݼУһС˺ʹö򣬲Ҷԭ򣬲ռöռ䡣 Ҫ׶Σһ׶ǰ齨һѣڶ׶ǽԪغ͵ǰѵһԪأҽ³άֶѵ״̬ @@ -876,7 +880,7 @@ public static void sort(Comparable[] a){ } ``` -### +### 6. һѵĸ߶Ϊ lgNڶвԪغɾԪصĸӶȶΪ lgN @@ -888,17 +892,17 @@ public static void sort(Comparable[] a){ ## Ӧ -### 㷨ıȽ +### 1. 㷨ıȽ ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/be53c00b-2534-4dc6-ad03-c55995c47db9.jpg) -ʱͨ㷨ѭָ٣û棬Ϊ˳طݡʱΪ $\~cNlgN$ c Զ㷨ҪСʹз֮ʵӦпֵܳijЩֲܹﵽ Լ𣬶㷨ȻҪԶʱ䡣 +ʱͨ㷨ѭָ٣û棬Ϊ˳طݡʱΪ \~cNlgN c Զ㷨ҪСʹз֮ʵӦпֵܳijЩֲܹﵽԼ𣬶㷨ȻҪԶʱ䡣 -### Java 㷨ʵ +### 2. Java 㷨ʵ Java ϵͳеҪ򷽷Ϊ java.util.Arrays.sort()ԭʼʹзֵĿ򣬶ʹù鲢 -### зֵĿѡ㷨 +### 3. зֵĿѡ㷨 partition() Ὣ a[lo] a[hi] 򲢷һ j ʹ a[lo..j-1] Сڵ a[j] a[j+1..hi] ڵ a[j]ô j=ka[j] ǵ k @@ -917,20 +921,19 @@ Java ϵͳ } ``` - # ʹ־ʵָЧķűɢб ## ű -### API +### 1. API ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b69d7184-ab62-4957-ba29-fb4fa25f9b65.jpg) һֵΪ null ʱʾ˿ʹ put(key, null) Ϊ delete(key) һӳʵ֡ -### ű +### 2. ű ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ba6ae411-82da-4d86-a434-6776d1731e8e.jpg) @@ -938,11 +941,11 @@ Java ϵͳ ҵijɱģͣıȽϴڲбȽʱʹķʴ -### ʵ +### 3. ʵ Ӷȣһձв N ͬļҪ \~N2/2 αȽϡ -### Ķֲ +### 4. Ķֲ ʹһƽ飬һ洢һ洢ֵ @@ -1007,7 +1010,7 @@ public class BinarySearchST, Value> { } ``` -### Զֲҵķ +### 5. Զֲҵķ ӶȣֲҪ lgN+1 αȽϣʹöֲʵֵķűIJҲҪʱǶġDzҪƶԪأԼġ @@ -1027,7 +1030,8 @@ public class BST, Value> { private Key key; private Value val; private Node left, right; - private int N; // ԸýڵΪнڵ + // ԸýڵΪнڵ + private int N; public Node(Key key, Value val, int N) { this.key = key; @@ -1047,7 +1051,7 @@ public class BST, Value> { } ``` -### get() +### 1. get() ǿյģδУҵļ͸ڵļȣУݹвңҵļСвңϴвҡ @@ -1064,7 +1068,7 @@ private Value get(Node x, Key key) { } ``` -### put() +### 2. put() ļУҪһ½ڵ㣬ҸϲڵʹøýڵȷӵС @@ -1083,7 +1087,7 @@ private Node put(Node x, Key key, Value val) { } ``` -### +### 3. 㷨ʱȡ״״ȡڼȺ˳õȫƽģÿӺ͸ڵľ붼Ϊ lgN£ĸ߶Ϊ N @@ -1091,7 +1095,7 @@ private Node put(Node x, Key key, Value val) { ӶȣҺͲΪ -### floor() +### 4. floor() key Сڸڵ keyôСڵ key ڵһУ key ڸڵ keyֻеڵдСڵ key Ľڵ㣬Сڵ key ڵУڵСڵ key ڵ㡣 @@ -1115,7 +1119,7 @@ private Node floor(Node x, Key key) { } ``` -### rank() +### 5. rank() ```java public int rank(Key key) { @@ -1130,7 +1134,7 @@ private int rank(Key key, Node x) { } ``` -### min() +### 6. min() ```java private Node min(Node x) { @@ -1139,7 +1143,7 @@ private Node min(Node x) { } ``` -### deleteMin() +### 7. deleteMin() ָСڵָСڵ @@ -1157,7 +1161,7 @@ public Node deleteMin(Node x) { } ``` -### delete() +### 8. delete() ɾĽڵֻôֻҪָڵָΨһɣСڵ滻ýڵ㡣 @@ -1185,7 +1189,7 @@ private Node delete(Node x, Key key) { } ``` -### keys() +### 9. keys() öĽΪеص㡣 @@ -1205,7 +1209,7 @@ private void keys(Node x, Queue queue, Key lo, Key hi) { } ``` -### ܷ +### 10. ܷ ӶȣвҪʱ䶼ĸ߶ȳȡ @@ -1217,13 +1221,13 @@ private void keys(Node x, Queue queue, Key lo, Key hi) { һƽ 2-3 пӵڵľӦͬġ -#### +#### 1. ֮һʱ 4- ڵʱҪ 4- ڵѳ 3 2- ڵ㣬м 2- ڵƵϲڵУƲʱ 4- ڵһֱзƣֱʱ 4- ڵ㡣 ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/912174d8-0786-4222-b7ef-a611d36e5db9.jpg) -#### +#### 2. 2-3 ı任ǾֲģصĽڵ֮ⲻ޸Ļ߼֣Щֲ任ӰȫԺƽԡ @@ -1272,7 +1276,7 @@ public class RedBlackBST, Value> { } ``` -#### ת +#### 1. ת ΪϷĺӶΪӣΪӣôҪת @@ -1293,7 +1297,7 @@ public Node rotateLeft(Node h) { } ``` -#### ת +#### 2. ת תΪתӣ֮IJ̽֡ @@ -1313,7 +1317,7 @@ public Node rotateRight(Node h) { } ``` -#### ɫת +#### 3. ɫת һ 4- ڵںбΪһڵӽڵ㶼Ǻɫġ 4- ڵҪӽڵɫɺ֮⣬ͬʱҪڵɫɺڱ죬 2-3 ĽǶȿǽмڵƵϲڵ㡣 @@ -1329,7 +1333,7 @@ void flipColors(Node h){ } ``` -#### +#### 4. 㷨 @@ -1365,7 +1369,7 @@ private Node put(Node x, Key key, Value val) { ڵһΪɫΪڵûϲڵ㣬Ҳûϲڵָڵ㡣flipColors() пܻʹøڵɫΪɫÿڵɺɫɺɫʱĺӸ߶ȼ 1. -#### ɾС +#### 5. ɾС Сһ 2- ڵУôɾüһӣƻƽԣҪȷС 2- ڵС 2- ڵת 3- ڵ 4- ڵַһϲڵһ keyֵܽڵһ keyϲڵ 2- ڵ㣬ôû취ϲڵ key ˣҪ֤ɾ·ϵнڵ㶼 2- ڵ㡣ɾĹУ֤֮һ @@ -1379,7 +1383,7 @@ private Node put(Node x, Key key, Value val) { ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/70b66757-755c-4e17-a7b7-5ce808023643.png) -#### +#### 6. һŴСΪ N ĺĸ߶Ȳᳬ 2lgNӦ 2-3 йߵ·ڵȫ 3- ڵ඼ 2- ڵ㡣