diff --git a/docs.rar b/docs.rar
new file mode 100644
index 00000000..4e6d7fb5
Binary files /dev/null and b/docs.rar differ
diff --git a/docs/notes/Docker.md b/docs/notes/Docker.md
index 1b61a7fe..da6e2bf4 100644
--- a/docs/notes/Docker.md
+++ b/docs/notes/Docker.md
@@ -8,7 +8,7 @@
-
+
# 一、解决的问题
@@ -20,9 +20,9 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
-
+
-
+
## 启动速度
@@ -76,7 +76,7 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
构建容器时,通过在镜像的基础上添加一个可写层(writable layer),用来保存着容器运行过程中的修改。
-
+
# 参考资料
diff --git a/docs/notes/Git.md b/docs/notes/Git.md
index 4d4cbb2b..41e2b16c 100644
--- a/docs/notes/Git.md
+++ b/docs/notes/Git.md
@@ -34,20 +34,20 @@ Github 就是一个中心服务器。
# 工作流
-
+
新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git,它属于 Git 的版本库。
Git 版本库有一个称为 stage 的暂存区,还有自动创建的 master 分支以及指向分支的 HEAD 指针。
-
+
- git add files 把文件的修改添加到暂存区
- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
-
+
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
@@ -58,25 +58,25 @@ Git 版本库有一个称为 stage 的暂存区,还有自动创建的 master
使用指针将每个提交连接成一条时间线,HEAD 指针指向当前分支指针。
-
+
新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
-
+
每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
-
+
合并分支也只需要改变指针即可。
-
+
# 冲突
当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
-
+
Git 会使用 <<<<<<< ,======= ,>>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
@@ -98,7 +98,7 @@ Creating a new branch is quick AND simple.
$ git merge --no-ff -m "merge with no-ff" dev
```
-
+
# 分支管理策略
@@ -106,7 +106,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
日常开发在开发分支 dev 上进行。
-
+
# 储藏(Stashing)
@@ -146,7 +146,7 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
# Git 命令一览
-
+
比较详细的地址:http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
diff --git a/docs/notes/HTTP.md b/docs/notes/HTTP.md
index ffe01382..747ea9c6 100644
--- a/docs/notes/HTTP.md
+++ b/docs/notes/HTTP.md
@@ -66,17 +66,17 @@ URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基
- URL(Uniform Resource Locator,统一资源定位符)
- URN(Uniform Resource Name,统一资源名称)
-
+
## 请求和响应报文
### 1. 请求报文
-
+
### 2. 响应报文
-
+
# 二、HTTP 方法
@@ -163,7 +163,7 @@ DELETE /file.html HTTP/1.1
CONNECT www.example.com:443 HTTP/1.1
```
-
+
## TRACE
@@ -305,7 +305,7 @@ CONNECT www.example.com:443 HTTP/1.1
## 连接管理
-
+
### 1. 短连接与长连接
@@ -634,11 +634,11 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
- 用户察觉得到正向代理的存在。
-
+
- 而反向代理一般位于内部网络中,用户察觉不到。
-
+
### 2. 网关
@@ -660,7 +660,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
通过使用 SSL,HTTPs 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
-
+
## 加密
@@ -671,7 +671,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
- 优点:运算速度快;
- 缺点:无法安全地将密钥传输给通信方。
-
+
### 2.非对称密钥加密
@@ -684,13 +684,13 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
- 优点:可以更安全地将公开密钥传输给通信发送方;
- 缺点:运算速度慢。
-
+
### 3. HTTPs 采用的加密方式
HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
-
+
## 认证
@@ -704,7 +704,7 @@ HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对
通信开始时,客户端需要使用服务器的公开密钥将自己的私有密钥传输给服务器,之后再进行对称密钥加密。
-
+
## 完整性保护
@@ -732,7 +732,7 @@ HTTP/1.x 实现简单是以牺牲性能为代价的:
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
-
+
在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。
@@ -740,13 +740,13 @@ HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式
- 消息(Message)是与逻辑请求或响应对应的完整的一系列帧。
- 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
-
+
## 服务端推送
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
-
+
## 首部压缩
@@ -756,7 +756,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见
不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
-
+
# 八、HTTP/1.1 新特性
diff --git a/docs/notes/Java IO.md b/docs/notes/Java IO.md
index 1b857bc7..c103a9f0 100644
--- a/docs/notes/Java IO.md
+++ b/docs/notes/Java IO.md
@@ -97,7 +97,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
-
+
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
@@ -277,7 +277,7 @@ public static void main(String[] args) throws IOException {
- Socket:客户端类
- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
-
+
## Datagram
@@ -339,23 +339,23 @@ I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
-
+
② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5,limit 保持不变。
-
+
③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。
-
+
④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
-
+
⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
-
+
## 文件 NIO 实例
@@ -413,7 +413,7 @@ NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用
应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
-
+
### 1. 创建选择器
diff --git a/docs/notes/Java 基础.md b/docs/notes/Java 基础.md
index 6707cc28..63998c7d 100644
--- a/docs/notes/Java 基础.md
+++ b/docs/notes/Java 基础.md
@@ -167,7 +167,7 @@ public final class String
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
-
+
**3. 安全性**
@@ -1236,7 +1236,7 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
-
+
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
diff --git a/docs/notes/Java 容器.md b/docs/notes/Java 容器.md
index dbd41edc..67bf0ac2 100644
--- a/docs/notes/Java 容器.md
+++ b/docs/notes/Java 容器.md
@@ -25,7 +25,7 @@
## Collection
-
+
### 1. Set
@@ -51,7 +51,7 @@
## Map
-
+
- TreeMap:基于红黑树实现。
@@ -66,7 +66,7 @@
## 迭代器模式
-
+
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
@@ -387,7 +387,7 @@ transient Node first;
transient Node last;
```
-
+
### 2. 与 ArrayList 的比较
@@ -409,7 +409,7 @@ transient Entry[] table;
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
-
+
```java
static class Entry implements Map.Entry {
@@ -485,7 +485,7 @@ map.put("K3", "V3");
- 计算键值对所在的桶;
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
-
+
### 3. put 操作
@@ -821,7 +821,7 @@ final Segment[] segments;
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
```
-
+
### 2. size 操作
diff --git a/docs/notes/Java 并发.md b/docs/notes/Java 并发.md
index 024f6636..ac91c755 100644
--- a/docs/notes/Java 并发.md
+++ b/docs/notes/Java 并发.md
@@ -61,7 +61,7 @@
# 一、线程状态转换
-
+
## 新建(New)
@@ -736,7 +736,7 @@ java.util.concurrent(J.U.C)大大提高了并发性能,AQS 被认为是 J.
维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
-
+
```java
public class CountdownLatchExample {
@@ -785,7 +785,7 @@ public CyclicBarrier(int parties) {
}
```
-
+
```java
public class CyclicBarrierExample {
@@ -818,7 +818,7 @@ before..before..before..before..before..before..before..before..before..before..
Semaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。
-
+
以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。
@@ -1024,7 +1024,7 @@ public class ForkJoinPool extends AbstractExecutorService
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列,用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务,避免和队列所属线程发生竞争。例如下图中,Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务,Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
-
+
# 九、线程不安全示例
@@ -1079,19 +1079,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
-
+
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
-
+
## 内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
-
+
- read:把一个变量的值从主内存传输到工作内存中
- load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
@@ -1114,11 +1114,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
下图演示了两个线程同时对 cnt 进行操作,load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存,T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
-
+
AtomicInteger 能保证多个线程修改的原子性。
-
+
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
@@ -1226,7 +1226,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
在一个线程内,在程序前面的操作先行发生于后面的操作。
-
+
### 2. 管程锁定规则
@@ -1234,7 +1234,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
-
+
### 3. volatile 变量规则
@@ -1242,7 +1242,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
-
+
### 4. 线程启动规则
@@ -1250,7 +1250,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
-
+
### 5. 线程加入规则
@@ -1258,7 +1258,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
Thread 对象的结束先行发生于 join() 方法返回。
-
+
### 6. 线程中断规则
@@ -1476,7 +1476,7 @@ public class ThreadLocalExample1 {
它所对应的底层结构图为:
-
+
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
@@ -1579,17 +1579,17 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
-
+
下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象,包含了 Mark Word 和其它信息。
-
+
轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
当尝试获取一个锁对象时,如果锁对象标记为 0 01,说明锁对象的锁未锁定(unlocked)状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record,然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00,表示该对象处于轻量级锁状态。
-
+
如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
@@ -1601,7 +1601,7 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定状态或者轻量级锁状态。
-
+
# 十三、多线程开发良好的实践
diff --git a/docs/notes/Java 虚拟机.md b/docs/notes/Java 虚拟机.md
index 3138a170..ed273c00 100644
--- a/docs/notes/Java 虚拟机.md
+++ b/docs/notes/Java 虚拟机.md
@@ -30,7 +30,7 @@
# 一、运行时数据区域
-
+
## 程序计数器
@@ -40,7 +40,7 @@
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
-
+
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
@@ -59,7 +59,7 @@ java -Xss512M HackTheJava
本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
-
+
## 堆
@@ -143,7 +143,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收,在 Java 中 GC
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
-
+
### 3. 方法区的回收
@@ -225,7 +225,7 @@ obj = null;
### 1. 标记 - 清除
-
+
标记要回收的对象,然后清除。
@@ -236,13 +236,13 @@ obj = null;
### 2. 标记 - 整理
-
+
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
### 3. 复制
-
+
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
@@ -263,7 +263,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1,保证了
## 垃圾收集器
-
+
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
@@ -272,7 +272,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1,保证了
### 1. Serial 收集器
-
+
Serial 翻译为串行,也就是说它以串行的方式执行。
@@ -284,7 +284,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 2. ParNew 收集器
-
+
它是 Serial 收集器的多线程版本。
@@ -306,7 +306,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 4. Serial Old 收集器
-
+
是 Serial 收集器的老年代版本,也是给 Client 模式下的虚拟机使用。如果用在 Server 模式下,它有两大用途:
@@ -315,7 +315,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 5. Parallel Old 收集器
-
+
是 Parallel Scavenge 收集器的老年代版本。
@@ -323,7 +323,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 6. CMS 收集器
-
+
CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。
@@ -348,17 +348,17 @@ G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,
堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
-
+
G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。
-
+
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。
-
+
如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:
@@ -446,7 +446,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
## 类的生命周期
-
+
包括以下 7 个阶段:
@@ -622,7 +622,7 @@ System.out.println(ConstClass.HELLOWORLD);
下图展示的类加载器之间的层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。这里类加载器之间的父子关系一般通过组合(Composition)关系来实现,而不是通过继承(Inheritance)的关系实现。
-
+
### 1. 工作过程
diff --git a/docs/notes/Leetcode 题解.md b/docs/notes/Leetcode 题解.md
index e68d7582..546976bf 100644
--- a/docs/notes/Leetcode 题解.md
+++ b/docs/notes/Leetcode 题解.md
@@ -463,7 +463,7 @@ public String frequencySort(String s) {
它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。
-
+
**按颜色进行排序**
@@ -1178,7 +1178,7 @@ public List diffWaysToCompute(String input) {
### BFS
-
+
广度优先搜索一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。
@@ -1407,7 +1407,7 @@ private int getShortestPath(List[] graphic, int start, int end) {
### DFS
-
+
广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历。
@@ -1718,7 +1718,7 @@ Backtracking(回溯)属于 DFS。
[17. Letter Combinations of a Phone Number (Medium)](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/)
-
+
```html
Input:Digit string "23"
@@ -2295,7 +2295,7 @@ private boolean isPalindrome(String s, int begin, int end) {
[37. Sudoku Solver (Hard)](https://leetcode.com/problems/sudoku-solver/description/)
-
+
```java
private boolean[][] rowsUsed = new boolean[9][10];
@@ -2357,7 +2357,7 @@ private int cubeNum(int i, int j) {
[51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/)
-
+
在 n\*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,求所有的 n 皇后的解。
@@ -2365,11 +2365,11 @@ private int cubeNum(int i, int j) {
45 度对角线标记数组的长度为 2 \* n - 1,通过下图可以明确 (r, c) 的位置所在的数组下标为 r + c。
-
+
135 度对角线标记数组的长度也是 2 \* n - 1,(r, c) 的位置所在的数组下标为 n - 1 - (r - c)。
-
+
```java
private List> solutions;
@@ -2571,7 +2571,7 @@ public int minPathSum(int[][] grid) {
题目描述:统计从矩阵左上角到右下角的路径总数,每次只能向右或者向下移动。
-
+
```java
public int uniquePaths(int m, int n) {
@@ -3302,7 +3302,7 @@ public int combinationSum4(int[] nums, int target) {
题目描述:交易之后需要有一天的冷却时间。
-
+
```java
public int maxProfit(int[] prices) {
@@ -3343,7 +3343,7 @@ The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
题目描述:每交易一次,都要支付一定的费用。
-
+
```java
public int maxProfit(int[] prices, int fee) {
@@ -5299,7 +5299,7 @@ private void inOrder(TreeNode node, List nums) {
### Trie
-
+
Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。
diff --git a/docs/notes/Linux.md b/docs/notes/Linux.md
index a8ca85a3..a681ff10 100644
--- a/docs/notes/Linux.md
+++ b/docs/notes/Linux.md
@@ -157,7 +157,7 @@ Linux 发行版是 Linux 内核及各种应用软件的集成版本。
- 编辑模式(Insert mode):按下 "i" 等按键之后进入,可以对文本进行编辑;
- 指令列模式(Bottom-line mode):按下 ":" 按键之后进入,用于保存退出等操作。
-
+
在指令列模式下,有以下命令用于离开或者保存文件。
@@ -191,25 +191,25 @@ GNU 计划,译为革奴计划,它的目标是创建一套完全自由的操
IDE(ATA)全称 Advanced Technology Attachment,接口速度最大为 133MB/s,因为并口线的抗干扰性太差,且排线占用空间较大,不利电脑内部散热,已逐渐被 SATA 所取代。
-
+
### 2. SATA
SATA 全称 Serial ATA,也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多,支持热插拔等功能。SATA-II 的接口速度为 300MiB/s,而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。
-
+
### 3. SCSI
SCSI 全称是 Small Computer System Interface(小型机系统接口),经历多代的发展,从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel(光纤通道),接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。
-
+
### 4. SAS
SAS(Serial Attached SCSI)是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。
-
+
## 磁盘的文件名
@@ -244,7 +244,7 @@ GPT 没有扩展分区概念,都是主分区,每个 LAB 可以分 4 个分
MBR 不支持 2.2 TB 以上的硬盘,GPT 则最多支持到 233 TB = 8 ZB。
-
+
## 开机检测程序
@@ -252,7 +252,7 @@ MBR 不支持 2.2 TB 以上的硬盘,GPT 则最多支持到 233 TB
BIOS(Basic Input/Output System,基本输入输出系统),它是一个固件(嵌入在硬件中的软件),BIOS 程序存放在断电后内容不会丢失的只读内存中。
-
+
BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可以开机的磁盘,并读取磁盘第一个扇区的主要开机记录(MBR),由主要开机记录(MBR)执行其中的开机管理程序,这个开机管理程序会加载操作系统的核心文件。
@@ -260,7 +260,7 @@ BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可
下图中,第一扇区的主要开机记录(MBR)中的开机管理程序提供了两个选单:M1、M2,M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。
-
+
安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录(MBR),而 Linux 可以选择将开机管理程序安装在主要开机记录(MBR)或者其它分区的启动扇区,并且可以设置开机管理程序的选单。
@@ -286,17 +286,17 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。
- superblock:记录文件系统的整体信息,包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
- block bitmap:记录 block 是否被使用的位域。
-
+
## 文件读取
对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block,然后把所有 block 的内容读出来。
-
+
而对于 FAT 文件系统,它没有 inode,每个 block 中存储着下一个 block 的编号。
-
+
## 磁盘碎片
@@ -333,7 +333,7 @@ inode 具有以下特点:
inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。
-
+
## 目录
@@ -359,7 +359,7 @@ ext3/ext4 文件系统引入了日志功能,可以利用日志来修复文件
- /usr (unix software resource):所有系统默认软件都会安装到这个目录;
- /var (variable):存放系统或程序运行过程中的数据文件。
-
+
# 五、文件
@@ -534,7 +534,7 @@ cp [-adfilprsu] source destination
-f :如果目标文件存在时,先删除目标文件
```
-
+
### 1. 实体链接
@@ -655,7 +655,7 @@ example: find . -name "shadow*"
+4、4 和 -4 的指示的时间范围如下:
-
+
**② 与文件拥有者和所属群组有关的选项**
@@ -1168,7 +1168,7 @@ dmtsai lines: 5 columns: 9
| Z | zombie (terminated but not reaped by its parent) |
| T | stopped (either by a job control signal or because it is being traced) |
-
+
## SIGCHLD
@@ -1181,7 +1181,7 @@ dmtsai lines: 5 columns: 9
在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
-
+
## wait()
diff --git a/docs/notes/MySQL.md b/docs/notes/MySQL.md
index bb02df8b..a858442a 100644
--- a/docs/notes/MySQL.md
+++ b/docs/notes/MySQL.md
@@ -42,7 +42,7 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1 ,且不为 null,则该指针指向节点的所有 key 大于等于 keyi 且小于等于 keyi+1 。
-
+
### 2. 操作
@@ -84,11 +84,11 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
-
+
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
-
+
### 2. 哈希索引
@@ -350,7 +350,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
-
+
## 垂直切分
@@ -358,7 +358,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
-
+
## Sharding 策略
@@ -392,7 +392,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
- **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的重放日志(Replay log)中。
- **SQL 线程** :负责读取重放日志并重放其中的 SQL 语句。
-
+
## 读写分离
@@ -406,7 +406,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
-
+
# 参考资料
diff --git a/docs/notes/Redis.md b/docs/notes/Redis.md
index e4653567..686f6ec9 100644
--- a/docs/notes/Redis.md
+++ b/docs/notes/Redis.md
@@ -67,7 +67,7 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
## STRING
-
+
```html
> set hello world
@@ -82,7 +82,7 @@ OK
## LIST
-
+
```html
> rpush list-key item
@@ -110,7 +110,7 @@ OK
## SET
-
+
```html
> sadd set-key item
@@ -144,7 +144,7 @@ OK
## HASH
-
+
```html
> hset hash-key sub-key1 value1
@@ -175,7 +175,7 @@ OK
## ZSET
-
+
```html
> zadd zset-key 728 member1
@@ -317,11 +317,11 @@ int dictRehash(dict *d, int n) {
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
-
+
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
-
+
与红黑树等平衡树相比,跳跃表具有以下优点:
@@ -472,7 +472,7 @@ Redis 服务器是一个事件驱动程序。
Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。
-
+
## 时间事件
@@ -525,7 +525,7 @@ def main():
从事件处理的角度来看,服务器运行流程如下:
-
+
# 十一、复制
@@ -545,7 +545,7 @@ def main():
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
-
+
# 十二、Sentinel
@@ -580,7 +580,7 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID,通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617,其中 article 为命名空间,ID 为 92617。
-
+
## 点赞功能
@@ -588,13 +588,13 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。
-
+
## 对文章进行排序
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
-
+
# 参考资料
diff --git a/docs/notes/Socket.md b/docs/notes/Socket.md
index 3310fda0..1bb87e50 100644
--- a/docs/notes/Socket.md
+++ b/docs/notes/Socket.md
@@ -46,7 +46,7 @@ Unix 有五种 I/O 模型:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
```
-
+
## 非阻塞式 I/O
@@ -54,7 +54,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率是比较低的。
-
+
## I/O 复用
@@ -64,7 +64,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
-
+
## 信号驱动 I/O
@@ -72,7 +72,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
-
+
## 异步 I/O
@@ -80,7 +80,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
-
+
## 五大 I/O 模型比较
@@ -91,7 +91,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
-
+
# 二、I/O 复用
diff --git a/docs/notes/pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png b/docs/notes/pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png
new file mode 100644
index 00000000..0e56341c
Binary files /dev/null and b/docs/notes/pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png differ
diff --git a/docs/notes/pics/014fbc4d-d873-4a12-b160-867ddaed9807.jpg b/docs/notes/pics/014fbc4d-d873-4a12-b160-867ddaed9807.jpg
new file mode 100644
index 00000000..39c003ce
Binary files /dev/null and b/docs/notes/pics/014fbc4d-d873-4a12-b160-867ddaed9807.jpg differ
diff --git a/docs/notes/pics/0157d362-98dd-4e51-ac26-00ecb76beb3e.png b/docs/notes/pics/0157d362-98dd-4e51-ac26-00ecb76beb3e.png
new file mode 100644
index 00000000..fc0999f9
Binary files /dev/null and b/docs/notes/pics/0157d362-98dd-4e51-ac26-00ecb76beb3e.png differ
diff --git a/docs/notes/pics/026d3cb4-67f7-4a83-884d-8032f57ec446.png b/docs/notes/pics/026d3cb4-67f7-4a83-884d-8032f57ec446.png
new file mode 100644
index 00000000..26d62519
Binary files /dev/null and b/docs/notes/pics/026d3cb4-67f7-4a83-884d-8032f57ec446.png differ
diff --git a/docs/notes/pics/02986f62-c641-44a8-a55f-983581490e0c.png b/docs/notes/pics/02986f62-c641-44a8-a55f-983581490e0c.png
new file mode 100644
index 00000000..96726ebc
Binary files /dev/null and b/docs/notes/pics/02986f62-c641-44a8-a55f-983581490e0c.png differ
diff --git a/docs/notes/pics/037c3a0b-332d-434d-a374-f343ef72c8e1.jpg b/docs/notes/pics/037c3a0b-332d-434d-a374-f343ef72c8e1.jpg
new file mode 100644
index 00000000..68950556
Binary files /dev/null and b/docs/notes/pics/037c3a0b-332d-434d-a374-f343ef72c8e1.jpg differ
diff --git a/docs/notes/pics/03f47940-3843-4b51-9e42-5dcaff44858b.jpg b/docs/notes/pics/03f47940-3843-4b51-9e42-5dcaff44858b.jpg
new file mode 100644
index 00000000..9a6f75c6
Binary files /dev/null and b/docs/notes/pics/03f47940-3843-4b51-9e42-5dcaff44858b.jpg differ
diff --git a/docs/notes/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png b/docs/notes/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png
new file mode 100644
index 00000000..57d8c810
Binary files /dev/null and b/docs/notes/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png differ
diff --git a/docs/notes/pics/04f41228-375d-4b7d-bfef-738c5a7c8f07.jpg b/docs/notes/pics/04f41228-375d-4b7d-bfef-738c5a7c8f07.jpg
new file mode 100644
index 00000000..17eb93b6
Binary files /dev/null and b/docs/notes/pics/04f41228-375d-4b7d-bfef-738c5a7c8f07.jpg differ
diff --git a/docs/notes/pics/051e436c-0e46-4c59-8f67-52d89d656182.png b/docs/notes/pics/051e436c-0e46-4c59-8f67-52d89d656182.png
new file mode 100644
index 00000000..e3054539
Binary files /dev/null and b/docs/notes/pics/051e436c-0e46-4c59-8f67-52d89d656182.png differ
diff --git a/docs/notes/pics/05907ab4-42c5-4b5e-9388-6617f6c97bea.jpg b/docs/notes/pics/05907ab4-42c5-4b5e-9388-6617f6c97bea.jpg
new file mode 100644
index 00000000..e1d7df60
Binary files /dev/null and b/docs/notes/pics/05907ab4-42c5-4b5e-9388-6617f6c97bea.jpg differ
diff --git a/docs/notes/pics/061c29ce-e2ed-425a-911e-56fbba1efce3.jpg b/docs/notes/pics/061c29ce-e2ed-425a-911e-56fbba1efce3.jpg
new file mode 100644
index 00000000..29d32e72
Binary files /dev/null and b/docs/notes/pics/061c29ce-e2ed-425a-911e-56fbba1efce3.jpg differ
diff --git a/docs/notes/pics/061c88c1-572f-424f-b580-9cbce903a3fe.png b/docs/notes/pics/061c88c1-572f-424f-b580-9cbce903a3fe.png
new file mode 100644
index 00000000..eb25a980
Binary files /dev/null and b/docs/notes/pics/061c88c1-572f-424f-b580-9cbce903a3fe.png differ
diff --git a/docs/notes/pics/0635cbe8.png b/docs/notes/pics/0635cbe8.png
new file mode 100644
index 00000000..849c9eaf
Binary files /dev/null and b/docs/notes/pics/0635cbe8.png differ
diff --git a/docs/notes/pics/06976908-98ab-46e9-a632-f0c2760ec46c.png b/docs/notes/pics/06976908-98ab-46e9-a632-f0c2760ec46c.png
new file mode 100644
index 00000000..f042f8f6
Binary files /dev/null and b/docs/notes/pics/06976908-98ab-46e9-a632-f0c2760ec46c.png differ
diff --git a/docs/notes/pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg b/docs/notes/pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg
new file mode 100644
index 00000000..b8b100a0
Binary files /dev/null and b/docs/notes/pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg differ
diff --git a/docs/notes/pics/07717718-1230-4347-aa18-2041c315e670.jpg b/docs/notes/pics/07717718-1230-4347-aa18-2041c315e670.jpg
new file mode 100644
index 00000000..456bd952
Binary files /dev/null and b/docs/notes/pics/07717718-1230-4347-aa18-2041c315e670.jpg differ
diff --git a/docs/notes/pics/07903a31-0fb3-45fc-86f5-26f0b28fa4e7.png b/docs/notes/pics/07903a31-0fb3-45fc-86f5-26f0b28fa4e7.png
new file mode 100644
index 00000000..40573164
Binary files /dev/null and b/docs/notes/pics/07903a31-0fb3-45fc-86f5-26f0b28fa4e7.png differ
diff --git a/docs/notes/pics/08427d38-8df1-49a1-8990-e0ce5ee36ca2.png b/docs/notes/pics/08427d38-8df1-49a1-8990-e0ce5ee36ca2.png
new file mode 100644
index 00000000..13d49836
Binary files /dev/null and b/docs/notes/pics/08427d38-8df1-49a1-8990-e0ce5ee36ca2.png differ
diff --git a/docs/notes/pics/0889c0b4-07b4-45fc-873c-e0e16b97f67d.png b/docs/notes/pics/0889c0b4-07b4-45fc-873c-e0e16b97f67d.png
new file mode 100644
index 00000000..4d9e3e21
Binary files /dev/null and b/docs/notes/pics/0889c0b4-07b4-45fc-873c-e0e16b97f67d.png differ
diff --git a/docs/notes/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg b/docs/notes/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg
new file mode 100644
index 00000000..09bbd597
Binary files /dev/null and b/docs/notes/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg differ
diff --git a/docs/notes/pics/09b52bcb-88ba-4e36-8244-b375f16ad116.jpg b/docs/notes/pics/09b52bcb-88ba-4e36-8244-b375f16ad116.jpg
new file mode 100644
index 00000000..146336aa
Binary files /dev/null and b/docs/notes/pics/09b52bcb-88ba-4e36-8244-b375f16ad116.jpg differ
diff --git a/docs/notes/pics/09e6e8d4-4d83-4949-b908-6d6b4c2fd064.png b/docs/notes/pics/09e6e8d4-4d83-4949-b908-6d6b4c2fd064.png
new file mode 100644
index 00000000..f76e5b5f
Binary files /dev/null and b/docs/notes/pics/09e6e8d4-4d83-4949-b908-6d6b4c2fd064.png differ
diff --git a/docs/notes/pics/0a9f4125-b6ab-4e94-a807-fd7070ae726a.png b/docs/notes/pics/0a9f4125-b6ab-4e94-a807-fd7070ae726a.png
new file mode 100644
index 00000000..395d9201
Binary files /dev/null and b/docs/notes/pics/0a9f4125-b6ab-4e94-a807-fd7070ae726a.png differ
diff --git a/docs/notes/pics/0aaf4630-d2a2-4783-b3f7-a2b6a7dfc01b.jpg b/docs/notes/pics/0aaf4630-d2a2-4783-b3f7-a2b6a7dfc01b.jpg
new file mode 100644
index 00000000..bee1bae5
Binary files /dev/null and b/docs/notes/pics/0aaf4630-d2a2-4783-b3f7-a2b6a7dfc01b.jpg differ
diff --git a/docs/notes/pics/0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg b/docs/notes/pics/0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg
new file mode 100644
index 00000000..7b88e7a0
Binary files /dev/null and b/docs/notes/pics/0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg differ
diff --git a/docs/notes/pics/0c55e11c-d3ce-4cd8-b139-028aea6f40e3.png b/docs/notes/pics/0c55e11c-d3ce-4cd8-b139-028aea6f40e3.png
new file mode 100644
index 00000000..5892c1f9
Binary files /dev/null and b/docs/notes/pics/0c55e11c-d3ce-4cd8-b139-028aea6f40e3.png differ
diff --git a/docs/notes/pics/0df5d84c-e7ca-4e3a-a688-bb8e68894467.png b/docs/notes/pics/0df5d84c-e7ca-4e3a-a688-bb8e68894467.png
new file mode 100644
index 00000000..78a69978
Binary files /dev/null and b/docs/notes/pics/0df5d84c-e7ca-4e3a-a688-bb8e68894467.png differ
diff --git a/docs/notes/pics/0e34263d-7287-4ffe-a716-37c53d1a2526.png b/docs/notes/pics/0e34263d-7287-4ffe-a716-37c53d1a2526.png
new file mode 100644
index 00000000..c5f0bbe3
Binary files /dev/null and b/docs/notes/pics/0e34263d-7287-4ffe-a716-37c53d1a2526.png differ
diff --git a/docs/notes/pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png b/docs/notes/pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png
new file mode 100644
index 00000000..79ec18df
Binary files /dev/null and b/docs/notes/pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png differ
diff --git a/docs/notes/pics/0ee0f61b-c782-441e-bf34-665650198ae0.jpg b/docs/notes/pics/0ee0f61b-c782-441e-bf34-665650198ae0.jpg
new file mode 100644
index 00000000..f3e7163b
Binary files /dev/null and b/docs/notes/pics/0ee0f61b-c782-441e-bf34-665650198ae0.jpg differ
diff --git a/docs/notes/pics/0f373947-c68f-45b4-a59e-086154745ac5.png b/docs/notes/pics/0f373947-c68f-45b4-a59e-086154745ac5.png
new file mode 100644
index 00000000..6b474d85
Binary files /dev/null and b/docs/notes/pics/0f373947-c68f-45b4-a59e-086154745ac5.png differ
diff --git a/docs/notes/pics/0f754c1d-b5cb-48cd-90e0-4a86034290a1.png b/docs/notes/pics/0f754c1d-b5cb-48cd-90e0-4a86034290a1.png
new file mode 100644
index 00000000..57dd8bf1
Binary files /dev/null and b/docs/notes/pics/0f754c1d-b5cb-48cd-90e0-4a86034290a1.png differ
diff --git a/docs/notes/pics/10.gif b/docs/notes/pics/10.gif
new file mode 100644
index 00000000..d52a911e
Binary files /dev/null and b/docs/notes/pics/10.gif differ
diff --git a/docs/notes/pics/107a6a2b-f15b-4cad-bced-b7fb95258c9c.png b/docs/notes/pics/107a6a2b-f15b-4cad-bced-b7fb95258c9c.png
new file mode 100644
index 00000000..35c2ddb1
Binary files /dev/null and b/docs/notes/pics/107a6a2b-f15b-4cad-bced-b7fb95258c9c.png differ
diff --git a/docs/notes/pics/10bdf7bf-0daa-4a26-b927-f142b3f8e72b.png b/docs/notes/pics/10bdf7bf-0daa-4a26-b927-f142b3f8e72b.png
new file mode 100644
index 00000000..cb78d856
Binary files /dev/null and b/docs/notes/pics/10bdf7bf-0daa-4a26-b927-f142b3f8e72b.png differ
diff --git a/docs/notes/pics/10f5e35b-1c71-4717-9e80-47f259702642.jpg b/docs/notes/pics/10f5e35b-1c71-4717-9e80-47f259702642.jpg
new file mode 100644
index 00000000..7041fd5f
Binary files /dev/null and b/docs/notes/pics/10f5e35b-1c71-4717-9e80-47f259702642.jpg differ
diff --git a/docs/notes/pics/11.gif b/docs/notes/pics/11.gif
new file mode 100644
index 00000000..5d9c6f00
Binary files /dev/null and b/docs/notes/pics/11.gif differ
diff --git a/docs/notes/pics/111521118015898.gif b/docs/notes/pics/111521118015898.gif
new file mode 100644
index 00000000..5c31da1d
Binary files /dev/null and b/docs/notes/pics/111521118015898.gif differ
diff --git a/docs/notes/pics/111521118445538.gif b/docs/notes/pics/111521118445538.gif
new file mode 100644
index 00000000..323d129c
Binary files /dev/null and b/docs/notes/pics/111521118445538.gif differ
diff --git a/docs/notes/pics/111521118483039.gif b/docs/notes/pics/111521118483039.gif
new file mode 100644
index 00000000..a81124dd
Binary files /dev/null and b/docs/notes/pics/111521118483039.gif differ
diff --git a/docs/notes/pics/111521118640738.gif b/docs/notes/pics/111521118640738.gif
new file mode 100644
index 00000000..7a7b05a9
Binary files /dev/null and b/docs/notes/pics/111521118640738.gif differ
diff --git a/docs/notes/pics/111521119203347.gif b/docs/notes/pics/111521119203347.gif
new file mode 100644
index 00000000..37cdb5a5
Binary files /dev/null and b/docs/notes/pics/111521119203347.gif differ
diff --git a/docs/notes/pics/111521119368714.gif b/docs/notes/pics/111521119368714.gif
new file mode 100644
index 00000000..216c3033
Binary files /dev/null and b/docs/notes/pics/111521119368714.gif differ
diff --git a/docs/notes/pics/11236498-1417-46ce-a1b0-e10054256955.png b/docs/notes/pics/11236498-1417-46ce-a1b0-e10054256955.png
new file mode 100644
index 00000000..19cd1543
Binary files /dev/null and b/docs/notes/pics/11236498-1417-46ce-a1b0-e10054256955.png differ
diff --git a/docs/notes/pics/1164a71f-413d-494a-9cc8-679fb6a2613d.jpg b/docs/notes/pics/1164a71f-413d-494a-9cc8-679fb6a2613d.jpg
new file mode 100644
index 00000000..1804cdb1
Binary files /dev/null and b/docs/notes/pics/1164a71f-413d-494a-9cc8-679fb6a2613d.jpg differ
diff --git a/docs/notes/pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png b/docs/notes/pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png
new file mode 100644
index 00000000..b44fa996
Binary files /dev/null and b/docs/notes/pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png differ
diff --git a/docs/notes/pics/123bdf81-1ef5-48a9-a08c-2db97057b4d2.png b/docs/notes/pics/123bdf81-1ef5-48a9-a08c-2db97057b4d2.png
new file mode 100644
index 00000000..3c248d37
Binary files /dev/null and b/docs/notes/pics/123bdf81-1ef5-48a9-a08c-2db97057b4d2.png differ
diff --git a/docs/notes/pics/12f958ee-ea02-481a-86ae-acc24934ad80.png b/docs/notes/pics/12f958ee-ea02-481a-86ae-acc24934ad80.png
new file mode 100644
index 00000000..6d683404
Binary files /dev/null and b/docs/notes/pics/12f958ee-ea02-481a-86ae-acc24934ad80.png differ
diff --git a/docs/notes/pics/137c593d-0a9e-47b8-a9e6-b71f540b82dd.png b/docs/notes/pics/137c593d-0a9e-47b8-a9e6-b71f540b82dd.png
new file mode 100644
index 00000000..a5ac33ca
Binary files /dev/null and b/docs/notes/pics/137c593d-0a9e-47b8-a9e6-b71f540b82dd.png differ
diff --git a/docs/notes/pics/13b0940e-d1d7-4b17-af4f-b70cb0a75e08.png b/docs/notes/pics/13b0940e-d1d7-4b17-af4f-b70cb0a75e08.png
new file mode 100644
index 00000000..27f1c9f1
Binary files /dev/null and b/docs/notes/pics/13b0940e-d1d7-4b17-af4f-b70cb0a75e08.png differ
diff --git a/docs/notes/pics/1492928105791_3.png b/docs/notes/pics/1492928105791_3.png
new file mode 100644
index 00000000..d18fc1ca
Binary files /dev/null and b/docs/notes/pics/1492928105791_3.png differ
diff --git a/docs/notes/pics/1492928416812_4.png b/docs/notes/pics/1492928416812_4.png
new file mode 100644
index 00000000..a43a731b
Binary files /dev/null and b/docs/notes/pics/1492928416812_4.png differ
diff --git a/docs/notes/pics/1492929000361_5.png b/docs/notes/pics/1492929000361_5.png
new file mode 100644
index 00000000..919d1222
Binary files /dev/null and b/docs/notes/pics/1492929000361_5.png differ
diff --git a/docs/notes/pics/1492929444818_6.png b/docs/notes/pics/1492929444818_6.png
new file mode 100644
index 00000000..0aea3f9a
Binary files /dev/null and b/docs/notes/pics/1492929444818_6.png differ
diff --git a/docs/notes/pics/1492929553651_7.png b/docs/notes/pics/1492929553651_7.png
new file mode 100644
index 00000000..13cf0b4e
Binary files /dev/null and b/docs/notes/pics/1492929553651_7.png differ
diff --git a/docs/notes/pics/1492930243286_8.png b/docs/notes/pics/1492930243286_8.png
new file mode 100644
index 00000000..6ee721ff
Binary files /dev/null and b/docs/notes/pics/1492930243286_8.png differ
diff --git a/docs/notes/pics/14cfe8d4-e31b-49e0-ac6a-6f4f7aa06ab6.png b/docs/notes/pics/14cfe8d4-e31b-49e0-ac6a-6f4f7aa06ab6.png
new file mode 100644
index 00000000..54a1f458
Binary files /dev/null and b/docs/notes/pics/14cfe8d4-e31b-49e0-ac6a-6f4f7aa06ab6.png differ
diff --git a/docs/notes/pics/15313ed8-a520-4799-a300-2b6b36be314f.jpg b/docs/notes/pics/15313ed8-a520-4799-a300-2b6b36be314f.jpg
new file mode 100644
index 00000000..cbba7f36
Binary files /dev/null and b/docs/notes/pics/15313ed8-a520-4799-a300-2b6b36be314f.jpg differ
diff --git a/docs/notes/pics/1556770b-8c01-4681-af10-46f1df69202c.jpg b/docs/notes/pics/1556770b-8c01-4681-af10-46f1df69202c.jpg
new file mode 100644
index 00000000..94d1adc2
Binary files /dev/null and b/docs/notes/pics/1556770b-8c01-4681-af10-46f1df69202c.jpg differ
diff --git a/docs/notes/pics/1582217a-ed46-4cac-811e-90d13a65163b.png b/docs/notes/pics/1582217a-ed46-4cac-811e-90d13a65163b.png
new file mode 100644
index 00000000..c89551d1
Binary files /dev/null and b/docs/notes/pics/1582217a-ed46-4cac-811e-90d13a65163b.png differ
diff --git a/docs/notes/pics/15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg b/docs/notes/pics/15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg
new file mode 100644
index 00000000..a61ab275
Binary files /dev/null and b/docs/notes/pics/15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg differ
diff --git a/docs/notes/pics/168e893c-e4a0-4ba4-b81f-9d993483abd0.jpg b/docs/notes/pics/168e893c-e4a0-4ba4-b81f-9d993483abd0.jpg
new file mode 100644
index 00000000..cbb68f98
Binary files /dev/null and b/docs/notes/pics/168e893c-e4a0-4ba4-b81f-9d993483abd0.jpg differ
diff --git a/docs/notes/pics/17976404-95f5-480e-9cb4-250e6aa1d55f.png b/docs/notes/pics/17976404-95f5-480e-9cb4-250e6aa1d55f.png
new file mode 100644
index 00000000..276969a7
Binary files /dev/null and b/docs/notes/pics/17976404-95f5-480e-9cb4-250e6aa1d55f.png differ
diff --git a/docs/notes/pics/1818e141-8700-4026-99f7-900a545875f5.png b/docs/notes/pics/1818e141-8700-4026-99f7-900a545875f5.png
new file mode 100644
index 00000000..1523ad79
Binary files /dev/null and b/docs/notes/pics/1818e141-8700-4026-99f7-900a545875f5.png differ
diff --git a/docs/notes/pics/185b9c49-4c13-4241-a848-fbff85c03a64.png b/docs/notes/pics/185b9c49-4c13-4241-a848-fbff85c03a64.png
new file mode 100644
index 00000000..6f56bc5e
Binary files /dev/null and b/docs/notes/pics/185b9c49-4c13-4241-a848-fbff85c03a64.png differ
diff --git a/docs/notes/pics/1a231f2a-5c2f-4231-8e0f-915aa5894347.jpg b/docs/notes/pics/1a231f2a-5c2f-4231-8e0f-915aa5894347.jpg
new file mode 100644
index 00000000..f43e0f25
Binary files /dev/null and b/docs/notes/pics/1a231f2a-5c2f-4231-8e0f-915aa5894347.jpg differ
diff --git a/docs/notes/pics/1a2f2998-d0da-41c8-8222-1fd95083a66b.png b/docs/notes/pics/1a2f2998-d0da-41c8-8222-1fd95083a66b.png
new file mode 100644
index 00000000..c4592305
Binary files /dev/null and b/docs/notes/pics/1a2f2998-d0da-41c8-8222-1fd95083a66b.png differ
diff --git a/docs/notes/pics/1a851e90-0d5c-4d4f-ac54-34c20ecfb903.jpg b/docs/notes/pics/1a851e90-0d5c-4d4f-ac54-34c20ecfb903.jpg
new file mode 100644
index 00000000..4809984f
Binary files /dev/null and b/docs/notes/pics/1a851e90-0d5c-4d4f-ac54-34c20ecfb903.jpg differ
diff --git a/docs/notes/pics/1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png b/docs/notes/pics/1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png
new file mode 100644
index 00000000..590a4299
Binary files /dev/null and b/docs/notes/pics/1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png differ
diff --git a/docs/notes/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg b/docs/notes/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg
new file mode 100644
index 00000000..48a91211
Binary files /dev/null and b/docs/notes/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg differ
diff --git a/docs/notes/pics/1b7f180e-7fee-4eaf-8ebb-164b68ae2b29.png b/docs/notes/pics/1b7f180e-7fee-4eaf-8ebb-164b68ae2b29.png
new file mode 100644
index 00000000..081bf5aa
Binary files /dev/null and b/docs/notes/pics/1b7f180e-7fee-4eaf-8ebb-164b68ae2b29.png differ
diff --git a/docs/notes/pics/1be8b4b0-cc7a-44d7-9c77-85be37b76f7d.png b/docs/notes/pics/1be8b4b0-cc7a-44d7-9c77-85be37b76f7d.png
new file mode 100644
index 00000000..6ba8797b
Binary files /dev/null and b/docs/notes/pics/1be8b4b0-cc7a-44d7-9c77-85be37b76f7d.png differ
diff --git a/docs/notes/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png b/docs/notes/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png
new file mode 100644
index 00000000..e4286077
Binary files /dev/null and b/docs/notes/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png differ
diff --git a/docs/notes/pics/1bfa3118-f3cd-4480-a950-cf6d646015db.png b/docs/notes/pics/1bfa3118-f3cd-4480-a950-cf6d646015db.png
new file mode 100644
index 00000000..c28fe627
Binary files /dev/null and b/docs/notes/pics/1bfa3118-f3cd-4480-a950-cf6d646015db.png differ
diff --git a/docs/notes/pics/1c4e8185-8153-46b6-bd5a-288b15feeae6.png b/docs/notes/pics/1c4e8185-8153-46b6-bd5a-288b15feeae6.png
new file mode 100644
index 00000000..35e992f7
Binary files /dev/null and b/docs/notes/pics/1c4e8185-8153-46b6-bd5a-288b15feeae6.png differ
diff --git a/docs/notes/pics/1ca52246-c443-48ae-b1f8-1cafc09ec75c.png b/docs/notes/pics/1ca52246-c443-48ae-b1f8-1cafc09ec75c.png
new file mode 100644
index 00000000..53596803
Binary files /dev/null and b/docs/notes/pics/1ca52246-c443-48ae-b1f8-1cafc09ec75c.png differ
diff --git a/docs/notes/pics/1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg b/docs/notes/pics/1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg
new file mode 100644
index 00000000..699a8e8e
Binary files /dev/null and b/docs/notes/pics/1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg differ
diff --git a/docs/notes/pics/1f039a45-6b91-4f31-a2c2-6c63eb8bdb56.png b/docs/notes/pics/1f039a45-6b91-4f31-a2c2-6c63eb8bdb56.png
new file mode 100644
index 00000000..eb4daeab
Binary files /dev/null and b/docs/notes/pics/1f039a45-6b91-4f31-a2c2-6c63eb8bdb56.png differ
diff --git a/docs/notes/pics/1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg b/docs/notes/pics/1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg
new file mode 100644
index 00000000..c1776a5c
Binary files /dev/null and b/docs/notes/pics/1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg differ
diff --git a/docs/notes/pics/1f4a7f10-52b2-4bd7-a67d-a9581d66dc62.jpg b/docs/notes/pics/1f4a7f10-52b2-4bd7-a67d-a9581d66dc62.jpg
new file mode 100644
index 00000000..e4f0f3ac
Binary files /dev/null and b/docs/notes/pics/1f4a7f10-52b2-4bd7-a67d-a9581d66dc62.jpg differ
diff --git a/docs/notes/pics/1fc969e4-0e7c-441b-b53c-01950d2f2be5.png b/docs/notes/pics/1fc969e4-0e7c-441b-b53c-01950d2f2be5.png
new file mode 100644
index 00000000..0f7d6660
Binary files /dev/null and b/docs/notes/pics/1fc969e4-0e7c-441b-b53c-01950d2f2be5.png differ
diff --git a/docs/notes/pics/20150928140509757.png b/docs/notes/pics/20150928140509757.png
new file mode 100644
index 00000000..60684377
Binary files /dev/null and b/docs/notes/pics/20150928140509757.png differ
diff --git a/docs/notes/pics/2017-06-11-ca.png b/docs/notes/pics/2017-06-11-ca.png
new file mode 100644
index 00000000..550292c1
Binary files /dev/null and b/docs/notes/pics/2017-06-11-ca.png differ
diff --git a/docs/notes/pics/2017511e-22f0-4d74-873d-1261b71cf5a4.png b/docs/notes/pics/2017511e-22f0-4d74-873d-1261b71cf5a4.png
new file mode 100644
index 00000000..81633b51
Binary files /dev/null and b/docs/notes/pics/2017511e-22f0-4d74-873d-1261b71cf5a4.png differ
diff --git a/docs/notes/pics/2018-05-29-15275543393037.jpg b/docs/notes/pics/2018-05-29-15275543393037.jpg
new file mode 100644
index 00000000..4af67ef0
Binary files /dev/null and b/docs/notes/pics/2018-05-29-15275543393037.jpg differ
diff --git a/docs/notes/pics/2018040302.jpg b/docs/notes/pics/2018040302.jpg
new file mode 100644
index 00000000..27daefae
Binary files /dev/null and b/docs/notes/pics/2018040302.jpg differ
diff --git a/docs/notes/pics/207c1801-2335-4b1b-b65c-126a0ba966cb.png b/docs/notes/pics/207c1801-2335-4b1b-b65c-126a0ba966cb.png
new file mode 100644
index 00000000..cace90b3
Binary files /dev/null and b/docs/notes/pics/207c1801-2335-4b1b-b65c-126a0ba966cb.png differ
diff --git a/docs/notes/pics/21041ec2-babb-483f-bf47-8b8148eec162.png b/docs/notes/pics/21041ec2-babb-483f-bf47-8b8148eec162.png
new file mode 100644
index 00000000..7de9b57a
Binary files /dev/null and b/docs/notes/pics/21041ec2-babb-483f-bf47-8b8148eec162.png differ
diff --git a/docs/notes/pics/211c60d4-75ca-4acd-8a4f-171458ed58b4.jpg b/docs/notes/pics/211c60d4-75ca-4acd-8a4f-171458ed58b4.jpg
new file mode 100644
index 00000000..efb47ffc
Binary files /dev/null and b/docs/notes/pics/211c60d4-75ca-4acd-8a4f-171458ed58b4.jpg differ
diff --git a/docs/notes/pics/220790c6-4377-4a2e-8686-58398afc8a18.png b/docs/notes/pics/220790c6-4377-4a2e-8686-58398afc8a18.png
new file mode 100644
index 00000000..79105257
Binary files /dev/null and b/docs/notes/pics/220790c6-4377-4a2e-8686-58398afc8a18.png differ
diff --git a/docs/notes/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png b/docs/notes/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png
new file mode 100644
index 00000000..8d7dc098
Binary files /dev/null and b/docs/notes/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png differ
diff --git a/docs/notes/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg b/docs/notes/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg
new file mode 100644
index 00000000..2ce6dd1f
Binary files /dev/null and b/docs/notes/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg differ
diff --git a/docs/notes/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png b/docs/notes/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png
new file mode 100644
index 00000000..5fccbd1c
Binary files /dev/null and b/docs/notes/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png differ
diff --git a/docs/notes/pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg b/docs/notes/pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg
new file mode 100644
index 00000000..92c11bfd
Binary files /dev/null and b/docs/notes/pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg differ
diff --git a/docs/notes/pics/249f3bb1-feee-4805-a259-a72699d638ca.jpg b/docs/notes/pics/249f3bb1-feee-4805-a259-a72699d638ca.jpg
new file mode 100644
index 00000000..82d2a1f4
Binary files /dev/null and b/docs/notes/pics/249f3bb1-feee-4805-a259-a72699d638ca.jpg differ
diff --git a/docs/notes/pics/25d6d3d4-4726-47b1-a9cb-3316d1ff5dd5.png b/docs/notes/pics/25d6d3d4-4726-47b1-a9cb-3316d1ff5dd5.png
new file mode 100644
index 00000000..7550da6b
Binary files /dev/null and b/docs/notes/pics/25d6d3d4-4726-47b1-a9cb-3316d1ff5dd5.png differ
diff --git a/docs/notes/pics/265a355d-aead-48aa-b455-f33b62fe729f.png b/docs/notes/pics/265a355d-aead-48aa-b455-f33b62fe729f.png
new file mode 100644
index 00000000..bb564f6e
Binary files /dev/null and b/docs/notes/pics/265a355d-aead-48aa-b455-f33b62fe729f.png differ
diff --git a/docs/notes/pics/2719067e-b299-4639-9065-bed6729dbf0b.png b/docs/notes/pics/2719067e-b299-4639-9065-bed6729dbf0b.png
new file mode 100644
index 00000000..95057e05
Binary files /dev/null and b/docs/notes/pics/2719067e-b299-4639-9065-bed6729dbf0b.png differ
diff --git a/docs/notes/pics/271ce08f-c124-475f-b490-be44fedc6d2e.png b/docs/notes/pics/271ce08f-c124-475f-b490-be44fedc6d2e.png
new file mode 100644
index 00000000..8de6367b
Binary files /dev/null and b/docs/notes/pics/271ce08f-c124-475f-b490-be44fedc6d2e.png differ
diff --git a/docs/notes/pics/2766d04f-7dad-42e4-99d1-60682c9d5c61.jpg b/docs/notes/pics/2766d04f-7dad-42e4-99d1-60682c9d5c61.jpg
new file mode 100644
index 00000000..f9a9489b
Binary files /dev/null and b/docs/notes/pics/2766d04f-7dad-42e4-99d1-60682c9d5c61.jpg differ
diff --git a/docs/notes/pics/276c31df-3b28-4ac2-b006-1e80fc86a64f.jpg b/docs/notes/pics/276c31df-3b28-4ac2-b006-1e80fc86a64f.jpg
new file mode 100644
index 00000000..8676c440
Binary files /dev/null and b/docs/notes/pics/276c31df-3b28-4ac2-b006-1e80fc86a64f.jpg differ
diff --git a/docs/notes/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg b/docs/notes/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg
new file mode 100644
index 00000000..c6de4ac5
Binary files /dev/null and b/docs/notes/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg differ
diff --git a/docs/notes/pics/27cd6f0c-f581-45da-b8c9-fed026830560.png b/docs/notes/pics/27cd6f0c-f581-45da-b8c9-fed026830560.png
new file mode 100644
index 00000000..40775ac8
Binary files /dev/null and b/docs/notes/pics/27cd6f0c-f581-45da-b8c9-fed026830560.png differ
diff --git a/docs/notes/pics/27ff9548-edb6-4465-92c8-7e6386e0b185.png b/docs/notes/pics/27ff9548-edb6-4465-92c8-7e6386e0b185.png
new file mode 100644
index 00000000..1aee414c
Binary files /dev/null and b/docs/notes/pics/27ff9548-edb6-4465-92c8-7e6386e0b185.png differ
diff --git a/docs/notes/pics/280f7728-594f-4811-a03a-fa8d32c013da.png b/docs/notes/pics/280f7728-594f-4811-a03a-fa8d32c013da.png
new file mode 100644
index 00000000..526b6847
Binary files /dev/null and b/docs/notes/pics/280f7728-594f-4811-a03a-fa8d32c013da.png differ
diff --git a/docs/notes/pics/2858f8ad-aedb-45a5-a706-e98c96d690fa.jpg b/docs/notes/pics/2858f8ad-aedb-45a5-a706-e98c96d690fa.jpg
new file mode 100644
index 00000000..d4171d08
Binary files /dev/null and b/docs/notes/pics/2858f8ad-aedb-45a5-a706-e98c96d690fa.jpg differ
diff --git a/docs/notes/pics/2861e923-4862-4526-881c-15529279d49c.png b/docs/notes/pics/2861e923-4862-4526-881c-15529279d49c.png
new file mode 100644
index 00000000..6cc26c26
Binary files /dev/null and b/docs/notes/pics/2861e923-4862-4526-881c-15529279d49c.png differ
diff --git a/docs/notes/pics/28ab96b4-82ea-4d99-99fb-b320f60d0a58.png b/docs/notes/pics/28ab96b4-82ea-4d99-99fb-b320f60d0a58.png
new file mode 100644
index 00000000..8072abc5
Binary files /dev/null and b/docs/notes/pics/28ab96b4-82ea-4d99-99fb-b320f60d0a58.png differ
diff --git a/docs/notes/pics/292b4a35-4507-4256-84ff-c218f108ee31.jpg b/docs/notes/pics/292b4a35-4507-4256-84ff-c218f108ee31.jpg
new file mode 100644
index 00000000..38e0905b
Binary files /dev/null and b/docs/notes/pics/292b4a35-4507-4256-84ff-c218f108ee31.jpg differ
diff --git a/docs/notes/pics/293d2af9-de1d-403e-bed0-85d029383528.png b/docs/notes/pics/293d2af9-de1d-403e-bed0-85d029383528.png
new file mode 100644
index 00000000..36765e32
Binary files /dev/null and b/docs/notes/pics/293d2af9-de1d-403e-bed0-85d029383528.png differ
diff --git a/docs/notes/pics/2991c772-fb1c-4051-a9c7-932b68e76bd7.jpg b/docs/notes/pics/2991c772-fb1c-4051-a9c7-932b68e76bd7.jpg
new file mode 100644
index 00000000..d99eb3a7
Binary files /dev/null and b/docs/notes/pics/2991c772-fb1c-4051-a9c7-932b68e76bd7.jpg differ
diff --git a/docs/notes/pics/2_14_microkernelArchitecture.jpg b/docs/notes/pics/2_14_microkernelArchitecture.jpg
new file mode 100644
index 00000000..21c2a58f
Binary files /dev/null and b/docs/notes/pics/2_14_microkernelArchitecture.jpg differ
diff --git a/docs/notes/pics/2a842a14-e4ab-4f37-83fa-f82c206fe426.png b/docs/notes/pics/2a842a14-e4ab-4f37-83fa-f82c206fe426.png
new file mode 100644
index 00000000..e75e0e12
Binary files /dev/null and b/docs/notes/pics/2a842a14-e4ab-4f37-83fa-f82c206fe426.png differ
diff --git a/docs/notes/pics/2a8e1442-2381-4439-a83f-0312c8678b1f.png b/docs/notes/pics/2a8e1442-2381-4439-a83f-0312c8678b1f.png
new file mode 100644
index 00000000..a97e49a6
Binary files /dev/null and b/docs/notes/pics/2a8e1442-2381-4439-a83f-0312c8678b1f.png differ
diff --git a/docs/notes/pics/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png b/docs/notes/pics/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png
new file mode 100644
index 00000000..173ce970
Binary files /dev/null and b/docs/notes/pics/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png differ
diff --git a/docs/notes/pics/2ad244f5-939c-49fa-9385-69bc688677ab.jpg b/docs/notes/pics/2ad244f5-939c-49fa-9385-69bc688677ab.jpg
new file mode 100644
index 00000000..5c1e0af9
Binary files /dev/null and b/docs/notes/pics/2ad244f5-939c-49fa-9385-69bc688677ab.jpg differ
diff --git a/docs/notes/pics/2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg b/docs/notes/pics/2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg
new file mode 100644
index 00000000..983ddd70
Binary files /dev/null and b/docs/notes/pics/2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg differ
diff --git a/docs/notes/pics/2bf2fd8f-5ade-48ba-a2b3-74195ac77c4b.png b/docs/notes/pics/2bf2fd8f-5ade-48ba-a2b3-74195ac77c4b.png
new file mode 100644
index 00000000..590a4299
Binary files /dev/null and b/docs/notes/pics/2bf2fd8f-5ade-48ba-a2b3-74195ac77c4b.png differ
diff --git a/docs/notes/pics/2c4556e4-0751-4377-ab08-e7b89d697ca7.png b/docs/notes/pics/2c4556e4-0751-4377-ab08-e7b89d697ca7.png
new file mode 100644
index 00000000..c7f87138
Binary files /dev/null and b/docs/notes/pics/2c4556e4-0751-4377-ab08-e7b89d697ca7.png differ
diff --git a/docs/notes/pics/2c8a7a87-1bf1-4d66-9ba9-225a1add0a51.png b/docs/notes/pics/2c8a7a87-1bf1-4d66-9ba9-225a1add0a51.png
new file mode 100644
index 00000000..1659fdae
Binary files /dev/null and b/docs/notes/pics/2c8a7a87-1bf1-4d66-9ba9-225a1add0a51.png differ
diff --git a/docs/notes/pics/2d09a847-b854-439c-9198-b29c65810944.png b/docs/notes/pics/2d09a847-b854-439c-9198-b29c65810944.png
new file mode 100644
index 00000000..384f7ef0
Binary files /dev/null and b/docs/notes/pics/2d09a847-b854-439c-9198-b29c65810944.png differ
diff --git a/docs/notes/pics/2e6c72f5-3b8e-4e32-b87b-9491322628fe.png b/docs/notes/pics/2e6c72f5-3b8e-4e32-b87b-9491322628fe.png
new file mode 100644
index 00000000..701e37f2
Binary files /dev/null and b/docs/notes/pics/2e6c72f5-3b8e-4e32-b87b-9491322628fe.png differ
diff --git a/docs/notes/pics/30210b86-472d-4574-abb6-b74898cc17a4.jpg b/docs/notes/pics/30210b86-472d-4574-abb6-b74898cc17a4.jpg
new file mode 100644
index 00000000..7726cf8c
Binary files /dev/null and b/docs/notes/pics/30210b86-472d-4574-abb6-b74898cc17a4.jpg differ
diff --git a/docs/notes/pics/3086c248-b552-499e-b101-9cffe5c2773e.png b/docs/notes/pics/3086c248-b552-499e-b101-9cffe5c2773e.png
new file mode 100644
index 00000000..c23e85c9
Binary files /dev/null and b/docs/notes/pics/3086c248-b552-499e-b101-9cffe5c2773e.png differ
diff --git a/docs/notes/pics/31d99967-1171-448e-8531-bccf5c14cffe.jpg b/docs/notes/pics/31d99967-1171-448e-8531-bccf5c14cffe.jpg
new file mode 100644
index 00000000..61e00649
Binary files /dev/null and b/docs/notes/pics/31d99967-1171-448e-8531-bccf5c14cffe.jpg differ
diff --git a/docs/notes/pics/323ffd6c-8b54-4f3e-b361-555a6c8bf218.png b/docs/notes/pics/323ffd6c-8b54-4f3e-b361-555a6c8bf218.png
new file mode 100644
index 00000000..3316254e
Binary files /dev/null and b/docs/notes/pics/323ffd6c-8b54-4f3e-b361-555a6c8bf218.png differ
diff --git a/docs/notes/pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg b/docs/notes/pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg
new file mode 100644
index 00000000..9de5783d
Binary files /dev/null and b/docs/notes/pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg differ
diff --git a/docs/notes/pics/33ac2b23-cb85-4e99-bc41-b7b7199fad1c.png b/docs/notes/pics/33ac2b23-cb85-4e99-bc41-b7b7199fad1c.png
new file mode 100644
index 00000000..6e8383f3
Binary files /dev/null and b/docs/notes/pics/33ac2b23-cb85-4e99-bc41-b7b7199fad1c.png differ
diff --git a/docs/notes/pics/348bc2db-582e-4aca-9f88-38c40e9a0e69.png b/docs/notes/pics/348bc2db-582e-4aca-9f88-38c40e9a0e69.png
new file mode 100644
index 00000000..cb7e3681
Binary files /dev/null and b/docs/notes/pics/348bc2db-582e-4aca-9f88-38c40e9a0e69.png differ
diff --git a/docs/notes/pics/35650b4b-efa1-49ba-9680-19837027cfc9.png b/docs/notes/pics/35650b4b-efa1-49ba-9680-19837027cfc9.png
new file mode 100644
index 00000000..8f400a65
Binary files /dev/null and b/docs/notes/pics/35650b4b-efa1-49ba-9680-19837027cfc9.png differ
diff --git a/docs/notes/pics/3646544a-cb57-451d-9e03-d3c4f5e4434a.png b/docs/notes/pics/3646544a-cb57-451d-9e03-d3c4f5e4434a.png
new file mode 100644
index 00000000..76d45e19
Binary files /dev/null and b/docs/notes/pics/3646544a-cb57-451d-9e03-d3c4f5e4434a.png differ
diff --git a/docs/notes/pics/37a72755-4890-4b42-9eab-b0084e0c54d9.png b/docs/notes/pics/37a72755-4890-4b42-9eab-b0084e0c54d9.png
new file mode 100644
index 00000000..c74c59ef
Binary files /dev/null and b/docs/notes/pics/37a72755-4890-4b42-9eab-b0084e0c54d9.png differ
diff --git a/docs/notes/pics/37e79a32-95a9-4503-bdb1-159527e628b8.png b/docs/notes/pics/37e79a32-95a9-4503-bdb1-159527e628b8.png
new file mode 100644
index 00000000..3b05b25b
Binary files /dev/null and b/docs/notes/pics/37e79a32-95a9-4503-bdb1-159527e628b8.png differ
diff --git a/docs/notes/pics/386cd64f-7a9d-40e6-8c55-22b90ee2d258.png b/docs/notes/pics/386cd64f-7a9d-40e6-8c55-22b90ee2d258.png
new file mode 100644
index 00000000..5f5f5636
Binary files /dev/null and b/docs/notes/pics/386cd64f-7a9d-40e6-8c55-22b90ee2d258.png differ
diff --git a/docs/notes/pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg b/docs/notes/pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg
new file mode 100644
index 00000000..78eb732b
Binary files /dev/null and b/docs/notes/pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg differ
diff --git a/docs/notes/pics/3939369b-3a4a-48a0-b9eb-3efae26dd400.png b/docs/notes/pics/3939369b-3a4a-48a0-b9eb-3efae26dd400.png
new file mode 100644
index 00000000..c2cf9d1b
Binary files /dev/null and b/docs/notes/pics/3939369b-3a4a-48a0-b9eb-3efae26dd400.png differ
diff --git a/docs/notes/pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png b/docs/notes/pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png
new file mode 100644
index 00000000..b486ec02
Binary files /dev/null and b/docs/notes/pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png differ
diff --git a/docs/notes/pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg b/docs/notes/pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg
new file mode 100644
index 00000000..60c19f88
Binary files /dev/null and b/docs/notes/pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg differ
diff --git a/docs/notes/pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png b/docs/notes/pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png
new file mode 100644
index 00000000..8e363e47
Binary files /dev/null and b/docs/notes/pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png differ
diff --git a/docs/notes/pics/3b0d1aa8-d0e0-46c2-8fd1-736bf08a11aa.jpg b/docs/notes/pics/3b0d1aa8-d0e0-46c2-8fd1-736bf08a11aa.jpg
new file mode 100644
index 00000000..f7e9f145
Binary files /dev/null and b/docs/notes/pics/3b0d1aa8-d0e0-46c2-8fd1-736bf08a11aa.jpg differ
diff --git a/docs/notes/pics/3b49dd67-2c40-4b81-8ad2-7bbb1fe2fcbd.png b/docs/notes/pics/3b49dd67-2c40-4b81-8ad2-7bbb1fe2fcbd.png
new file mode 100644
index 00000000..13f53b6a
Binary files /dev/null and b/docs/notes/pics/3b49dd67-2c40-4b81-8ad2-7bbb1fe2fcbd.png differ
diff --git a/docs/notes/pics/3ca58a41-8794-49c1-992e-de5d579a50d1.png b/docs/notes/pics/3ca58a41-8794-49c1-992e-de5d579a50d1.png
new file mode 100644
index 00000000..725f2f29
Binary files /dev/null and b/docs/notes/pics/3ca58a41-8794-49c1-992e-de5d579a50d1.png differ
diff --git a/docs/notes/pics/3cd630ea-017c-488d-ad1d-732b4efeddf5.png b/docs/notes/pics/3cd630ea-017c-488d-ad1d-732b4efeddf5.png
new file mode 100644
index 00000000..9dc77733
Binary files /dev/null and b/docs/notes/pics/3cd630ea-017c-488d-ad1d-732b4efeddf5.png differ
diff --git a/docs/notes/pics/3d5b828e-5c4d-48d8-a440-281e4a8e1c92.png b/docs/notes/pics/3d5b828e-5c4d-48d8-a440-281e4a8e1c92.png
new file mode 100644
index 00000000..2f39530c
Binary files /dev/null and b/docs/notes/pics/3d5b828e-5c4d-48d8-a440-281e4a8e1c92.png differ
diff --git a/docs/notes/pics/3f5bba4b-7813-4aea-b578-970c7e3f6bf3.jpg b/docs/notes/pics/3f5bba4b-7813-4aea-b578-970c7e3f6bf3.jpg
new file mode 100644
index 00000000..c9702daf
Binary files /dev/null and b/docs/notes/pics/3f5bba4b-7813-4aea-b578-970c7e3f6bf3.jpg differ
diff --git a/docs/notes/pics/3fb5b255-b791-45b6-8754-325c8741855a.png b/docs/notes/pics/3fb5b255-b791-45b6-8754-325c8741855a.png
new file mode 100644
index 00000000..621245d7
Binary files /dev/null and b/docs/notes/pics/3fb5b255-b791-45b6-8754-325c8741855a.png differ
diff --git a/docs/notes/pics/3fdfc89d-719e-4d93-b518-29fa612b3b18.png b/docs/notes/pics/3fdfc89d-719e-4d93-b518-29fa612b3b18.png
new file mode 100644
index 00000000..781dca88
Binary files /dev/null and b/docs/notes/pics/3fdfc89d-719e-4d93-b518-29fa612b3b18.png differ
diff --git a/docs/notes/pics/3ff4f00a-2321-48fd-95f4-ce6001332151.png b/docs/notes/pics/3ff4f00a-2321-48fd-95f4-ce6001332151.png
new file mode 100644
index 00000000..266a4687
Binary files /dev/null and b/docs/notes/pics/3ff4f00a-2321-48fd-95f4-ce6001332151.png differ
diff --git a/docs/notes/pics/41026c79-dfc1-40f7-85ae-062910fd272b.png b/docs/notes/pics/41026c79-dfc1-40f7-85ae-062910fd272b.png
new file mode 100644
index 00000000..a60891bb
Binary files /dev/null and b/docs/notes/pics/41026c79-dfc1-40f7-85ae-062910fd272b.png differ
diff --git a/docs/notes/pics/41392d76-dd1d-4712-85d9-e8bb46b04a2d.png b/docs/notes/pics/41392d76-dd1d-4712-85d9-e8bb46b04a2d.png
new file mode 100644
index 00000000..d2fd2c63
Binary files /dev/null and b/docs/notes/pics/41392d76-dd1d-4712-85d9-e8bb46b04a2d.png differ
diff --git a/docs/notes/pics/423f2a40-bee1-488e-b460-8e76c48ee560.png b/docs/notes/pics/423f2a40-bee1-488e-b460-8e76c48ee560.png
new file mode 100644
index 00000000..7b8c8c08
Binary files /dev/null and b/docs/notes/pics/423f2a40-bee1-488e-b460-8e76c48ee560.png differ
diff --git a/docs/notes/pics/426df589-6f97-4622-b74d-4a81fcb1da8e.png b/docs/notes/pics/426df589-6f97-4622-b74d-4a81fcb1da8e.png
new file mode 100644
index 00000000..98327bba
Binary files /dev/null and b/docs/notes/pics/426df589-6f97-4622-b74d-4a81fcb1da8e.png differ
diff --git a/docs/notes/pics/43f2cafa-3568-4a89-a895-4725666b94a6.png b/docs/notes/pics/43f2cafa-3568-4a89-a895-4725666b94a6.png
new file mode 100644
index 00000000..010278a2
Binary files /dev/null and b/docs/notes/pics/43f2cafa-3568-4a89-a895-4725666b94a6.png differ
diff --git a/docs/notes/pics/44e4a7ab-215c-41a1-8e34-f55f6c09e517.jpg b/docs/notes/pics/44e4a7ab-215c-41a1-8e34-f55f6c09e517.jpg
new file mode 100644
index 00000000..a14ecacf
Binary files /dev/null and b/docs/notes/pics/44e4a7ab-215c-41a1-8e34-f55f6c09e517.jpg differ
diff --git a/docs/notes/pics/44edefb7-4b58-4519-b8ee-4aca01697b78.jpg b/docs/notes/pics/44edefb7-4b58-4519-b8ee-4aca01697b78.jpg
new file mode 100644
index 00000000..32d0f3d2
Binary files /dev/null and b/docs/notes/pics/44edefb7-4b58-4519-b8ee-4aca01697b78.jpg differ
diff --git a/docs/notes/pics/450px-HTTP_persistent_connection.svg.png b/docs/notes/pics/450px-HTTP_persistent_connection.svg.png
new file mode 100644
index 00000000..e4fb8ba2
Binary files /dev/null and b/docs/notes/pics/450px-HTTP_persistent_connection.svg.png differ
diff --git a/docs/notes/pics/4583e24f-424b-4d50-8a14-2c38a1827d4a.png b/docs/notes/pics/4583e24f-424b-4d50-8a14-2c38a1827d4a.png
new file mode 100644
index 00000000..be98ce69
Binary files /dev/null and b/docs/notes/pics/4583e24f-424b-4d50-8a14-2c38a1827d4a.png differ
diff --git a/docs/notes/pics/45e0e0bf-386d-4280-a341-a0b9496c7674.png b/docs/notes/pics/45e0e0bf-386d-4280-a341-a0b9496c7674.png
new file mode 100644
index 00000000..32fb94aa
Binary files /dev/null and b/docs/notes/pics/45e0e0bf-386d-4280-a341-a0b9496c7674.png differ
diff --git a/docs/notes/pics/4628274c-25b6-4053-97cf-d1239b44c43d.png b/docs/notes/pics/4628274c-25b6-4053-97cf-d1239b44c43d.png
new file mode 100644
index 00000000..6db68ca5
Binary files /dev/null and b/docs/notes/pics/4628274c-25b6-4053-97cf-d1239b44c43d.png differ
diff --git a/docs/notes/pics/46cec213-3048-4a80-aded-fdd577542801.jpg b/docs/notes/pics/46cec213-3048-4a80-aded-fdd577542801.jpg
new file mode 100644
index 00000000..32e1f3d5
Binary files /dev/null and b/docs/notes/pics/46cec213-3048-4a80-aded-fdd577542801.jpg differ
diff --git a/docs/notes/pics/46f66e88-e65a-4ad0-a060-3c63fe22947c.png b/docs/notes/pics/46f66e88-e65a-4ad0-a060-3c63fe22947c.png
new file mode 100644
index 00000000..0dcc8706
Binary files /dev/null and b/docs/notes/pics/46f66e88-e65a-4ad0-a060-3c63fe22947c.png differ
diff --git a/docs/notes/pics/47358f87-bc4c-496f-9a90-8d696de94cee.png b/docs/notes/pics/47358f87-bc4c-496f-9a90-8d696de94cee.png
new file mode 100644
index 00000000..83d59359
Binary files /dev/null and b/docs/notes/pics/47358f87-bc4c-496f-9a90-8d696de94cee.png differ
diff --git a/docs/notes/pics/47d98583-8bb0-45cc-812d-47eefa0a4a40.jpg b/docs/notes/pics/47d98583-8bb0-45cc-812d-47eefa0a4a40.jpg
new file mode 100644
index 00000000..f6ddd2c2
Binary files /dev/null and b/docs/notes/pics/47d98583-8bb0-45cc-812d-47eefa0a4a40.jpg differ
diff --git a/docs/notes/pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png b/docs/notes/pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png
new file mode 100644
index 00000000..f9f73faf
Binary files /dev/null and b/docs/notes/pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png differ
diff --git a/docs/notes/pics/4885d0bc-1441-460f-bd75-a2088aa7f2d4.png b/docs/notes/pics/4885d0bc-1441-460f-bd75-a2088aa7f2d4.png
new file mode 100644
index 00000000..2f8dd24f
Binary files /dev/null and b/docs/notes/pics/4885d0bc-1441-460f-bd75-a2088aa7f2d4.png differ
diff --git a/docs/notes/pics/48a934ff-a29b-434c-8e1d-8c8ec20cb91d.png b/docs/notes/pics/48a934ff-a29b-434c-8e1d-8c8ec20cb91d.png
new file mode 100644
index 00000000..9c6b68dc
Binary files /dev/null and b/docs/notes/pics/48a934ff-a29b-434c-8e1d-8c8ec20cb91d.png differ
diff --git a/docs/notes/pics/48f8f98e-8dfd-450d-8b5b-df4688f0d377.jpg b/docs/notes/pics/48f8f98e-8dfd-450d-8b5b-df4688f0d377.jpg
new file mode 100644
index 00000000..272de82d
Binary files /dev/null and b/docs/notes/pics/48f8f98e-8dfd-450d-8b5b-df4688f0d377.jpg differ
diff --git a/docs/notes/pics/49495c95-52e5-4c9a-b27b-92cf235ff5ec.png b/docs/notes/pics/49495c95-52e5-4c9a-b27b-92cf235ff5ec.png
new file mode 100644
index 00000000..662d99c3
Binary files /dev/null and b/docs/notes/pics/49495c95-52e5-4c9a-b27b-92cf235ff5ec.png differ
diff --git a/docs/notes/pics/49d6de7b-0d0d-425c-9e49-a1559dc23b10.png b/docs/notes/pics/49d6de7b-0d0d-425c-9e49-a1559dc23b10.png
new file mode 100644
index 00000000..eea3c6b4
Binary files /dev/null and b/docs/notes/pics/49d6de7b-0d0d-425c-9e49-a1559dc23b10.png differ
diff --git a/docs/notes/pics/4bb7ed45-ec14-4d31-9da4-94024d9d3b05.png b/docs/notes/pics/4bb7ed45-ec14-4d31-9da4-94024d9d3b05.png
new file mode 100644
index 00000000..c5912612
Binary files /dev/null and b/docs/notes/pics/4bb7ed45-ec14-4d31-9da4-94024d9d3b05.png differ
diff --git a/docs/notes/pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png b/docs/notes/pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png
new file mode 100644
index 00000000..25ac4f70
Binary files /dev/null and b/docs/notes/pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png differ
diff --git a/docs/notes/pics/4d741402-344d-4b7c-be01-e57184bcad0e.png b/docs/notes/pics/4d741402-344d-4b7c-be01-e57184bcad0e.png
new file mode 100644
index 00000000..a4a5e7b0
Binary files /dev/null and b/docs/notes/pics/4d741402-344d-4b7c-be01-e57184bcad0e.png differ
diff --git a/docs/notes/pics/4d930e22-f493-49ae-8dff-ea21cd6895dc.png b/docs/notes/pics/4d930e22-f493-49ae-8dff-ea21cd6895dc.png
new file mode 100644
index 00000000..7ee2ffb4
Binary files /dev/null and b/docs/notes/pics/4d930e22-f493-49ae-8dff-ea21cd6895dc.png differ
diff --git a/docs/notes/pics/4dc08713-f6fe-424c-a24c-ad5a993a941d.png b/docs/notes/pics/4dc08713-f6fe-424c-a24c-ad5a993a941d.png
new file mode 100644
index 00000000..8a0b1d3f
Binary files /dev/null and b/docs/notes/pics/4dc08713-f6fe-424c-a24c-ad5a993a941d.png differ
diff --git a/docs/notes/pics/4e2485e4-34bd-4967-9f02-0c093b797aaa.png b/docs/notes/pics/4e2485e4-34bd-4967-9f02-0c093b797aaa.png
new file mode 100644
index 00000000..a5643118
Binary files /dev/null and b/docs/notes/pics/4e2485e4-34bd-4967-9f02-0c093b797aaa.png differ
diff --git a/docs/notes/pics/4e760981-a0c5-4dbf-9fbf-ce963e0629fb.png b/docs/notes/pics/4e760981-a0c5-4dbf-9fbf-ce963e0629fb.png
new file mode 100644
index 00000000..e5768980
Binary files /dev/null and b/docs/notes/pics/4e760981-a0c5-4dbf-9fbf-ce963e0629fb.png differ
diff --git a/docs/notes/pics/4f48e806-f90b-4c09-a55f-ac0cd641c047.png b/docs/notes/pics/4f48e806-f90b-4c09-a55f-ac0cd641c047.png
new file mode 100644
index 00000000..649d16cd
Binary files /dev/null and b/docs/notes/pics/4f48e806-f90b-4c09-a55f-ac0cd641c047.png differ
diff --git a/docs/notes/pics/4fc032e0-ac6f-4b42-9182-ee104a25e7a1.png b/docs/notes/pics/4fc032e0-ac6f-4b42-9182-ee104a25e7a1.png
new file mode 100644
index 00000000..4c61977c
Binary files /dev/null and b/docs/notes/pics/4fc032e0-ac6f-4b42-9182-ee104a25e7a1.png differ
diff --git a/docs/notes/pics/4ff355cf-9a7f-4468-af43-e5b02038facc.jpg b/docs/notes/pics/4ff355cf-9a7f-4468-af43-e5b02038facc.jpg
new file mode 100644
index 00000000..f81e5707
Binary files /dev/null and b/docs/notes/pics/4ff355cf-9a7f-4468-af43-e5b02038facc.jpg differ
diff --git a/docs/notes/pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg b/docs/notes/pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg
new file mode 100644
index 00000000..4a3f798b
Binary files /dev/null and b/docs/notes/pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg differ
diff --git a/docs/notes/pics/50d38e84-238f-4081-8876-14ef6d7938b5.jpg b/docs/notes/pics/50d38e84-238f-4081-8876-14ef6d7938b5.jpg
new file mode 100644
index 00000000..6546cefa
Binary files /dev/null and b/docs/notes/pics/50d38e84-238f-4081-8876-14ef6d7938b5.jpg differ
diff --git a/docs/notes/pics/5158bc2f-83a6-4351-817e-c9b07f955d76.png b/docs/notes/pics/5158bc2f-83a6-4351-817e-c9b07f955d76.png
new file mode 100644
index 00000000..61f0adce
Binary files /dev/null and b/docs/notes/pics/5158bc2f-83a6-4351-817e-c9b07f955d76.png differ
diff --git a/docs/notes/pics/518f16f2-a9f7-499a-98e1-f1dbb37b5a9a.png b/docs/notes/pics/518f16f2-a9f7-499a-98e1-f1dbb37b5a9a.png
new file mode 100644
index 00000000..3a1010b9
Binary files /dev/null and b/docs/notes/pics/518f16f2-a9f7-499a-98e1-f1dbb37b5a9a.png differ
diff --git a/docs/notes/pics/51e2ed95-65b8-4ae9-8af3-65602d452a25.jpg b/docs/notes/pics/51e2ed95-65b8-4ae9-8af3-65602d452a25.jpg
new file mode 100644
index 00000000..595cdc58
Binary files /dev/null and b/docs/notes/pics/51e2ed95-65b8-4ae9-8af3-65602d452a25.jpg differ
diff --git a/docs/notes/pics/51fb761d-8ce0-4472-92ff-2f227ac7888a.png b/docs/notes/pics/51fb761d-8ce0-4472-92ff-2f227ac7888a.png
new file mode 100644
index 00000000..d49b1727
Binary files /dev/null and b/docs/notes/pics/51fb761d-8ce0-4472-92ff-2f227ac7888a.png differ
diff --git a/docs/notes/pics/5292faa6-0141-4638-bf0f-bb95b081dcba.jpg b/docs/notes/pics/5292faa6-0141-4638-bf0f-bb95b081dcba.jpg
new file mode 100644
index 00000000..32e1f054
Binary files /dev/null and b/docs/notes/pics/5292faa6-0141-4638-bf0f-bb95b081dcba.jpg differ
diff --git a/docs/notes/pics/52e1af6f-3a7a-4bee-aa8f-fcb5dacebe40.jpg b/docs/notes/pics/52e1af6f-3a7a-4bee-aa8f-fcb5dacebe40.jpg
new file mode 100644
index 00000000..809abead
Binary files /dev/null and b/docs/notes/pics/52e1af6f-3a7a-4bee-aa8f-fcb5dacebe40.jpg differ
diff --git a/docs/notes/pics/5341d726-ffde-4d2a-a000-46597bcc9c5a.png b/docs/notes/pics/5341d726-ffde-4d2a-a000-46597bcc9c5a.png
new file mode 100644
index 00000000..61161099
Binary files /dev/null and b/docs/notes/pics/5341d726-ffde-4d2a-a000-46597bcc9c5a.png differ
diff --git a/docs/notes/pics/5359cbf5-5a79-4874-9b17-f23c53c2cb80.jpg b/docs/notes/pics/5359cbf5-5a79-4874-9b17-f23c53c2cb80.jpg
new file mode 100644
index 00000000..a449f38c
Binary files /dev/null and b/docs/notes/pics/5359cbf5-5a79-4874-9b17-f23c53c2cb80.jpg differ
diff --git a/docs/notes/pics/536c6dfd-305a-4b95-b12c-28ca5e8aa043.png b/docs/notes/pics/536c6dfd-305a-4b95-b12c-28ca5e8aa043.png
new file mode 100644
index 00000000..29bbc9de
Binary files /dev/null and b/docs/notes/pics/536c6dfd-305a-4b95-b12c-28ca5e8aa043.png differ
diff --git a/docs/notes/pics/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png b/docs/notes/pics/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png
new file mode 100644
index 00000000..2666f9c2
Binary files /dev/null and b/docs/notes/pics/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png differ
diff --git a/docs/notes/pics/540631a4-6018-40a5-aed7-081e2eeeaeea.png b/docs/notes/pics/540631a4-6018-40a5-aed7-081e2eeeaeea.png
new file mode 100644
index 00000000..e22b2c83
Binary files /dev/null and b/docs/notes/pics/540631a4-6018-40a5-aed7-081e2eeeaeea.png differ
diff --git a/docs/notes/pics/54cb3f21-485b-4159-8bf5-dcde1c4d4c36.png b/docs/notes/pics/54cb3f21-485b-4159-8bf5-dcde1c4d4c36.png
new file mode 100644
index 00000000..3a69d2ce
Binary files /dev/null and b/docs/notes/pics/54cb3f21-485b-4159-8bf5-dcde1c4d4c36.png differ
diff --git a/docs/notes/pics/54f1e052-0596-4b5e-833c-e80d75bf3f9b.png b/docs/notes/pics/54f1e052-0596-4b5e-833c-e80d75bf3f9b.png
new file mode 100644
index 00000000..ad60a7e0
Binary files /dev/null and b/docs/notes/pics/54f1e052-0596-4b5e-833c-e80d75bf3f9b.png differ
diff --git a/docs/notes/pics/55dc4e84-573d-4c13-a765-52ed1dd251f9.png b/docs/notes/pics/55dc4e84-573d-4c13-a765-52ed1dd251f9.png
new file mode 100644
index 00000000..525b323a
Binary files /dev/null and b/docs/notes/pics/55dc4e84-573d-4c13-a765-52ed1dd251f9.png differ
diff --git a/docs/notes/pics/562f2844-d77c-40e0-887a-28a7128abd42.png b/docs/notes/pics/562f2844-d77c-40e0-887a-28a7128abd42.png
new file mode 100644
index 00000000..b74f69b7
Binary files /dev/null and b/docs/notes/pics/562f2844-d77c-40e0-887a-28a7128abd42.png differ
diff --git a/docs/notes/pics/58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg b/docs/notes/pics/58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg
new file mode 100644
index 00000000..a695be3a
Binary files /dev/null and b/docs/notes/pics/58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg differ
diff --git a/docs/notes/pics/5930aeb8-847d-4e9f-a168-9334d7dec744.png b/docs/notes/pics/5930aeb8-847d-4e9f-a168-9334d7dec744.png
new file mode 100644
index 00000000..6c9a572e
Binary files /dev/null and b/docs/notes/pics/5930aeb8-847d-4e9f-a168-9334d7dec744.png differ
diff --git a/docs/notes/pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg b/docs/notes/pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg
new file mode 100644
index 00000000..62b39e4b
Binary files /dev/null and b/docs/notes/pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg differ
diff --git a/docs/notes/pics/5999e5de-7c16-4b52-b3aa-6dc7b58c7894.png b/docs/notes/pics/5999e5de-7c16-4b52-b3aa-6dc7b58c7894.png
new file mode 100644
index 00000000..a61a7dc4
Binary files /dev/null and b/docs/notes/pics/5999e5de-7c16-4b52-b3aa-6dc7b58c7894.png differ
diff --git a/docs/notes/pics/5aa82b89-f266-44da-887d-18f31f01d8ef.png b/docs/notes/pics/5aa82b89-f266-44da-887d-18f31f01d8ef.png
new file mode 100644
index 00000000..68310502
Binary files /dev/null and b/docs/notes/pics/5aa82b89-f266-44da-887d-18f31f01d8ef.png differ
diff --git a/docs/notes/pics/5aac64d3-2c7b-4f32-9e9a-1df2186f588b.png b/docs/notes/pics/5aac64d3-2c7b-4f32-9e9a-1df2186f588b.png
new file mode 100644
index 00000000..f457a99d
Binary files /dev/null and b/docs/notes/pics/5aac64d3-2c7b-4f32-9e9a-1df2186f588b.png differ
diff --git a/docs/notes/pics/5acf7550-86c5-4c5b-b912-8ce70ef9c34e.png b/docs/notes/pics/5acf7550-86c5-4c5b-b912-8ce70ef9c34e.png
new file mode 100644
index 00000000..e209482b
Binary files /dev/null and b/docs/notes/pics/5acf7550-86c5-4c5b-b912-8ce70ef9c34e.png differ
diff --git a/docs/notes/pics/5b910141-08b6-442d-a4bc-a1608458c636.png b/docs/notes/pics/5b910141-08b6-442d-a4bc-a1608458c636.png
new file mode 100644
index 00000000..67134656
Binary files /dev/null and b/docs/notes/pics/5b910141-08b6-442d-a4bc-a1608458c636.png differ
diff --git a/docs/notes/pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg b/docs/notes/pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg
new file mode 100644
index 00000000..ba83d342
Binary files /dev/null and b/docs/notes/pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg differ
diff --git a/docs/notes/pics/5d4a5181-65fb-4bf2-a9c6-899cab534b44.png b/docs/notes/pics/5d4a5181-65fb-4bf2-a9c6-899cab534b44.png
new file mode 100644
index 00000000..110bea35
Binary files /dev/null and b/docs/notes/pics/5d4a5181-65fb-4bf2-a9c6-899cab534b44.png differ
diff --git a/docs/notes/pics/5e8d3c04-d93b-48a7-875e-41ababed00e0.jpg b/docs/notes/pics/5e8d3c04-d93b-48a7-875e-41ababed00e0.jpg
new file mode 100644
index 00000000..b8d0adf8
Binary files /dev/null and b/docs/notes/pics/5e8d3c04-d93b-48a7-875e-41ababed00e0.jpg differ
diff --git a/docs/notes/pics/5e9b10f3-9504-4483-9667-d4770adebf9f.png b/docs/notes/pics/5e9b10f3-9504-4483-9667-d4770adebf9f.png
new file mode 100644
index 00000000..4ac499de
Binary files /dev/null and b/docs/notes/pics/5e9b10f3-9504-4483-9667-d4770adebf9f.png differ
diff --git a/docs/notes/pics/5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg b/docs/notes/pics/5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg
new file mode 100644
index 00000000..dd5c7c16
Binary files /dev/null and b/docs/notes/pics/5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg differ
diff --git a/docs/notes/pics/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png b/docs/notes/pics/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png
new file mode 100644
index 00000000..a3ea0a24
Binary files /dev/null and b/docs/notes/pics/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png differ
diff --git a/docs/notes/pics/5f96e565-0693-47df-80f1-29e4271057b7.png b/docs/notes/pics/5f96e565-0693-47df-80f1-29e4271057b7.png
new file mode 100644
index 00000000..4da1e286
Binary files /dev/null and b/docs/notes/pics/5f96e565-0693-47df-80f1-29e4271057b7.png differ
diff --git a/docs/notes/pics/600e9c75-5033-4dad-ae2b-930957db638e.png b/docs/notes/pics/600e9c75-5033-4dad-ae2b-930957db638e.png
new file mode 100644
index 00000000..bf0834d5
Binary files /dev/null and b/docs/notes/pics/600e9c75-5033-4dad-ae2b-930957db638e.png differ
diff --git a/docs/notes/pics/600px-Sharedmem.jpg b/docs/notes/pics/600px-Sharedmem.jpg
new file mode 100644
index 00000000..76cb2a48
Binary files /dev/null and b/docs/notes/pics/600px-Sharedmem.jpg differ
diff --git a/docs/notes/pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png b/docs/notes/pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png
new file mode 100644
index 00000000..900ee963
Binary files /dev/null and b/docs/notes/pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png differ
diff --git a/docs/notes/pics/61942711-45a0-4e11-bbc9-434e31436f33.png b/docs/notes/pics/61942711-45a0-4e11-bbc9-434e31436f33.png
new file mode 100644
index 00000000..8f093ef6
Binary files /dev/null and b/docs/notes/pics/61942711-45a0-4e11-bbc9-434e31436f33.png differ
diff --git a/docs/notes/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png b/docs/notes/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png
new file mode 100644
index 00000000..3a41cdce
Binary files /dev/null and b/docs/notes/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png differ
diff --git a/docs/notes/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg b/docs/notes/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg
new file mode 100644
index 00000000..90e9065c
Binary files /dev/null and b/docs/notes/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg differ
diff --git a/docs/notes/pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg b/docs/notes/pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg
new file mode 100644
index 00000000..d6471621
Binary files /dev/null and b/docs/notes/pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg differ
diff --git a/docs/notes/pics/63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg b/docs/notes/pics/63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg
new file mode 100644
index 00000000..05fac206
Binary files /dev/null and b/docs/notes/pics/63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg differ
diff --git a/docs/notes/pics/6539b9a4-2b24-4d10-8c94-2eb5aba1e296.png b/docs/notes/pics/6539b9a4-2b24-4d10-8c94-2eb5aba1e296.png
new file mode 100644
index 00000000..053a3dc6
Binary files /dev/null and b/docs/notes/pics/6539b9a4-2b24-4d10-8c94-2eb5aba1e296.png differ
diff --git a/docs/notes/pics/654acfed-a6a5-4fc7-8f40-3fdcae57bae8.jpg b/docs/notes/pics/654acfed-a6a5-4fc7-8f40-3fdcae57bae8.jpg
new file mode 100644
index 00000000..ed98e7e6
Binary files /dev/null and b/docs/notes/pics/654acfed-a6a5-4fc7-8f40-3fdcae57bae8.jpg differ
diff --git a/docs/notes/pics/658fc5e7-79c0-4247-9445-d69bf194c539.png b/docs/notes/pics/658fc5e7-79c0-4247-9445-d69bf194c539.png
new file mode 100644
index 00000000..f488859e
Binary files /dev/null and b/docs/notes/pics/658fc5e7-79c0-4247-9445-d69bf194c539.png differ
diff --git a/docs/notes/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg b/docs/notes/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg
new file mode 100644
index 00000000..eec226c5
Binary files /dev/null and b/docs/notes/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg differ
diff --git a/docs/notes/pics/66402828-fb2b-418f-83f6-82153491bcfe.jpg b/docs/notes/pics/66402828-fb2b-418f-83f6-82153491bcfe.jpg
new file mode 100644
index 00000000..fc86a236
Binary files /dev/null and b/docs/notes/pics/66402828-fb2b-418f-83f6-82153491bcfe.jpg differ
diff --git a/docs/notes/pics/6675d713-8b59-4067-ad16-fdd538d4bb43.png b/docs/notes/pics/6675d713-8b59-4067-ad16-fdd538d4bb43.png
new file mode 100644
index 00000000..65048cb3
Binary files /dev/null and b/docs/notes/pics/6675d713-8b59-4067-ad16-fdd538d4bb43.png differ
diff --git a/docs/notes/pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg b/docs/notes/pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg
new file mode 100644
index 00000000..7035f001
Binary files /dev/null and b/docs/notes/pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg differ
diff --git a/docs/notes/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png b/docs/notes/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png
new file mode 100644
index 00000000..b63baeb2
Binary files /dev/null and b/docs/notes/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png differ
diff --git a/docs/notes/pics/685a692f-8f76-4cac-baac-b68e2df9a30f.jpg b/docs/notes/pics/685a692f-8f76-4cac-baac-b68e2df9a30f.jpg
new file mode 100644
index 00000000..a1d12d17
Binary files /dev/null and b/docs/notes/pics/685a692f-8f76-4cac-baac-b68e2df9a30f.jpg differ
diff --git a/docs/notes/pics/68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png b/docs/notes/pics/68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png
new file mode 100644
index 00000000..39d7ec60
Binary files /dev/null and b/docs/notes/pics/68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png differ
diff --git a/docs/notes/pics/688dacfe-1057-412f-b3a1-86abb5b0f914.png b/docs/notes/pics/688dacfe-1057-412f-b3a1-86abb5b0f914.png
new file mode 100644
index 00000000..21fa725f
Binary files /dev/null and b/docs/notes/pics/688dacfe-1057-412f-b3a1-86abb5b0f914.png differ
diff --git a/docs/notes/pics/68b110b9-76c6-4ee2-b541-4145e65adb3e.jpg b/docs/notes/pics/68b110b9-76c6-4ee2-b541-4145e65adb3e.jpg
new file mode 100644
index 00000000..d82f46eb
Binary files /dev/null and b/docs/notes/pics/68b110b9-76c6-4ee2-b541-4145e65adb3e.jpg differ
diff --git a/docs/notes/pics/691f11eb-31a7-46be-9de1-61f433c4b3c7.png b/docs/notes/pics/691f11eb-31a7-46be-9de1-61f433c4b3c7.png
new file mode 100644
index 00000000..b61e2174
Binary files /dev/null and b/docs/notes/pics/691f11eb-31a7-46be-9de1-61f433c4b3c7.png differ
diff --git a/docs/notes/pics/699b4f96-d63f-46ea-a581-2b3d95eceb6a.jpg b/docs/notes/pics/699b4f96-d63f-46ea-a581-2b3d95eceb6a.jpg
new file mode 100644
index 00000000..313b0f92
Binary files /dev/null and b/docs/notes/pics/699b4f96-d63f-46ea-a581-2b3d95eceb6a.jpg differ
diff --git a/docs/notes/pics/69f16984-a66f-4288-82e4-79b4aa43e835.jpg b/docs/notes/pics/69f16984-a66f-4288-82e4-79b4aa43e835.jpg
new file mode 100644
index 00000000..03b7f3da
Binary files /dev/null and b/docs/notes/pics/69f16984-a66f-4288-82e4-79b4aa43e835.jpg differ
diff --git a/docs/notes/pics/6c0f4afb-20ab-49fd-837d-8144f4e38bfd.png b/docs/notes/pics/6c0f4afb-20ab-49fd-837d-8144f4e38bfd.png
new file mode 100644
index 00000000..d86b4635
Binary files /dev/null and b/docs/notes/pics/6c0f4afb-20ab-49fd-837d-8144f4e38bfd.png differ
diff --git a/docs/notes/pics/6f4abf41-3728-4a6b-9b94-85eed7ca8163.png b/docs/notes/pics/6f4abf41-3728-4a6b-9b94-85eed7ca8163.png
new file mode 100644
index 00000000..1fb8642f
Binary files /dev/null and b/docs/notes/pics/6f4abf41-3728-4a6b-9b94-85eed7ca8163.png differ
diff --git a/docs/notes/pics/7.gif b/docs/notes/pics/7.gif
new file mode 100644
index 00000000..fad88513
Binary files /dev/null and b/docs/notes/pics/7.gif differ
diff --git a/docs/notes/pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png b/docs/notes/pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png
new file mode 100644
index 00000000..0d28e996
Binary files /dev/null and b/docs/notes/pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png differ
diff --git a/docs/notes/pics/71363383-2d06-4c63-8b72-c01c2186707d.png b/docs/notes/pics/71363383-2d06-4c63-8b72-c01c2186707d.png
new file mode 100644
index 00000000..621820c3
Binary files /dev/null and b/docs/notes/pics/71363383-2d06-4c63-8b72-c01c2186707d.png differ
diff --git a/docs/notes/pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png b/docs/notes/pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png
new file mode 100644
index 00000000..4e99159f
Binary files /dev/null and b/docs/notes/pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png differ
diff --git a/docs/notes/pics/7299afd2-9114-44e6-9d5e-4025d0b2a541.png b/docs/notes/pics/7299afd2-9114-44e6-9d5e-4025d0b2a541.png
new file mode 100644
index 00000000..812d4643
Binary files /dev/null and b/docs/notes/pics/7299afd2-9114-44e6-9d5e-4025d0b2a541.png differ
diff --git a/docs/notes/pics/72f0ff69-138d-4e54-b7ac-ebe025d978dc.png b/docs/notes/pics/72f0ff69-138d-4e54-b7ac-ebe025d978dc.png
new file mode 100644
index 00000000..5299728f
Binary files /dev/null and b/docs/notes/pics/72f0ff69-138d-4e54-b7ac-ebe025d978dc.png differ
diff --git a/docs/notes/pics/72fe492e-f1cb-4cfc-92f8-412fb3ae6fec.png b/docs/notes/pics/72fe492e-f1cb-4cfc-92f8-412fb3ae6fec.png
new file mode 100644
index 00000000..748980c4
Binary files /dev/null and b/docs/notes/pics/72fe492e-f1cb-4cfc-92f8-412fb3ae6fec.png differ
diff --git a/docs/notes/pics/73b73189-9e95-47e5-91d0-9378b8462e15.png b/docs/notes/pics/73b73189-9e95-47e5-91d0-9378b8462e15.png
new file mode 100644
index 00000000..3f3b32e5
Binary files /dev/null and b/docs/notes/pics/73b73189-9e95-47e5-91d0-9378b8462e15.png differ
diff --git a/docs/notes/pics/766aedd0-1b00-4065-aa2b-7d31138df84f.png b/docs/notes/pics/766aedd0-1b00-4065-aa2b-7d31138df84f.png
new file mode 100644
index 00000000..e8a69bff
Binary files /dev/null and b/docs/notes/pics/766aedd0-1b00-4065-aa2b-7d31138df84f.png differ
diff --git a/docs/notes/pics/76a25fc8-a579-4d7c-974b-7640b57fbf39.jpg b/docs/notes/pics/76a25fc8-a579-4d7c-974b-7640b57fbf39.jpg
new file mode 100644
index 00000000..fd13a137
Binary files /dev/null and b/docs/notes/pics/76a25fc8-a579-4d7c-974b-7640b57fbf39.jpg differ
diff --git a/docs/notes/pics/76a49594323247f21c9b3a69945445ee.png b/docs/notes/pics/76a49594323247f21c9b3a69945445ee.png
new file mode 100644
index 00000000..788ba0b1
Binary files /dev/null and b/docs/notes/pics/76a49594323247f21c9b3a69945445ee.png differ
diff --git a/docs/notes/pics/76b48b4c-8999-4967-893b-832602e73285.png b/docs/notes/pics/76b48b4c-8999-4967-893b-832602e73285.png
new file mode 100644
index 00000000..ce851687
Binary files /dev/null and b/docs/notes/pics/76b48b4c-8999-4967-893b-832602e73285.png differ
diff --git a/docs/notes/pics/76dc7769-1aac-4888-9bea-064f1caa8e77.jpg b/docs/notes/pics/76dc7769-1aac-4888-9bea-064f1caa8e77.jpg
new file mode 100644
index 00000000..642aba6b
Binary files /dev/null and b/docs/notes/pics/76dc7769-1aac-4888-9bea-064f1caa8e77.jpg differ
diff --git a/docs/notes/pics/7779232-1e8ed39548081a1f.png b/docs/notes/pics/7779232-1e8ed39548081a1f.png
new file mode 100644
index 00000000..95e9027e
Binary files /dev/null and b/docs/notes/pics/7779232-1e8ed39548081a1f.png differ
diff --git a/docs/notes/pics/7779232-96822582feb08651.png b/docs/notes/pics/7779232-96822582feb08651.png
new file mode 100644
index 00000000..d45ba85c
Binary files /dev/null and b/docs/notes/pics/7779232-96822582feb08651.png differ
diff --git a/docs/notes/pics/77931a4b-72ba-4016-827d-84b9a6845a51.png b/docs/notes/pics/77931a4b-72ba-4016-827d-84b9a6845a51.png
new file mode 100644
index 00000000..6f8a3c52
Binary files /dev/null and b/docs/notes/pics/77931a4b-72ba-4016-827d-84b9a6845a51.png differ
diff --git a/docs/notes/pics/77f81379-3987-4036-8d7c-93a4dcf7b05d.jpg b/docs/notes/pics/77f81379-3987-4036-8d7c-93a4dcf7b05d.jpg
new file mode 100644
index 00000000..bc5ddb98
Binary files /dev/null and b/docs/notes/pics/77f81379-3987-4036-8d7c-93a4dcf7b05d.jpg differ
diff --git a/docs/notes/pics/79076335-cfae-4fe6-97b9-62e8eebbf2b9.png b/docs/notes/pics/79076335-cfae-4fe6-97b9-62e8eebbf2b9.png
new file mode 100644
index 00000000..6d9ce787
Binary files /dev/null and b/docs/notes/pics/79076335-cfae-4fe6-97b9-62e8eebbf2b9.png differ
diff --git a/docs/notes/pics/794239e3-4baf-4aad-92df-f02f59b2a6fe.png b/docs/notes/pics/794239e3-4baf-4aad-92df-f02f59b2a6fe.png
new file mode 100644
index 00000000..7adddd91
Binary files /dev/null and b/docs/notes/pics/794239e3-4baf-4aad-92df-f02f59b2a6fe.png differ
diff --git a/docs/notes/pics/79b12431-6d9d-4a7d-985b-1b79bc5bf5fb.png b/docs/notes/pics/79b12431-6d9d-4a7d-985b-1b79bc5bf5fb.png
new file mode 100644
index 00000000..d2a30004
Binary files /dev/null and b/docs/notes/pics/79b12431-6d9d-4a7d-985b-1b79bc5bf5fb.png differ
diff --git a/docs/notes/pics/7a29acce-f243-4914-9f00-f2988c528412.jpg b/docs/notes/pics/7a29acce-f243-4914-9f00-f2988c528412.jpg
new file mode 100644
index 00000000..a048d094
Binary files /dev/null and b/docs/notes/pics/7a29acce-f243-4914-9f00-f2988c528412.jpg differ
diff --git a/docs/notes/pics/7a3c6a30-c735-4edb-8115-337288a4f0f2.jpg b/docs/notes/pics/7a3c6a30-c735-4edb-8115-337288a4f0f2.jpg
new file mode 100644
index 00000000..8d40765e
Binary files /dev/null and b/docs/notes/pics/7a3c6a30-c735-4edb-8115-337288a4f0f2.jpg differ
diff --git a/docs/notes/pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg b/docs/notes/pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg
new file mode 100644
index 00000000..31c70314
Binary files /dev/null and b/docs/notes/pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg differ
diff --git a/docs/notes/pics/7b038838-c75b-4538-ae84-6299386704e5.jpg b/docs/notes/pics/7b038838-c75b-4538-ae84-6299386704e5.jpg
new file mode 100644
index 00000000..919a0e58
Binary files /dev/null and b/docs/notes/pics/7b038838-c75b-4538-ae84-6299386704e5.jpg differ
diff --git a/docs/notes/pics/7b281b1e-0595-402b-ae35-8c91084c33c1.png b/docs/notes/pics/7b281b1e-0595-402b-ae35-8c91084c33c1.png
new file mode 100644
index 00000000..9308ecb6
Binary files /dev/null and b/docs/notes/pics/7b281b1e-0595-402b-ae35-8c91084c33c1.png differ
diff --git a/docs/notes/pics/7b3efa99-d306-4982-8cfb-e7153c33aab4.png b/docs/notes/pics/7b3efa99-d306-4982-8cfb-e7153c33aab4.png
new file mode 100644
index 00000000..21aafd0a
Binary files /dev/null and b/docs/notes/pics/7b3efa99-d306-4982-8cfb-e7153c33aab4.png differ
diff --git a/docs/notes/pics/7b48448f-cbe3-4287-9041-f56566b9d0b4.png b/docs/notes/pics/7b48448f-cbe3-4287-9041-f56566b9d0b4.png
new file mode 100644
index 00000000..6d981924
Binary files /dev/null and b/docs/notes/pics/7b48448f-cbe3-4287-9041-f56566b9d0b4.png differ
diff --git a/docs/notes/pics/7b68b142-9489-44f6-87b0-4cb5c6431e63.jpg b/docs/notes/pics/7b68b142-9489-44f6-87b0-4cb5c6431e63.jpg
new file mode 100644
index 00000000..d4380524
Binary files /dev/null and b/docs/notes/pics/7b68b142-9489-44f6-87b0-4cb5c6431e63.jpg differ
diff --git a/docs/notes/pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png b/docs/notes/pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png
new file mode 100644
index 00000000..711fb45b
Binary files /dev/null and b/docs/notes/pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png differ
diff --git a/docs/notes/pics/7be0abf9-687c-4451-becd-626b0be7ec22.jpg b/docs/notes/pics/7be0abf9-687c-4451-becd-626b0be7ec22.jpg
new file mode 100644
index 00000000..002f50ac
Binary files /dev/null and b/docs/notes/pics/7be0abf9-687c-4451-becd-626b0be7ec22.jpg differ
diff --git a/docs/notes/pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png b/docs/notes/pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png
new file mode 100644
index 00000000..8b5ce204
Binary files /dev/null and b/docs/notes/pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png differ
diff --git a/docs/notes/pics/7c98e1b6-c446-4cde-8513-5c11b9f52aea.jpg b/docs/notes/pics/7c98e1b6-c446-4cde-8513-5c11b9f52aea.jpg
new file mode 100644
index 00000000..7dcb6d1c
Binary files /dev/null and b/docs/notes/pics/7c98e1b6-c446-4cde-8513-5c11b9f52aea.jpg differ
diff --git a/docs/notes/pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png b/docs/notes/pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png
new file mode 100644
index 00000000..66e26e80
Binary files /dev/null and b/docs/notes/pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png differ
diff --git a/docs/notes/pics/7ec9d619-fa60-4a2b-95aa-bf1a62aad408.jpg b/docs/notes/pics/7ec9d619-fa60-4a2b-95aa-bf1a62aad408.jpg
new file mode 100644
index 00000000..5753388e
Binary files /dev/null and b/docs/notes/pics/7ec9d619-fa60-4a2b-95aa-bf1a62aad408.jpg differ
diff --git a/docs/notes/pics/7f38a583-2f2e-4738-97af-510e6fb403a7.png b/docs/notes/pics/7f38a583-2f2e-4738-97af-510e6fb403a7.png
new file mode 100644
index 00000000..57e71b9c
Binary files /dev/null and b/docs/notes/pics/7f38a583-2f2e-4738-97af-510e6fb403a7.png differ
diff --git a/docs/notes/pics/7f642a65-b167-4c8f-b382-8322c6322b2c.jpg b/docs/notes/pics/7f642a65-b167-4c8f-b382-8322c6322b2c.jpg
new file mode 100644
index 00000000..27751a37
Binary files /dev/null and b/docs/notes/pics/7f642a65-b167-4c8f-b382-8322c6322b2c.jpg differ
diff --git a/docs/notes/pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png b/docs/notes/pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png
new file mode 100644
index 00000000..b636edf5
Binary files /dev/null and b/docs/notes/pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png differ
diff --git a/docs/notes/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png b/docs/notes/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png
new file mode 100644
index 00000000..ac453eeb
Binary files /dev/null and b/docs/notes/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png differ
diff --git a/docs/notes/pics/80804f52-8815-4096-b506-48eef3eed5c6.png b/docs/notes/pics/80804f52-8815-4096-b506-48eef3eed5c6.png
new file mode 100644
index 00000000..06c8760b
Binary files /dev/null and b/docs/notes/pics/80804f52-8815-4096-b506-48eef3eed5c6.png differ
diff --git a/docs/notes/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg b/docs/notes/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg
new file mode 100644
index 00000000..5446f103
Binary files /dev/null and b/docs/notes/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg differ
diff --git a/docs/notes/pics/8229e8e7-a183-4d29-94e6-e8d8537c6ce5.png b/docs/notes/pics/8229e8e7-a183-4d29-94e6-e8d8537c6ce5.png
new file mode 100644
index 00000000..3aaa6323
Binary files /dev/null and b/docs/notes/pics/8229e8e7-a183-4d29-94e6-e8d8537c6ce5.png differ
diff --git a/docs/notes/pics/823cdab7-3779-4e3a-a951-dc2d154e0ee6.jpg b/docs/notes/pics/823cdab7-3779-4e3a-a951-dc2d154e0ee6.jpg
new file mode 100644
index 00000000..48d9c267
Binary files /dev/null and b/docs/notes/pics/823cdab7-3779-4e3a-a951-dc2d154e0ee6.jpg differ
diff --git a/docs/notes/pics/82cfda3b-b53b-4c89-9fdb-26dd2db0cd02.jpg b/docs/notes/pics/82cfda3b-b53b-4c89-9fdb-26dd2db0cd02.jpg
new file mode 100644
index 00000000..2b510c43
Binary files /dev/null and b/docs/notes/pics/82cfda3b-b53b-4c89-9fdb-26dd2db0cd02.jpg differ
diff --git a/docs/notes/pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg b/docs/notes/pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg
new file mode 100644
index 00000000..cb83edea
Binary files /dev/null and b/docs/notes/pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg differ
diff --git a/docs/notes/pics/836a4eaf-4798-4e48-b52a-a3dab9435ace.png b/docs/notes/pics/836a4eaf-4798-4e48-b52a-a3dab9435ace.png
new file mode 100644
index 00000000..be8ab737
Binary files /dev/null and b/docs/notes/pics/836a4eaf-4798-4e48-b52a-a3dab9435ace.png differ
diff --git a/docs/notes/pics/8433fbb2-c35c-45ef-831d-e3ca42aebd51.png b/docs/notes/pics/8433fbb2-c35c-45ef-831d-e3ca42aebd51.png
new file mode 100644
index 00000000..5c0b076b
Binary files /dev/null and b/docs/notes/pics/8433fbb2-c35c-45ef-831d-e3ca42aebd51.png differ
diff --git a/docs/notes/pics/85370d54-40d1-4912-bcbe-37a2481c861d.png b/docs/notes/pics/85370d54-40d1-4912-bcbe-37a2481c861d.png
new file mode 100644
index 00000000..f1664e13
Binary files /dev/null and b/docs/notes/pics/85370d54-40d1-4912-bcbe-37a2481c861d.png differ
diff --git a/docs/notes/pics/85583359-1b45-45f2-9811-4f7bb9a64db7.jpg b/docs/notes/pics/85583359-1b45-45f2-9811-4f7bb9a64db7.jpg
new file mode 100644
index 00000000..0abcf7d6
Binary files /dev/null and b/docs/notes/pics/85583359-1b45-45f2-9811-4f7bb9a64db7.jpg differ
diff --git a/docs/notes/pics/8587132a-021d-4f1f-a8ec-5a9daa7157a7.png b/docs/notes/pics/8587132a-021d-4f1f-a8ec-5a9daa7157a7.png
new file mode 100644
index 00000000..f77ff346
Binary files /dev/null and b/docs/notes/pics/8587132a-021d-4f1f-a8ec-5a9daa7157a7.png differ
diff --git a/docs/notes/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg b/docs/notes/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg
new file mode 100644
index 00000000..4b911193
Binary files /dev/null and b/docs/notes/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg differ
diff --git a/docs/notes/pics/864bfa7d-1149-420c-a752-f9b3d4e782ec.png b/docs/notes/pics/864bfa7d-1149-420c-a752-f9b3d4e782ec.png
new file mode 100644
index 00000000..72cc988f
Binary files /dev/null and b/docs/notes/pics/864bfa7d-1149-420c-a752-f9b3d4e782ec.png differ
diff --git a/docs/notes/pics/8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png b/docs/notes/pics/8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png
new file mode 100644
index 00000000..9eda1deb
Binary files /dev/null and b/docs/notes/pics/8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png differ
diff --git a/docs/notes/pics/867e93eb-3161-4f39-b2d2-c0cd3788e194.png b/docs/notes/pics/867e93eb-3161-4f39-b2d2-c0cd3788e194.png
new file mode 100644
index 00000000..26cb0153
Binary files /dev/null and b/docs/notes/pics/867e93eb-3161-4f39-b2d2-c0cd3788e194.png differ
diff --git a/docs/notes/pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png b/docs/notes/pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png
new file mode 100644
index 00000000..56f83eaf
Binary files /dev/null and b/docs/notes/pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png differ
diff --git a/docs/notes/pics/88ff46b3-028a-4dbb-a572-1f062b8b96d3.png b/docs/notes/pics/88ff46b3-028a-4dbb-a572-1f062b8b96d3.png
new file mode 100644
index 00000000..c6344ad2
Binary files /dev/null and b/docs/notes/pics/88ff46b3-028a-4dbb-a572-1f062b8b96d3.png differ
diff --git a/docs/notes/pics/897503d0-59e3-4752-903d-529fbdb72fee.jpg b/docs/notes/pics/897503d0-59e3-4752-903d-529fbdb72fee.jpg
new file mode 100644
index 00000000..e0935e57
Binary files /dev/null and b/docs/notes/pics/897503d0-59e3-4752-903d-529fbdb72fee.jpg differ
diff --git a/docs/notes/pics/8a4c6ad4-a816-47d1-b93f-7ca4f78ab67a.png b/docs/notes/pics/8a4c6ad4-a816-47d1-b93f-7ca4f78ab67a.png
new file mode 100644
index 00000000..360a984e
Binary files /dev/null and b/docs/notes/pics/8a4c6ad4-a816-47d1-b93f-7ca4f78ab67a.png differ
diff --git a/docs/notes/pics/8adb2591-d3f1-4632-84cb-823fb9c5eb09.jpg b/docs/notes/pics/8adb2591-d3f1-4632-84cb-823fb9c5eb09.jpg
new file mode 100644
index 00000000..9083d22b
Binary files /dev/null and b/docs/notes/pics/8adb2591-d3f1-4632-84cb-823fb9c5eb09.jpg differ
diff --git a/docs/notes/pics/8ae4550b-f0cb-4e4d-9e2b-c550538bf230.png b/docs/notes/pics/8ae4550b-f0cb-4e4d-9e2b-c550538bf230.png
new file mode 100644
index 00000000..31ae5e0c
Binary files /dev/null and b/docs/notes/pics/8ae4550b-f0cb-4e4d-9e2b-c550538bf230.png differ
diff --git a/docs/notes/pics/8af348d0-4d72-4f76-b56c-0a440ed4673d.png b/docs/notes/pics/8af348d0-4d72-4f76-b56c-0a440ed4673d.png
new file mode 100644
index 00000000..9d575722
Binary files /dev/null and b/docs/notes/pics/8af348d0-4d72-4f76-b56c-0a440ed4673d.png differ
diff --git a/docs/notes/pics/8b335d94-c1ca-42e1-ad48-bb179d28a4f1.jpg b/docs/notes/pics/8b335d94-c1ca-42e1-ad48-bb179d28a4f1.jpg
new file mode 100644
index 00000000..17fb16de
Binary files /dev/null and b/docs/notes/pics/8b335d94-c1ca-42e1-ad48-bb179d28a4f1.jpg differ
diff --git a/docs/notes/pics/8b798007-e0fb-420c-b981-ead215692417.jpg b/docs/notes/pics/8b798007-e0fb-420c-b981-ead215692417.jpg
new file mode 100644
index 00000000..dd218133
Binary files /dev/null and b/docs/notes/pics/8b798007-e0fb-420c-b981-ead215692417.jpg differ
diff --git a/docs/notes/pics/8c0b3ae1-1087-46f4-8637-8d46b4ae659c.png b/docs/notes/pics/8c0b3ae1-1087-46f4-8637-8d46b4ae659c.png
new file mode 100644
index 00000000..86b3b637
Binary files /dev/null and b/docs/notes/pics/8c0b3ae1-1087-46f4-8637-8d46b4ae659c.png differ
diff --git a/docs/notes/pics/8c662999-c16c-481c-9f40-1fdba5bc9167.png b/docs/notes/pics/8c662999-c16c-481c-9f40-1fdba5bc9167.png
new file mode 100644
index 00000000..ff810e91
Binary files /dev/null and b/docs/notes/pics/8c662999-c16c-481c-9f40-1fdba5bc9167.png differ
diff --git a/docs/notes/pics/8cc671f0-7134-44b1-a7b5-6d24fe55e1c1.jpg b/docs/notes/pics/8cc671f0-7134-44b1-a7b5-6d24fe55e1c1.jpg
new file mode 100644
index 00000000..5e6608b2
Binary files /dev/null and b/docs/notes/pics/8cc671f0-7134-44b1-a7b5-6d24fe55e1c1.jpg differ
diff --git a/docs/notes/pics/8dfb4cc9-26da-45e7-b820-4576fa1cbb0e.png b/docs/notes/pics/8dfb4cc9-26da-45e7-b820-4576fa1cbb0e.png
new file mode 100644
index 00000000..7044dfbd
Binary files /dev/null and b/docs/notes/pics/8dfb4cc9-26da-45e7-b820-4576fa1cbb0e.png differ
diff --git a/docs/notes/pics/8f0cc500-5994-4c7a-91a9-62885d658662.png b/docs/notes/pics/8f0cc500-5994-4c7a-91a9-62885d658662.png
new file mode 100644
index 00000000..034205a8
Binary files /dev/null and b/docs/notes/pics/8f0cc500-5994-4c7a-91a9-62885d658662.png differ
diff --git a/docs/notes/pics/8f3b9519-d705-48fe-87ad-2e4052fc81d2.png b/docs/notes/pics/8f3b9519-d705-48fe-87ad-2e4052fc81d2.png
new file mode 100644
index 00000000..a8e36ee0
Binary files /dev/null and b/docs/notes/pics/8f3b9519-d705-48fe-87ad-2e4052fc81d2.png differ
diff --git a/docs/notes/pics/8f64e9c5-7682-4feb-9312-dea09514e160.jpg b/docs/notes/pics/8f64e9c5-7682-4feb-9312-dea09514e160.jpg
new file mode 100644
index 00000000..6f7e9e35
Binary files /dev/null and b/docs/notes/pics/8f64e9c5-7682-4feb-9312-dea09514e160.jpg differ
diff --git a/docs/notes/pics/8f6f9dc9-9ecd-47c8-b50e-2814f0219056.png b/docs/notes/pics/8f6f9dc9-9ecd-47c8-b50e-2814f0219056.png
new file mode 100644
index 00000000..21b8a930
Binary files /dev/null and b/docs/notes/pics/8f6f9dc9-9ecd-47c8-b50e-2814f0219056.png differ
diff --git a/docs/notes/pics/8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png b/docs/notes/pics/8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png
new file mode 100644
index 00000000..2e53fbe3
Binary files /dev/null and b/docs/notes/pics/8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png differ
diff --git a/docs/notes/pics/9.gif b/docs/notes/pics/9.gif
new file mode 100644
index 00000000..f81aa264
Binary files /dev/null and b/docs/notes/pics/9.gif differ
diff --git a/docs/notes/pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg b/docs/notes/pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg
new file mode 100644
index 00000000..7b2d0143
Binary files /dev/null and b/docs/notes/pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg differ
diff --git a/docs/notes/pics/902ef59f-7bcb-45a1-a80a-2f7afaa03629.jpg b/docs/notes/pics/902ef59f-7bcb-45a1-a80a-2f7afaa03629.jpg
new file mode 100644
index 00000000..552847b8
Binary files /dev/null and b/docs/notes/pics/902ef59f-7bcb-45a1-a80a-2f7afaa03629.jpg differ
diff --git a/docs/notes/pics/910f613f-514f-4534-87dd-9b4699d59d31.png b/docs/notes/pics/910f613f-514f-4534-87dd-9b4699d59d31.png
new file mode 100644
index 00000000..28362d47
Binary files /dev/null and b/docs/notes/pics/910f613f-514f-4534-87dd-9b4699d59d31.png differ
diff --git a/docs/notes/pics/9110c1a0-8a54-4145-a814-2477d0128114.png b/docs/notes/pics/9110c1a0-8a54-4145-a814-2477d0128114.png
new file mode 100644
index 00000000..68aa9f98
Binary files /dev/null and b/docs/notes/pics/9110c1a0-8a54-4145-a814-2477d0128114.png differ
diff --git a/docs/notes/pics/91ef04e4-923a-4277-99c0-6be4ce81e5ac.jpg b/docs/notes/pics/91ef04e4-923a-4277-99c0-6be4ce81e5ac.jpg
new file mode 100644
index 00000000..f4de7074
Binary files /dev/null and b/docs/notes/pics/91ef04e4-923a-4277-99c0-6be4ce81e5ac.jpg differ
diff --git a/docs/notes/pics/920c034c-c212-4f79-9ddb-84e4bb6cd088.png b/docs/notes/pics/920c034c-c212-4f79-9ddb-84e4bb6cd088.png
new file mode 100644
index 00000000..ac17fd0c
Binary files /dev/null and b/docs/notes/pics/920c034c-c212-4f79-9ddb-84e4bb6cd088.png differ
diff --git a/docs/notes/pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg b/docs/notes/pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg
new file mode 100644
index 00000000..5bb29598
Binary files /dev/null and b/docs/notes/pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg differ
diff --git a/docs/notes/pics/926c7438-c5e1-4b94-840a-dcb24ff1dafe.png b/docs/notes/pics/926c7438-c5e1-4b94-840a-dcb24ff1dafe.png
new file mode 100644
index 00000000..c6cdfd77
Binary files /dev/null and b/docs/notes/pics/926c7438-c5e1-4b94-840a-dcb24ff1dafe.png differ
diff --git a/docs/notes/pics/92ad9bae-7d02-43ba-8115-a9d6f530ca28.png b/docs/notes/pics/92ad9bae-7d02-43ba-8115-a9d6f530ca28.png
new file mode 100644
index 00000000..7b85c49a
Binary files /dev/null and b/docs/notes/pics/92ad9bae-7d02-43ba-8115-a9d6f530ca28.png differ
diff --git a/docs/notes/pics/94589319-975f-490b-8bae-90b3a4953559.png b/docs/notes/pics/94589319-975f-490b-8bae-90b3a4953559.png
new file mode 100644
index 00000000..fab53e3d
Binary files /dev/null and b/docs/notes/pics/94589319-975f-490b-8bae-90b3a4953559.png differ
diff --git a/docs/notes/pics/952afa9a-458b-44ce-bba9-463e60162945.png b/docs/notes/pics/952afa9a-458b-44ce-bba9-463e60162945.png
new file mode 100644
index 00000000..db93c1ac
Binary files /dev/null and b/docs/notes/pics/952afa9a-458b-44ce-bba9-463e60162945.png differ
diff --git a/docs/notes/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png b/docs/notes/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png
new file mode 100644
index 00000000..4983142a
Binary files /dev/null and b/docs/notes/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png differ
diff --git a/docs/notes/pics/955af054-8872-4569-82e7-2e10b66bc38e.png b/docs/notes/pics/955af054-8872-4569-82e7-2e10b66bc38e.png
new file mode 100644
index 00000000..502af347
Binary files /dev/null and b/docs/notes/pics/955af054-8872-4569-82e7-2e10b66bc38e.png differ
diff --git a/docs/notes/pics/96b63e13-e2d8-4ddb-9aa1-a38959ca96e5.jpg b/docs/notes/pics/96b63e13-e2d8-4ddb-9aa1-a38959ca96e5.jpg
new file mode 100644
index 00000000..3dbe14f1
Binary files /dev/null and b/docs/notes/pics/96b63e13-e2d8-4ddb-9aa1-a38959ca96e5.jpg differ
diff --git a/docs/notes/pics/992faced-afcf-414d-b801-9c16d6570fec.jpg b/docs/notes/pics/992faced-afcf-414d-b801-9c16d6570fec.jpg
new file mode 100644
index 00000000..1a363f1e
Binary files /dev/null and b/docs/notes/pics/992faced-afcf-414d-b801-9c16d6570fec.jpg differ
diff --git a/docs/notes/pics/9b829410-86c4-40aa-ba8d-9e8e26c0eeb8.jpg b/docs/notes/pics/9b829410-86c4-40aa-ba8d-9e8e26c0eeb8.jpg
new file mode 100644
index 00000000..470580c3
Binary files /dev/null and b/docs/notes/pics/9b829410-86c4-40aa-ba8d-9e8e26c0eeb8.jpg differ
diff --git a/docs/notes/pics/9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png b/docs/notes/pics/9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png
new file mode 100644
index 00000000..c7f87138
Binary files /dev/null and b/docs/notes/pics/9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png differ
diff --git a/docs/notes/pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png b/docs/notes/pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png
new file mode 100644
index 00000000..26ac536e
Binary files /dev/null and b/docs/notes/pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png differ
diff --git a/docs/notes/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png b/docs/notes/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png
new file mode 100644
index 00000000..49da824e
Binary files /dev/null and b/docs/notes/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png differ
diff --git a/docs/notes/pics/9d0a637c-6a8f-4f5a-99b9-fdcfa26793ff.png b/docs/notes/pics/9d0a637c-6a8f-4f5a-99b9-fdcfa26793ff.png
new file mode 100644
index 00000000..34a8f664
Binary files /dev/null and b/docs/notes/pics/9d0a637c-6a8f-4f5a-99b9-fdcfa26793ff.png differ
diff --git a/docs/notes/pics/9d549816-60b7-4899-9877-23b01503ab13.png b/docs/notes/pics/9d549816-60b7-4899-9877-23b01503ab13.png
new file mode 100644
index 00000000..9c4e04cc
Binary files /dev/null and b/docs/notes/pics/9d549816-60b7-4899-9877-23b01503ab13.png differ
diff --git a/docs/notes/pics/9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg b/docs/notes/pics/9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg
new file mode 100644
index 00000000..15d4b3c8
Binary files /dev/null and b/docs/notes/pics/9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg differ
diff --git a/docs/notes/pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png b/docs/notes/pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png
new file mode 100644
index 00000000..ba045e20
Binary files /dev/null and b/docs/notes/pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png differ
diff --git a/docs/notes/pics/BSD_disk.png b/docs/notes/pics/BSD_disk.png
new file mode 100644
index 00000000..48b0e0e8
Binary files /dev/null and b/docs/notes/pics/BSD_disk.png differ
diff --git a/docs/notes/pics/ClienteServidorSockets1521731145260.jpg b/docs/notes/pics/ClienteServidorSockets1521731145260.jpg
new file mode 100644
index 00000000..18976fb3
Binary files /dev/null and b/docs/notes/pics/ClienteServidorSockets1521731145260.jpg differ
diff --git a/docs/notes/pics/CountdownLatch.png b/docs/notes/pics/CountdownLatch.png
new file mode 100644
index 00000000..1a581bbf
Binary files /dev/null and b/docs/notes/pics/CountdownLatch.png differ
diff --git a/docs/notes/pics/CyclicBarrier.png b/docs/notes/pics/CyclicBarrier.png
new file mode 100644
index 00000000..5fe5b88b
Binary files /dev/null and b/docs/notes/pics/CyclicBarrier.png differ
diff --git a/docs/notes/pics/DP-Decorator-java.io.png b/docs/notes/pics/DP-Decorator-java.io.png
new file mode 100644
index 00000000..897a510b
Binary files /dev/null and b/docs/notes/pics/DP-Decorator-java.io.png differ
diff --git a/docs/notes/pics/GUID_Partition_Table_Scheme.svg.png b/docs/notes/pics/GUID_Partition_Table_Scheme.svg.png
new file mode 100644
index 00000000..6638ae7a
Binary files /dev/null and b/docs/notes/pics/GUID_Partition_Table_Scheme.svg.png differ
diff --git a/docs/notes/pics/HTTP1_x_Connections.png b/docs/notes/pics/HTTP1_x_Connections.png
new file mode 100644
index 00000000..d8c18a3c
Binary files /dev/null and b/docs/notes/pics/HTTP1_x_Connections.png differ
diff --git a/docs/notes/pics/HTTP_RequestMessageExample.png b/docs/notes/pics/HTTP_RequestMessageExample.png
new file mode 100644
index 00000000..8fd213cb
Binary files /dev/null and b/docs/notes/pics/HTTP_RequestMessageExample.png differ
diff --git a/docs/notes/pics/HTTP_ResponseMessageExample.png b/docs/notes/pics/HTTP_ResponseMessageExample.png
new file mode 100644
index 00000000..1adf26c5
Binary files /dev/null and b/docs/notes/pics/HTTP_ResponseMessageExample.png differ
diff --git a/docs/notes/pics/How-HTTPS-Works.png b/docs/notes/pics/How-HTTPS-Works.png
new file mode 100644
index 00000000..c10605f7
Binary files /dev/null and b/docs/notes/pics/How-HTTPS-Works.png differ
diff --git a/docs/notes/pics/HowLinkedListWorks.png b/docs/notes/pics/HowLinkedListWorks.png
new file mode 100644
index 00000000..2640d80d
Binary files /dev/null and b/docs/notes/pics/HowLinkedListWorks.png differ
diff --git a/docs/notes/pics/Iterator-1.jpg b/docs/notes/pics/Iterator-1.jpg
new file mode 100644
index 00000000..f9f818c6
Binary files /dev/null and b/docs/notes/pics/Iterator-1.jpg differ
diff --git a/docs/notes/pics/JNI-Java-Native-Interface.jpg b/docs/notes/pics/JNI-Java-Native-Interface.jpg
new file mode 100644
index 00000000..28b45e2e
Binary files /dev/null and b/docs/notes/pics/JNI-Java-Native-Interface.jpg differ
diff --git a/docs/notes/pics/JNIFigure1.gif b/docs/notes/pics/JNIFigure1.gif
new file mode 100644
index 00000000..f47f289e
Binary files /dev/null and b/docs/notes/pics/JNIFigure1.gif differ
diff --git a/docs/notes/pics/JVM-Stack.png b/docs/notes/pics/JVM-Stack.png
new file mode 100644
index 00000000..e55ccf9b
Binary files /dev/null and b/docs/notes/pics/JVM-Stack.png differ
diff --git a/docs/notes/pics/JVM-runtime-data-area.jpg b/docs/notes/pics/JVM-runtime-data-area.jpg
new file mode 100644
index 00000000..88f8691f
Binary files /dev/null and b/docs/notes/pics/JVM-runtime-data-area.jpg differ
diff --git a/docs/notes/pics/LOun2W9134NxVugmbJPp15d4LalxC4O.png b/docs/notes/pics/LOun2W9134NxVugmbJPp15d4LalxC4O.png
new file mode 100644
index 00000000..188460a5
Binary files /dev/null and b/docs/notes/pics/LOun2W9134NxVugmbJPp15d4LalxC4O.png differ
diff --git a/docs/notes/pics/MultiNode-SessionReplication.jpg b/docs/notes/pics/MultiNode-SessionReplication.jpg
new file mode 100644
index 00000000..0223bd80
Binary files /dev/null and b/docs/notes/pics/MultiNode-SessionReplication.jpg differ
diff --git a/docs/notes/pics/MultiNode-SpringSession.jpg b/docs/notes/pics/MultiNode-SpringSession.jpg
new file mode 100644
index 00000000..38d56e2c
Binary files /dev/null and b/docs/notes/pics/MultiNode-SpringSession.jpg differ
diff --git a/docs/notes/pics/MultiNode-StickySessions.jpg b/docs/notes/pics/MultiNode-StickySessions.jpg
new file mode 100644
index 00000000..a7e1c6aa
Binary files /dev/null and b/docs/notes/pics/MultiNode-StickySessions.jpg differ
diff --git a/docs/notes/pics/NP4z3i8m38Ntd28NQ4_0KCJ2q044Oez.png b/docs/notes/pics/NP4z3i8m38Ntd28NQ4_0KCJ2q044Oez.png
new file mode 100644
index 00000000..3819cda2
Binary files /dev/null and b/docs/notes/pics/NP4z3i8m38Ntd28NQ4_0KCJ2q044Oez.png differ
diff --git a/docs/notes/pics/PPjwP.png b/docs/notes/pics/PPjwP.png
new file mode 100644
index 00000000..80631505
Binary files /dev/null and b/docs/notes/pics/PPjwP.png differ
diff --git a/docs/notes/pics/ProcessState.png b/docs/notes/pics/ProcessState.png
new file mode 100644
index 00000000..39269579
Binary files /dev/null and b/docs/notes/pics/ProcessState.png differ
diff --git a/docs/notes/pics/Semaphore.png b/docs/notes/pics/Semaphore.png
new file mode 100644
index 00000000..6b8c30b1
Binary files /dev/null and b/docs/notes/pics/Semaphore.png differ
diff --git a/docs/notes/pics/SoWkIImgAStDuU8goIp9ILK8IatCoQn.png b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILK8IatCoQn.png
new file mode 100644
index 00000000..da66da14
Binary files /dev/null and b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILK8IatCoQn.png differ
diff --git a/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmB2xEJyv.png b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmB2xEJyv.png
new file mode 100644
index 00000000..e5ae5234
Binary files /dev/null and b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmB2xEJyv.png differ
diff --git a/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmJ4ylIar.png b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmJ4ylIar.png
new file mode 100644
index 00000000..e31398b6
Binary files /dev/null and b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmJ4ylIar.png differ
diff --git a/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmJyrBBKh.png b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmJyrBBKh.png
new file mode 100644
index 00000000..055d995e
Binary files /dev/null and b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmJyrBBKh.png differ
diff --git a/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmpiyjo2_.png b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmpiyjo2_.png
new file mode 100644
index 00000000..37f32c4c
Binary files /dev/null and b/docs/notes/pics/SoWkIImgAStDuU8goIp9ILLmpiyjo2_.png differ
diff --git a/docs/notes/pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png b/docs/notes/pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png
new file mode 100644
index 00000000..124ec977
Binary files /dev/null and b/docs/notes/pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png differ
diff --git a/docs/notes/pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png b/docs/notes/pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png
new file mode 100644
index 00000000..7a202d35
Binary files /dev/null and b/docs/notes/pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png differ
diff --git a/docs/notes/pics/Technology-ComputerNetworking-Internet-ISPs.png b/docs/notes/pics/Technology-ComputerNetworking-Internet-ISPs.png
new file mode 100644
index 00000000..72a30a7b
Binary files /dev/null and b/docs/notes/pics/Technology-ComputerNetworking-Internet-ISPs.png differ
diff --git a/docs/notes/pics/VP4n3i8m34Ntd28NQ4_0KCJ2q044Oez.png b/docs/notes/pics/VP4n3i8m34Ntd28NQ4_0KCJ2q044Oez.png
new file mode 100644
index 00000000..c77f4ff8
Binary files /dev/null and b/docs/notes/pics/VP4n3i8m34Ntd28NQ4_0KCJ2q044Oez.png differ
diff --git a/docs/notes/pics/VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png b/docs/notes/pics/VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png
new file mode 100644
index 00000000..d2559cf3
Binary files /dev/null and b/docs/notes/pics/VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png differ
diff --git a/docs/notes/pics/ZnJvbT1jc2RuJnVybD15VkdkdVYyUXZ.jpg b/docs/notes/pics/ZnJvbT1jc2RuJnVybD15VkdkdVYyUXZ.jpg
new file mode 100644
index 00000000..3027986e
Binary files /dev/null and b/docs/notes/pics/ZnJvbT1jc2RuJnVybD15VkdkdVYyUXZ.jpg differ
diff --git a/docs/notes/pics/_u4E0B_u8F7D.png b/docs/notes/pics/_u4E0B_u8F7D.png
new file mode 100644
index 00000000..9da97330
Binary files /dev/null and b/docs/notes/pics/_u4E0B_u8F7D.png differ
diff --git a/docs/notes/pics/a01d1516-8168-461a-a24b-620b9cfc40f4.png b/docs/notes/pics/a01d1516-8168-461a-a24b-620b9cfc40f4.png
new file mode 100644
index 00000000..4b9b4b48
Binary files /dev/null and b/docs/notes/pics/a01d1516-8168-461a-a24b-620b9cfc40f4.png differ
diff --git a/docs/notes/pics/a0df8edc-581b-4977-95c2-d7025795b899.png b/docs/notes/pics/a0df8edc-581b-4977-95c2-d7025795b899.png
new file mode 100644
index 00000000..9103dfa6
Binary files /dev/null and b/docs/notes/pics/a0df8edc-581b-4977-95c2-d7025795b899.png differ
diff --git a/docs/notes/pics/a1198642-9159-4d88-8aec-c3b04e7a2563.jpg b/docs/notes/pics/a1198642-9159-4d88-8aec-c3b04e7a2563.jpg
new file mode 100644
index 00000000..30e92639
Binary files /dev/null and b/docs/notes/pics/a1198642-9159-4d88-8aec-c3b04e7a2563.jpg differ
diff --git a/docs/notes/pics/a2d13178-f1ef-4811-a240-1fe95b55b1eb.png b/docs/notes/pics/a2d13178-f1ef-4811-a240-1fe95b55b1eb.png
new file mode 100644
index 00000000..edc6840a
Binary files /dev/null and b/docs/notes/pics/a2d13178-f1ef-4811-a240-1fe95b55b1eb.png differ
diff --git a/docs/notes/pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png b/docs/notes/pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png
new file mode 100644
index 00000000..1a5a6474
Binary files /dev/null and b/docs/notes/pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png differ
diff --git a/docs/notes/pics/a3253deb-8d21-40a1-aae4-7d178e4aa319.jpg b/docs/notes/pics/a3253deb-8d21-40a1-aae4-7d178e4aa319.jpg
new file mode 100644
index 00000000..23258afa
Binary files /dev/null and b/docs/notes/pics/a3253deb-8d21-40a1-aae4-7d178e4aa319.jpg differ
diff --git a/docs/notes/pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png b/docs/notes/pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png
new file mode 100644
index 00000000..03b37a61
Binary files /dev/null and b/docs/notes/pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png differ
diff --git a/docs/notes/pics/a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg b/docs/notes/pics/a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg
new file mode 100644
index 00000000..7b432fd1
Binary files /dev/null and b/docs/notes/pics/a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg differ
diff --git a/docs/notes/pics/a40661e4-1a71-46d2-a158-ff36f7fc3331.png b/docs/notes/pics/a40661e4-1a71-46d2-a158-ff36f7fc3331.png
new file mode 100644
index 00000000..e980a2e3
Binary files /dev/null and b/docs/notes/pics/a40661e4-1a71-46d2-a158-ff36f7fc3331.png differ
diff --git a/docs/notes/pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg b/docs/notes/pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg
new file mode 100644
index 00000000..a7050bdf
Binary files /dev/null and b/docs/notes/pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg differ
diff --git a/docs/notes/pics/a4b162e5-db2a-4a27-b213-1fe481c5a06a.png b/docs/notes/pics/a4b162e5-db2a-4a27-b213-1fe481c5a06a.png
new file mode 100644
index 00000000..960a4234
Binary files /dev/null and b/docs/notes/pics/a4b162e5-db2a-4a27-b213-1fe481c5a06a.png differ
diff --git a/docs/notes/pics/a4c17d43-fa5e-4935-b74e-147e7f7e782c.png b/docs/notes/pics/a4c17d43-fa5e-4935-b74e-147e7f7e782c.png
new file mode 100644
index 00000000..461fffb0
Binary files /dev/null and b/docs/notes/pics/a4c17d43-fa5e-4935-b74e-147e7f7e782c.png differ
diff --git a/docs/notes/pics/a57a6fc8-c5e9-456c-80ff-a5139dda4b6e.png b/docs/notes/pics/a57a6fc8-c5e9-456c-80ff-a5139dda4b6e.png
new file mode 100644
index 00000000..384e7aa6
Binary files /dev/null and b/docs/notes/pics/a57a6fc8-c5e9-456c-80ff-a5139dda4b6e.png differ
diff --git a/docs/notes/pics/a58e294a-615d-4ea0-9fbf-064a6daec4b2.png b/docs/notes/pics/a58e294a-615d-4ea0-9fbf-064a6daec4b2.png
new file mode 100644
index 00000000..fdefb823
Binary files /dev/null and b/docs/notes/pics/a58e294a-615d-4ea0-9fbf-064a6daec4b2.png differ
diff --git a/docs/notes/pics/a6026bb4-3daf-439f-b1ec-a5a24e19d2fb.jpg b/docs/notes/pics/a6026bb4-3daf-439f-b1ec-a5a24e19d2fb.jpg
new file mode 100644
index 00000000..4ff577e2
Binary files /dev/null and b/docs/notes/pics/a6026bb4-3daf-439f-b1ec-a5a24e19d2fb.jpg differ
diff --git a/docs/notes/pics/a6ac2b08-3861-4e85-baa8-382287bfee9f.png b/docs/notes/pics/a6ac2b08-3861-4e85-baa8-382287bfee9f.png
new file mode 100644
index 00000000..26b0bd03
Binary files /dev/null and b/docs/notes/pics/a6ac2b08-3861-4e85-baa8-382287bfee9f.png differ
diff --git a/docs/notes/pics/a6c20f60-5eba-427d-9413-352ada4b40fe.png b/docs/notes/pics/a6c20f60-5eba-427d-9413-352ada4b40fe.png
new file mode 100644
index 00000000..11d36653
Binary files /dev/null and b/docs/notes/pics/a6c20f60-5eba-427d-9413-352ada4b40fe.png differ
diff --git a/docs/notes/pics/a74b70ac-323a-4b31-b4d5-90569b8a944b.png b/docs/notes/pics/a74b70ac-323a-4b31-b4d5-90569b8a944b.png
new file mode 100644
index 00000000..3d686121
Binary files /dev/null and b/docs/notes/pics/a74b70ac-323a-4b31-b4d5-90569b8a944b.png differ
diff --git a/docs/notes/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg b/docs/notes/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg
new file mode 100644
index 00000000..67b2264d
Binary files /dev/null and b/docs/notes/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg differ
diff --git a/docs/notes/pics/aa29cc88-7256-4399-8c7f-3cf4a6489559.png b/docs/notes/pics/aa29cc88-7256-4399-8c7f-3cf4a6489559.png
new file mode 100644
index 00000000..9b93237e
Binary files /dev/null and b/docs/notes/pics/aa29cc88-7256-4399-8c7f-3cf4a6489559.png differ
diff --git a/docs/notes/pics/aa42f9c6-ad7a-48f4-8e8b-f3b6de3feaec.png b/docs/notes/pics/aa42f9c6-ad7a-48f4-8e8b-f3b6de3feaec.png
new file mode 100644
index 00000000..cdb78c11
Binary files /dev/null and b/docs/notes/pics/aa42f9c6-ad7a-48f4-8e8b-f3b6de3feaec.png differ
diff --git a/docs/notes/pics/aa844ff0-cd16-4478-b415-da071b615a17.jpg b/docs/notes/pics/aa844ff0-cd16-4478-b415-da071b615a17.jpg
new file mode 100644
index 00000000..e69fff5a
Binary files /dev/null and b/docs/notes/pics/aa844ff0-cd16-4478-b415-da071b615a17.jpg differ
diff --git a/docs/notes/pics/ab77240d-7338-4547-9183-00215e7220ec.png b/docs/notes/pics/ab77240d-7338-4547-9183-00215e7220ec.png
new file mode 100644
index 00000000..d57d91ce
Binary files /dev/null and b/docs/notes/pics/ab77240d-7338-4547-9183-00215e7220ec.png differ
diff --git a/docs/notes/pics/abb3e0d1-c1bd-45d0-8190-73c74a9f6679.png b/docs/notes/pics/abb3e0d1-c1bd-45d0-8190-73c74a9f6679.png
new file mode 100644
index 00000000..6a6bf78f
Binary files /dev/null and b/docs/notes/pics/abb3e0d1-c1bd-45d0-8190-73c74a9f6679.png differ
diff --git a/docs/notes/pics/ac106e7e-489a-4082-abd9-dabebe48394c.jpg b/docs/notes/pics/ac106e7e-489a-4082-abd9-dabebe48394c.jpg
new file mode 100644
index 00000000..0d323411
Binary files /dev/null and b/docs/notes/pics/ac106e7e-489a-4082-abd9-dabebe48394c.jpg differ
diff --git a/docs/notes/pics/ac9b31ec-cef1-4880-a875-fc4571ca10e1.png b/docs/notes/pics/ac9b31ec-cef1-4880-a875-fc4571ca10e1.png
new file mode 100644
index 00000000..3d6bd025
Binary files /dev/null and b/docs/notes/pics/ac9b31ec-cef1-4880-a875-fc4571ca10e1.png differ
diff --git a/docs/notes/pics/ace830df-9919-48ca-91b5-60b193f593d2.png b/docs/notes/pics/ace830df-9919-48ca-91b5-60b193f593d2.png
new file mode 100644
index 00000000..79efa287
Binary files /dev/null and b/docs/notes/pics/ace830df-9919-48ca-91b5-60b193f593d2.png differ
diff --git a/docs/notes/pics/ae1b27b8-bc13-42e7-ac12-a2242e125499.png b/docs/notes/pics/ae1b27b8-bc13-42e7-ac12-a2242e125499.png
new file mode 100644
index 00000000..27977740
Binary files /dev/null and b/docs/notes/pics/ae1b27b8-bc13-42e7-ac12-a2242e125499.png differ
diff --git a/docs/notes/pics/ae3fc93a-44d5-4beb-b05a-874bd9c0a657.png b/docs/notes/pics/ae3fc93a-44d5-4beb-b05a-874bd9c0a657.png
new file mode 100644
index 00000000..ea23c7db
Binary files /dev/null and b/docs/notes/pics/ae3fc93a-44d5-4beb-b05a-874bd9c0a657.png differ
diff --git a/docs/notes/pics/af198da1-2480-4043-b07f-a3b91a88b815.png b/docs/notes/pics/af198da1-2480-4043-b07f-a3b91a88b815.png
new file mode 100644
index 00000000..34d7a286
Binary files /dev/null and b/docs/notes/pics/af198da1-2480-4043-b07f-a3b91a88b815.png differ
diff --git a/docs/notes/pics/af4639f9-af54-4400-aaf5-4e261d96ace7.png b/docs/notes/pics/af4639f9-af54-4400-aaf5-4e261d96ace7.png
new file mode 100644
index 00000000..8de4fa4d
Binary files /dev/null and b/docs/notes/pics/af4639f9-af54-4400-aaf5-4e261d96ace7.png differ
diff --git a/docs/notes/pics/b0c97118-8f30-4619-9c22-a141f627db39.png b/docs/notes/pics/b0c97118-8f30-4619-9c22-a141f627db39.png
new file mode 100644
index 00000000..e3cf245b
Binary files /dev/null and b/docs/notes/pics/b0c97118-8f30-4619-9c22-a141f627db39.png differ
diff --git a/docs/notes/pics/b0e8ef47-2f23-4379-8c64-10d5cb44d438.jpg b/docs/notes/pics/b0e8ef47-2f23-4379-8c64-10d5cb44d438.jpg
new file mode 100644
index 00000000..cb17fdcb
Binary files /dev/null and b/docs/notes/pics/b0e8ef47-2f23-4379-8c64-10d5cb44d438.jpg differ
diff --git a/docs/notes/pics/b0f61ac2-a4b6-4042-9cf0-ccf4238c1ff7.png b/docs/notes/pics/b0f61ac2-a4b6-4042-9cf0-ccf4238c1ff7.png
new file mode 100644
index 00000000..73dad483
Binary files /dev/null and b/docs/notes/pics/b0f61ac2-a4b6-4042-9cf0-ccf4238c1ff7.png differ
diff --git a/docs/notes/pics/b1df9732-86ce-4d69-9f06-fba1db7b3b5a.jpg b/docs/notes/pics/b1df9732-86ce-4d69-9f06-fba1db7b3b5a.jpg
new file mode 100644
index 00000000..a71d167e
Binary files /dev/null and b/docs/notes/pics/b1df9732-86ce-4d69-9f06-fba1db7b3b5a.jpg differ
diff --git a/docs/notes/pics/b1fa0453-a4b0-4eae-a352-48acca8fff74.png b/docs/notes/pics/b1fa0453-a4b0-4eae-a352-48acca8fff74.png
new file mode 100644
index 00000000..842b2f6c
Binary files /dev/null and b/docs/notes/pics/b1fa0453-a4b0-4eae-a352-48acca8fff74.png differ
diff --git a/docs/notes/pics/b20a3466-44b4-445e-87c7-dd4fb9ef44b2.png b/docs/notes/pics/b20a3466-44b4-445e-87c7-dd4fb9ef44b2.png
new file mode 100644
index 00000000..3d5adabd
Binary files /dev/null and b/docs/notes/pics/b20a3466-44b4-445e-87c7-dd4fb9ef44b2.png differ
diff --git a/docs/notes/pics/b29f8971-9cb8-480d-b986-0e60c2ece069.png b/docs/notes/pics/b29f8971-9cb8-480d-b986-0e60c2ece069.png
new file mode 100644
index 00000000..65f73b0e
Binary files /dev/null and b/docs/notes/pics/b29f8971-9cb8-480d-b986-0e60c2ece069.png differ
diff --git a/docs/notes/pics/b396d726-b75f-4a32-89a2-03a7b6e19f6f.jpg b/docs/notes/pics/b396d726-b75f-4a32-89a2-03a7b6e19f6f.jpg
new file mode 100644
index 00000000..a3e1a656
Binary files /dev/null and b/docs/notes/pics/b396d726-b75f-4a32-89a2-03a7b6e19f6f.jpg differ
diff --git a/docs/notes/pics/b418ca51-f005-4510-b7ad-f092eb6aeb24.png b/docs/notes/pics/b418ca51-f005-4510-b7ad-f092eb6aeb24.png
new file mode 100644
index 00000000..07157513
Binary files /dev/null and b/docs/notes/pics/b418ca51-f005-4510-b7ad-f092eb6aeb24.png differ
diff --git a/docs/notes/pics/b4252c85-6fb0-4995-9a68-a1a5925fbdb1.png b/docs/notes/pics/b4252c85-6fb0-4995-9a68-a1a5925fbdb1.png
new file mode 100644
index 00000000..59ea02cc
Binary files /dev/null and b/docs/notes/pics/b4252c85-6fb0-4995-9a68-a1a5925fbdb1.png differ
diff --git a/docs/notes/pics/b4b29aa9-dd2c-467b-b75f-ca6541cb25b5.jpg b/docs/notes/pics/b4b29aa9-dd2c-467b-b75f-ca6541cb25b5.jpg
new file mode 100644
index 00000000..15f6fce8
Binary files /dev/null and b/docs/notes/pics/b4b29aa9-dd2c-467b-b75f-ca6541cb25b5.jpg differ
diff --git a/docs/notes/pics/b54eeb16-0b0e-484c-be62-306f57c40d77.jpg b/docs/notes/pics/b54eeb16-0b0e-484c-be62-306f57c40d77.jpg
new file mode 100644
index 00000000..692a0357
Binary files /dev/null and b/docs/notes/pics/b54eeb16-0b0e-484c-be62-306f57c40d77.jpg differ
diff --git a/docs/notes/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png b/docs/notes/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png
new file mode 100644
index 00000000..dd32da70
Binary files /dev/null and b/docs/notes/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png differ
diff --git a/docs/notes/pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg b/docs/notes/pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg
new file mode 100644
index 00000000..58fb0a05
Binary files /dev/null and b/docs/notes/pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg differ
diff --git a/docs/notes/pics/b84ba6fb-312b-4e69-8c77-fb6eb6fb38d4.png b/docs/notes/pics/b84ba6fb-312b-4e69-8c77-fb6eb6fb38d4.png
new file mode 100644
index 00000000..dc44da3d
Binary files /dev/null and b/docs/notes/pics/b84ba6fb-312b-4e69-8c77-fb6eb6fb38d4.png differ
diff --git a/docs/notes/pics/b8dd708d-f372-4b04-b828-1dd99021c244.png b/docs/notes/pics/b8dd708d-f372-4b04-b828-1dd99021c244.png
new file mode 100644
index 00000000..c74e816e
Binary files /dev/null and b/docs/notes/pics/b8dd708d-f372-4b04-b828-1dd99021c244.png differ
diff --git a/docs/notes/pics/b988877c-0f0a-4593-916d-de2081320628.jpg b/docs/notes/pics/b988877c-0f0a-4593-916d-de2081320628.jpg
new file mode 100644
index 00000000..67339134
Binary files /dev/null and b/docs/notes/pics/b988877c-0f0a-4593-916d-de2081320628.jpg differ
diff --git a/docs/notes/pics/b9a39d2a-618c-468b-86db-2e851f1a0057.jpg b/docs/notes/pics/b9a39d2a-618c-468b-86db-2e851f1a0057.jpg
new file mode 100644
index 00000000..05c7e6ce
Binary files /dev/null and b/docs/notes/pics/b9a39d2a-618c-468b-86db-2e851f1a0057.jpg differ
diff --git a/docs/notes/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg b/docs/notes/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg
new file mode 100644
index 00000000..b7502831
Binary files /dev/null and b/docs/notes/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg differ
diff --git a/docs/notes/pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png b/docs/notes/pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png
new file mode 100644
index 00000000..6664d398
Binary files /dev/null and b/docs/notes/pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png differ
diff --git a/docs/notes/pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png b/docs/notes/pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png
new file mode 100644
index 00000000..07d8692d
Binary files /dev/null and b/docs/notes/pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png differ
diff --git a/docs/notes/pics/bc603930-d74d-4499-a3e7-2d740fc07f33.png b/docs/notes/pics/bc603930-d74d-4499-a3e7-2d740fc07f33.png
new file mode 100644
index 00000000..6c9a572e
Binary files /dev/null and b/docs/notes/pics/bc603930-d74d-4499-a3e7-2d740fc07f33.png differ
diff --git a/docs/notes/pics/bc775758-89ab-4805-9f9c-78b8739cf780.jpg b/docs/notes/pics/bc775758-89ab-4805-9f9c-78b8739cf780.jpg
new file mode 100644
index 00000000..4cd6f60f
Binary files /dev/null and b/docs/notes/pics/bc775758-89ab-4805-9f9c-78b8739cf780.jpg differ
diff --git a/docs/notes/pics/be5c2c61-86d2-4dba-a289-b48ea23219de.jpg b/docs/notes/pics/be5c2c61-86d2-4dba-a289-b48ea23219de.jpg
new file mode 100644
index 00000000..a2965a7d
Binary files /dev/null and b/docs/notes/pics/be5c2c61-86d2-4dba-a289-b48ea23219de.jpg differ
diff --git a/docs/notes/pics/be7dca03-12ec-456b-8b54-b1b3161f5531.png b/docs/notes/pics/be7dca03-12ec-456b-8b54-b1b3161f5531.png
new file mode 100644
index 00000000..2c2214de
Binary files /dev/null and b/docs/notes/pics/be7dca03-12ec-456b-8b54-b1b3161f5531.png differ
diff --git a/docs/notes/pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png b/docs/notes/pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png
new file mode 100644
index 00000000..b24241d1
Binary files /dev/null and b/docs/notes/pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png differ
diff --git a/docs/notes/pics/bee1ff1d-c80f-4b3c-b58c-7073a8896ab2.jpg b/docs/notes/pics/bee1ff1d-c80f-4b3c-b58c-7073a8896ab2.jpg
new file mode 100644
index 00000000..e4becc19
Binary files /dev/null and b/docs/notes/pics/bee1ff1d-c80f-4b3c-b58c-7073a8896ab2.jpg differ
diff --git a/docs/notes/pics/bf0ff9fc-467e-4a3f-8922-115ba2c55bde.png b/docs/notes/pics/bf0ff9fc-467e-4a3f-8922-115ba2c55bde.png
new file mode 100644
index 00000000..69222ad8
Binary files /dev/null and b/docs/notes/pics/bf0ff9fc-467e-4a3f-8922-115ba2c55bde.png differ
diff --git a/docs/notes/pics/bf16c541-0717-473b-b75d-4115864f4fbf.jpg b/docs/notes/pics/bf16c541-0717-473b-b75d-4115864f4fbf.jpg
new file mode 100644
index 00000000..a83ba275
Binary files /dev/null and b/docs/notes/pics/bf16c541-0717-473b-b75d-4115864f4fbf.jpg differ
diff --git a/docs/notes/pics/bf667594-bb4b-4634-bf9b-0596a45415ba.jpg b/docs/notes/pics/bf667594-bb4b-4634-bf9b-0596a45415ba.jpg
new file mode 100644
index 00000000..30956ccf
Binary files /dev/null and b/docs/notes/pics/bf667594-bb4b-4634-bf9b-0596a45415ba.jpg differ
diff --git a/docs/notes/pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png b/docs/notes/pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png
new file mode 100644
index 00000000..b9d9dba2
Binary files /dev/null and b/docs/notes/pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png differ
diff --git a/docs/notes/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png b/docs/notes/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png
new file mode 100644
index 00000000..9e2feb27
Binary files /dev/null and b/docs/notes/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png differ
diff --git a/docs/notes/pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png b/docs/notes/pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png
new file mode 100644
index 00000000..add3c5d4
Binary files /dev/null and b/docs/notes/pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png differ
diff --git a/docs/notes/pics/c2117f61-1177-4768-bf33-cf4f950d911c.png b/docs/notes/pics/c2117f61-1177-4768-bf33-cf4f950d911c.png
new file mode 100644
index 00000000..8c74b619
Binary files /dev/null and b/docs/notes/pics/c2117f61-1177-4768-bf33-cf4f950d911c.png differ
diff --git a/docs/notes/pics/c23957e9-a572-44f8-be15-f306c8b92722.jpg b/docs/notes/pics/c23957e9-a572-44f8-be15-f306c8b92722.jpg
new file mode 100644
index 00000000..2732c6d7
Binary files /dev/null and b/docs/notes/pics/c23957e9-a572-44f8-be15-f306c8b92722.jpg differ
diff --git a/docs/notes/pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg b/docs/notes/pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg
new file mode 100644
index 00000000..593513fe
Binary files /dev/null and b/docs/notes/pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg differ
diff --git a/docs/notes/pics/c2cbf5d2-82af-4c78-bd43-495da5adf55f.png b/docs/notes/pics/c2cbf5d2-82af-4c78-bd43-495da5adf55f.png
new file mode 100644
index 00000000..70ecc3ec
Binary files /dev/null and b/docs/notes/pics/c2cbf5d2-82af-4c78-bd43-495da5adf55f.png differ
diff --git a/docs/notes/pics/c2d343f7-604c-4856-9a3c-c71d6f67fecc.png b/docs/notes/pics/c2d343f7-604c-4856-9a3c-c71d6f67fecc.png
new file mode 100644
index 00000000..84b2898b
Binary files /dev/null and b/docs/notes/pics/c2d343f7-604c-4856-9a3c-c71d6f67fecc.png differ
diff --git a/docs/notes/pics/c2f0c8e2-da66-498c-a38f-e1176abee29e.png b/docs/notes/pics/c2f0c8e2-da66-498c-a38f-e1176abee29e.png
new file mode 100644
index 00000000..781c0eff
Binary files /dev/null and b/docs/notes/pics/c2f0c8e2-da66-498c-a38f-e1176abee29e.png differ
diff --git a/docs/notes/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg b/docs/notes/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg
new file mode 100644
index 00000000..17a2e9bf
Binary files /dev/null and b/docs/notes/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg differ
diff --git a/docs/notes/pics/c3c1c0e8-3a78-4426-961f-b46dd0879dd8.png b/docs/notes/pics/c3c1c0e8-3a78-4426-961f-b46dd0879dd8.png
new file mode 100644
index 00000000..48e980fc
Binary files /dev/null and b/docs/notes/pics/c3c1c0e8-3a78-4426-961f-b46dd0879dd8.png differ
diff --git a/docs/notes/pics/c4c14368-519c-4a0e-8331-0a553715e3e7.jpg b/docs/notes/pics/c4c14368-519c-4a0e-8331-0a553715e3e7.jpg
new file mode 100644
index 00000000..0cb4f0a0
Binary files /dev/null and b/docs/notes/pics/c4c14368-519c-4a0e-8331-0a553715e3e7.jpg differ
diff --git a/docs/notes/pics/c5022dd3-be22-4250-b9f6-38ae984a04d7.jpg b/docs/notes/pics/c5022dd3-be22-4250-b9f6-38ae984a04d7.jpg
new file mode 100644
index 00000000..3eb79406
Binary files /dev/null and b/docs/notes/pics/c5022dd3-be22-4250-b9f6-38ae984a04d7.jpg differ
diff --git a/docs/notes/pics/c5085437-54df-4304-b62d-44b961711ba7.png b/docs/notes/pics/c5085437-54df-4304-b62d-44b961711ba7.png
new file mode 100644
index 00000000..36c948aa
Binary files /dev/null and b/docs/notes/pics/c5085437-54df-4304-b62d-44b961711ba7.png differ
diff --git a/docs/notes/pics/c5f611f0-fd5c-4158-9003-278141136e6e.jpg b/docs/notes/pics/c5f611f0-fd5c-4158-9003-278141136e6e.jpg
new file mode 100644
index 00000000..473091be
Binary files /dev/null and b/docs/notes/pics/c5f611f0-fd5c-4158-9003-278141136e6e.jpg differ
diff --git a/docs/notes/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg b/docs/notes/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg
new file mode 100644
index 00000000..5e392d41
Binary files /dev/null and b/docs/notes/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg differ
diff --git a/docs/notes/pics/c79da808-0f28-4a36-bc04-33ccc5b83c13.png b/docs/notes/pics/c79da808-0f28-4a36-bc04-33ccc5b83c13.png
new file mode 100644
index 00000000..91e2c144
Binary files /dev/null and b/docs/notes/pics/c79da808-0f28-4a36-bc04-33ccc5b83c13.png differ
diff --git a/docs/notes/pics/c7d4956c-9988-4a10-a704-28fdae7f3d28.png b/docs/notes/pics/c7d4956c-9988-4a10-a704-28fdae7f3d28.png
new file mode 100644
index 00000000..56510359
Binary files /dev/null and b/docs/notes/pics/c7d4956c-9988-4a10-a704-28fdae7f3d28.png differ
diff --git a/docs/notes/pics/c812c28a-1513-4a82-bfda-ab6a40981aa0.png b/docs/notes/pics/c812c28a-1513-4a82-bfda-ab6a40981aa0.png
new file mode 100644
index 00000000..b1142bff
Binary files /dev/null and b/docs/notes/pics/c812c28a-1513-4a82-bfda-ab6a40981aa0.png differ
diff --git a/docs/notes/pics/c81af7d8-3128-4a3c-a9c9-3e0f5b87ab22.jpg b/docs/notes/pics/c81af7d8-3128-4a3c-a9c9-3e0f5b87ab22.jpg
new file mode 100644
index 00000000..c967b300
Binary files /dev/null and b/docs/notes/pics/c81af7d8-3128-4a3c-a9c9-3e0f5b87ab22.jpg differ
diff --git a/docs/notes/pics/c8d18ca9-0b09-441a-9a0c-fb063630d708.png b/docs/notes/pics/c8d18ca9-0b09-441a-9a0c-fb063630d708.png
new file mode 100644
index 00000000..514ab054
Binary files /dev/null and b/docs/notes/pics/c8d18ca9-0b09-441a-9a0c-fb063630d708.png differ
diff --git a/docs/notes/pics/c8dbff58-d981-48be-8c1c-caa6c2738791.jpg b/docs/notes/pics/c8dbff58-d981-48be-8c1c-caa6c2738791.jpg
new file mode 100644
index 00000000..1414ae0a
Binary files /dev/null and b/docs/notes/pics/c8dbff58-d981-48be-8c1c-caa6c2738791.jpg differ
diff --git a/docs/notes/pics/c9a1de44-b1c0-4d13-a654-827d4ef8a723.png b/docs/notes/pics/c9a1de44-b1c0-4d13-a654-827d4ef8a723.png
new file mode 100644
index 00000000..f9ad721b
Binary files /dev/null and b/docs/notes/pics/c9a1de44-b1c0-4d13-a654-827d4ef8a723.png differ
diff --git a/docs/notes/pics/c9ad2bf4-5580-4018-bce4-1b9a71804d9c.png b/docs/notes/pics/c9ad2bf4-5580-4018-bce4-1b9a71804d9c.png
new file mode 100644
index 00000000..fea5821b
Binary files /dev/null and b/docs/notes/pics/c9ad2bf4-5580-4018-bce4-1b9a71804d9c.png differ
diff --git a/docs/notes/pics/c9cfcd20-c901-435f-9a07-3e46830c359f.jpg b/docs/notes/pics/c9cfcd20-c901-435f-9a07-3e46830c359f.jpg
new file mode 100644
index 00000000..813b5142
Binary files /dev/null and b/docs/notes/pics/c9cfcd20-c901-435f-9a07-3e46830c359f.jpg differ
diff --git a/docs/notes/pics/c9cfd600-bc91-4f3a-9f99-b42f88a5bb24.jpg b/docs/notes/pics/c9cfd600-bc91-4f3a-9f99-b42f88a5bb24.jpg
new file mode 100644
index 00000000..fa7ce3ae
Binary files /dev/null and b/docs/notes/pics/c9cfd600-bc91-4f3a-9f99-b42f88a5bb24.jpg differ
diff --git a/docs/notes/pics/cb0ed469-27ab-471b-a830-648b279103c8.png b/docs/notes/pics/cb0ed469-27ab-471b-a830-648b279103c8.png
new file mode 100644
index 00000000..88c2ce86
Binary files /dev/null and b/docs/notes/pics/cb0ed469-27ab-471b-a830-648b279103c8.png differ
diff --git a/docs/notes/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png b/docs/notes/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png
new file mode 100644
index 00000000..27f2b742
Binary files /dev/null and b/docs/notes/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png differ
diff --git a/docs/notes/pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png b/docs/notes/pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png
new file mode 100644
index 00000000..f8550a11
Binary files /dev/null and b/docs/notes/pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png differ
diff --git a/docs/notes/pics/cdbe1d12-5ad9-4acb-a717-bbc822c2acf3.png b/docs/notes/pics/cdbe1d12-5ad9-4acb-a717-bbc822c2acf3.png
new file mode 100644
index 00000000..63792c74
Binary files /dev/null and b/docs/notes/pics/cdbe1d12-5ad9-4acb-a717-bbc822c2acf3.png differ
diff --git a/docs/notes/pics/ce039f03-6588-4f0c-b35b-a494de0eac47.png b/docs/notes/pics/ce039f03-6588-4f0c-b35b-a494de0eac47.png
new file mode 100644
index 00000000..d5025bb3
Binary files /dev/null and b/docs/notes/pics/ce039f03-6588-4f0c-b35b-a494de0eac47.png differ
diff --git a/docs/notes/pics/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png b/docs/notes/pics/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png
new file mode 100644
index 00000000..9b9f3838
Binary files /dev/null and b/docs/notes/pics/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png differ
diff --git a/docs/notes/pics/class_loader_hierarchy.png b/docs/notes/pics/class_loader_hierarchy.png
new file mode 100644
index 00000000..6f4baf6f
Binary files /dev/null and b/docs/notes/pics/class_loader_hierarchy.png differ
diff --git a/docs/notes/pics/cookiedata.png b/docs/notes/pics/cookiedata.png
new file mode 100644
index 00000000..a425fca6
Binary files /dev/null and b/docs/notes/pics/cookiedata.png differ
diff --git a/docs/notes/pics/d0afdd23-c9a5-4d1c-9b3d-404bff3bd0d1.png b/docs/notes/pics/d0afdd23-c9a5-4d1c-9b3d-404bff3bd0d1.png
new file mode 100644
index 00000000..58ff84fe
Binary files /dev/null and b/docs/notes/pics/d0afdd23-c9a5-4d1c-9b3d-404bff3bd0d1.png differ
diff --git a/docs/notes/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png b/docs/notes/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png
new file mode 100644
index 00000000..cc971351
Binary files /dev/null and b/docs/notes/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png differ
diff --git a/docs/notes/pics/d1f81ac3-9fdb-4371-a49d-ca84917aa89f.jpg b/docs/notes/pics/d1f81ac3-9fdb-4371-a49d-ca84917aa89f.jpg
new file mode 100644
index 00000000..90953621
Binary files /dev/null and b/docs/notes/pics/d1f81ac3-9fdb-4371-a49d-ca84917aa89f.jpg differ
diff --git a/docs/notes/pics/d2d34239-e7c1-482b-b33e-3170c5943556.jpg b/docs/notes/pics/d2d34239-e7c1-482b-b33e-3170c5943556.jpg
new file mode 100644
index 00000000..22f5062a
Binary files /dev/null and b/docs/notes/pics/d2d34239-e7c1-482b-b33e-3170c5943556.jpg differ
diff --git a/docs/notes/pics/d49466db-fdd3-4d36-8a86-47dc45c07a1e.jpg b/docs/notes/pics/d49466db-fdd3-4d36-8a86-47dc45c07a1e.jpg
new file mode 100644
index 00000000..c4c7a915
Binary files /dev/null and b/docs/notes/pics/d49466db-fdd3-4d36-8a86-47dc45c07a1e.jpg differ
diff --git a/docs/notes/pics/d4c3a4a1-0846-46ec-9cc3-eaddfca71254.jpg b/docs/notes/pics/d4c3a4a1-0846-46ec-9cc3-eaddfca71254.jpg
new file mode 100644
index 00000000..bbc7f102
Binary files /dev/null and b/docs/notes/pics/d4c3a4a1-0846-46ec-9cc3-eaddfca71254.jpg differ
diff --git a/docs/notes/pics/d4eef1e2-5703-4ca4-82ab-8dda93d6b81f.png b/docs/notes/pics/d4eef1e2-5703-4ca4-82ab-8dda93d6b81f.png
new file mode 100644
index 00000000..4f62e6f5
Binary files /dev/null and b/docs/notes/pics/d4eef1e2-5703-4ca4-82ab-8dda93d6b81f.png differ
diff --git a/docs/notes/pics/d52270b4-9097-4667-9f18-f405fc661c99.png b/docs/notes/pics/d52270b4-9097-4667-9f18-f405fc661c99.png
new file mode 100644
index 00000000..347fe316
Binary files /dev/null and b/docs/notes/pics/d52270b4-9097-4667-9f18-f405fc661c99.png differ
diff --git a/docs/notes/pics/d5c16be7-a1c0-4c8d-b6b9-5999cdc6f9b3.png b/docs/notes/pics/d5c16be7-a1c0-4c8d-b6b9-5999cdc6f9b3.png
new file mode 100644
index 00000000..df5be529
Binary files /dev/null and b/docs/notes/pics/d5c16be7-a1c0-4c8d-b6b9-5999cdc6f9b3.png differ
diff --git a/docs/notes/pics/d7f6dec1-02b6-4969-b3ab-e01ee78659b9.png b/docs/notes/pics/d7f6dec1-02b6-4969-b3ab-e01ee78659b9.png
new file mode 100644
index 00000000..2fa7a4e4
Binary files /dev/null and b/docs/notes/pics/d7f6dec1-02b6-4969-b3ab-e01ee78659b9.png differ
diff --git a/docs/notes/pics/d99dc9e2-197c-4085-813d-7195da1c6762.png b/docs/notes/pics/d99dc9e2-197c-4085-813d-7195da1c6762.png
new file mode 100644
index 00000000..a2c04eba
Binary files /dev/null and b/docs/notes/pics/d99dc9e2-197c-4085-813d-7195da1c6762.png differ
diff --git a/docs/notes/pics/db4921d4-184b-48ba-a3cf-1d1141e3ba2d.png b/docs/notes/pics/db4921d4-184b-48ba-a3cf-1d1141e3ba2d.png
new file mode 100644
index 00000000..f88f3b54
Binary files /dev/null and b/docs/notes/pics/db4921d4-184b-48ba-a3cf-1d1141e3ba2d.png differ
diff --git a/docs/notes/pics/db54db2f-82b2-4222-8d63-e49a8a7fc966.png b/docs/notes/pics/db54db2f-82b2-4222-8d63-e49a8a7fc966.png
new file mode 100644
index 00000000..23fb9449
Binary files /dev/null and b/docs/notes/pics/db54db2f-82b2-4222-8d63-e49a8a7fc966.png differ
diff --git a/docs/notes/pics/dbb8516d-37ba-4e2c-b26b-eefd7de21b45.png b/docs/notes/pics/dbb8516d-37ba-4e2c-b26b-eefd7de21b45.png
new file mode 100644
index 00000000..1ee66db8
Binary files /dev/null and b/docs/notes/pics/dbb8516d-37ba-4e2c-b26b-eefd7de21b45.png differ
diff --git a/docs/notes/pics/dbc5c9f1-c13c-4d06-86ba-7cc949eb4c8f.jpg b/docs/notes/pics/dbc5c9f1-c13c-4d06-86ba-7cc949eb4c8f.jpg
new file mode 100644
index 00000000..6ff8388d
Binary files /dev/null and b/docs/notes/pics/dbc5c9f1-c13c-4d06-86ba-7cc949eb4c8f.jpg differ
diff --git a/docs/notes/pics/dbd60b1f-b700-4da6-a993-62578e892333.jpg b/docs/notes/pics/dbd60b1f-b700-4da6-a993-62578e892333.jpg
new file mode 100644
index 00000000..aa076b2a
Binary files /dev/null and b/docs/notes/pics/dbd60b1f-b700-4da6-a993-62578e892333.jpg differ
diff --git a/docs/notes/pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg b/docs/notes/pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg
new file mode 100644
index 00000000..8090706b
Binary files /dev/null and b/docs/notes/pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg differ
diff --git a/docs/notes/pics/dd15a984-e977-4644-b127-708cddb8ca99.png b/docs/notes/pics/dd15a984-e977-4644-b127-708cddb8ca99.png
new file mode 100644
index 00000000..4397e88e
Binary files /dev/null and b/docs/notes/pics/dd15a984-e977-4644-b127-708cddb8ca99.png differ
diff --git a/docs/notes/pics/dd3b289c-d90e-44a6-a44c-4880517eb1de.png b/docs/notes/pics/dd3b289c-d90e-44a6-a44c-4880517eb1de.png
new file mode 100644
index 00000000..51055a2b
Binary files /dev/null and b/docs/notes/pics/dd3b289c-d90e-44a6-a44c-4880517eb1de.png differ
diff --git a/docs/notes/pics/dd782132-d830-4c55-9884-cfac0a541b8e.png b/docs/notes/pics/dd782132-d830-4c55-9884-cfac0a541b8e.png
new file mode 100644
index 00000000..e338c1bb
Binary files /dev/null and b/docs/notes/pics/dd782132-d830-4c55-9884-cfac0a541b8e.png differ
diff --git a/docs/notes/pics/dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg b/docs/notes/pics/dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg
new file mode 100644
index 00000000..69f4dd05
Binary files /dev/null and b/docs/notes/pics/dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg differ
diff --git a/docs/notes/pics/dda1608d-26e0-4f10-8327-a459969b150a.png b/docs/notes/pics/dda1608d-26e0-4f10-8327-a459969b150a.png
new file mode 100644
index 00000000..7bab8f15
Binary files /dev/null and b/docs/notes/pics/dda1608d-26e0-4f10-8327-a459969b150a.png differ
diff --git a/docs/notes/pics/ddb5ff4c-4ada-46aa-9bf1-140bdb5e4676.jpg b/docs/notes/pics/ddb5ff4c-4ada-46aa-9bf1-140bdb5e4676.jpg
new file mode 100644
index 00000000..73b3d739
Binary files /dev/null and b/docs/notes/pics/ddb5ff4c-4ada-46aa-9bf1-140bdb5e4676.jpg differ
diff --git a/docs/notes/pics/ddcf2327-8d84-425d-8535-121a94bcb88d.jpg b/docs/notes/pics/ddcf2327-8d84-425d-8535-121a94bcb88d.jpg
new file mode 100644
index 00000000..2a95d92d
Binary files /dev/null and b/docs/notes/pics/ddcf2327-8d84-425d-8535-121a94bcb88d.jpg differ
diff --git a/docs/notes/pics/de9b9ea0-1327-4865-93e5-6f805c48bc9e.png b/docs/notes/pics/de9b9ea0-1327-4865-93e5-6f805c48bc9e.png
new file mode 100644
index 00000000..cfabd4d7
Binary files /dev/null and b/docs/notes/pics/de9b9ea0-1327-4865-93e5-6f805c48bc9e.png differ
diff --git a/docs/notes/pics/docker-filesystems-busyboxrw.png b/docs/notes/pics/docker-filesystems-busyboxrw.png
new file mode 100644
index 00000000..c12710af
Binary files /dev/null and b/docs/notes/pics/docker-filesystems-busyboxrw.png differ
diff --git a/docs/notes/pics/e026c24d-00fa-4e7c-97a8-95a98cdc383a.png b/docs/notes/pics/e026c24d-00fa-4e7c-97a8-95a98cdc383a.png
new file mode 100644
index 00000000..427cfbf8
Binary files /dev/null and b/docs/notes/pics/e026c24d-00fa-4e7c-97a8-95a98cdc383a.png differ
diff --git a/docs/notes/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png b/docs/notes/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png
new file mode 100644
index 00000000..b4c565fb
Binary files /dev/null and b/docs/notes/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png differ
diff --git a/docs/notes/pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg b/docs/notes/pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg
new file mode 100644
index 00000000..0968e1bc
Binary files /dev/null and b/docs/notes/pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg differ
diff --git a/docs/notes/pics/e143f6da-d114-4ba4-8712-f65299047fa2.png b/docs/notes/pics/e143f6da-d114-4ba4-8712-f65299047fa2.png
new file mode 100644
index 00000000..38cbf667
Binary files /dev/null and b/docs/notes/pics/e143f6da-d114-4ba4-8712-f65299047fa2.png differ
diff --git a/docs/notes/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png b/docs/notes/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png
new file mode 100644
index 00000000..bffe7520
Binary files /dev/null and b/docs/notes/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png differ
diff --git a/docs/notes/pics/e2f0d889-2330-424c-8193-198edebecff7.png b/docs/notes/pics/e2f0d889-2330-424c-8193-198edebecff7.png
new file mode 100644
index 00000000..d747d6f3
Binary files /dev/null and b/docs/notes/pics/e2f0d889-2330-424c-8193-198edebecff7.png differ
diff --git a/docs/notes/pics/e3124763-f75e-46c3-ba82-341e6c98d862.jpg b/docs/notes/pics/e3124763-f75e-46c3-ba82-341e6c98d862.jpg
new file mode 100644
index 00000000..80643657
Binary files /dev/null and b/docs/notes/pics/e3124763-f75e-46c3-ba82-341e6c98d862.jpg differ
diff --git a/docs/notes/pics/e31abb94-9201-4e06-9902-61101b92f475.png b/docs/notes/pics/e31abb94-9201-4e06-9902-61101b92f475.png
new file mode 100644
index 00000000..90833a5c
Binary files /dev/null and b/docs/notes/pics/e31abb94-9201-4e06-9902-61101b92f475.png differ
diff --git a/docs/notes/pics/e3bf5de4-ab1e-4a9b-896d-4b0ad7e9220a.jpg b/docs/notes/pics/e3bf5de4-ab1e-4a9b-896d-4b0ad7e9220a.jpg
new file mode 100644
index 00000000..a3ead324
Binary files /dev/null and b/docs/notes/pics/e3bf5de4-ab1e-4a9b-896d-4b0ad7e9220a.jpg differ
diff --git a/docs/notes/pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png b/docs/notes/pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png
new file mode 100644
index 00000000..105916c6
Binary files /dev/null and b/docs/notes/pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png differ
diff --git a/docs/notes/pics/e41405a8-7c05-4f70-8092-e961e28d3112.jpg b/docs/notes/pics/e41405a8-7c05-4f70-8092-e961e28d3112.jpg
new file mode 100644
index 00000000..7fef7ba5
Binary files /dev/null and b/docs/notes/pics/e41405a8-7c05-4f70-8092-e961e28d3112.jpg differ
diff --git a/docs/notes/pics/e6723b94-1a33-4605-b775-f6813352d383.png b/docs/notes/pics/e6723b94-1a33-4605-b775-f6813352d383.png
new file mode 100644
index 00000000..fdb9280e
Binary files /dev/null and b/docs/notes/pics/e6723b94-1a33-4605-b775-f6813352d383.png differ
diff --git a/docs/notes/pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg b/docs/notes/pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg
new file mode 100644
index 00000000..8eda7a0a
Binary files /dev/null and b/docs/notes/pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg differ
diff --git a/docs/notes/pics/e6bded8e-41a0-489a-88a6-638e88ab7666.jpg b/docs/notes/pics/e6bded8e-41a0-489a-88a6-638e88ab7666.jpg
new file mode 100644
index 00000000..f4aa12a0
Binary files /dev/null and b/docs/notes/pics/e6bded8e-41a0-489a-88a6-638e88ab7666.jpg differ
diff --git a/docs/notes/pics/e800b001-7779-495b-8459-d33a7440d7b8.jpg b/docs/notes/pics/e800b001-7779-495b-8459-d33a7440d7b8.jpg
new file mode 100644
index 00000000..07d6b7a9
Binary files /dev/null and b/docs/notes/pics/e800b001-7779-495b-8459-d33a7440d7b8.jpg differ
diff --git a/docs/notes/pics/e82e0454-4ece-435e-945f-90bc0d37bf44.png b/docs/notes/pics/e82e0454-4ece-435e-945f-90bc0d37bf44.png
new file mode 100644
index 00000000..74a9f8b6
Binary files /dev/null and b/docs/notes/pics/e82e0454-4ece-435e-945f-90bc0d37bf44.png differ
diff --git a/docs/notes/pics/e92d0ebc-7d46-413b-aec1-34a39602f787.png b/docs/notes/pics/e92d0ebc-7d46-413b-aec1-34a39602f787.png
new file mode 100644
index 00000000..1090a779
Binary files /dev/null and b/docs/notes/pics/e92d0ebc-7d46-413b-aec1-34a39602f787.png differ
diff --git a/docs/notes/pics/ea2304ce-268b-4238-9486-4d8f8aea8ca4.png b/docs/notes/pics/ea2304ce-268b-4238-9486-4d8f8aea8ca4.png
new file mode 100644
index 00000000..59b54d2f
Binary files /dev/null and b/docs/notes/pics/ea2304ce-268b-4238-9486-4d8f8aea8ca4.png differ
diff --git a/docs/notes/pics/ea5f3efe-d5e6-499b-b278-9e898af61257.jpg b/docs/notes/pics/ea5f3efe-d5e6-499b-b278-9e898af61257.jpg
new file mode 100644
index 00000000..a07e736d
Binary files /dev/null and b/docs/notes/pics/ea5f3efe-d5e6-499b-b278-9e898af61257.jpg differ
diff --git a/docs/notes/pics/eb4a7007-d437-4740-865d-672973effe25.png b/docs/notes/pics/eb4a7007-d437-4740-865d-672973effe25.png
new file mode 100644
index 00000000..e2a0faab
Binary files /dev/null and b/docs/notes/pics/eb4a7007-d437-4740-865d-672973effe25.png differ
diff --git a/docs/notes/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png b/docs/notes/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png
new file mode 100644
index 00000000..7104f020
Binary files /dev/null and b/docs/notes/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png differ
diff --git a/docs/notes/pics/ec923dc7-864c-47b0-a411-1f2c48d084de.png b/docs/notes/pics/ec923dc7-864c-47b0-a411-1f2c48d084de.png
new file mode 100644
index 00000000..007e9646
Binary files /dev/null and b/docs/notes/pics/ec923dc7-864c-47b0-a411-1f2c48d084de.png differ
diff --git a/docs/notes/pics/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png b/docs/notes/pics/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png
new file mode 100644
index 00000000..25ed7497
Binary files /dev/null and b/docs/notes/pics/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png differ
diff --git a/docs/notes/pics/ed523051-608f-4c3f-b343-383e2d194470.png b/docs/notes/pics/ed523051-608f-4c3f-b343-383e2d194470.png
new file mode 100644
index 00000000..1f703e2f
Binary files /dev/null and b/docs/notes/pics/ed523051-608f-4c3f-b343-383e2d194470.png differ
diff --git a/docs/notes/pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png b/docs/notes/pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png
new file mode 100644
index 00000000..1c153a8a
Binary files /dev/null and b/docs/notes/pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png differ
diff --git a/docs/notes/pics/ed7b96ac-6428-4bd5-9986-674c54c2a959.png b/docs/notes/pics/ed7b96ac-6428-4bd5-9986-674c54c2a959.png
new file mode 100644
index 00000000..78b3cace
Binary files /dev/null and b/docs/notes/pics/ed7b96ac-6428-4bd5-9986-674c54c2a959.png differ
diff --git a/docs/notes/pics/eebdeb57-8efb-4848-9bb6-97512990897c.jpg b/docs/notes/pics/eebdeb57-8efb-4848-9bb6-97512990897c.jpg
new file mode 100644
index 00000000..5632fdca
Binary files /dev/null and b/docs/notes/pics/eebdeb57-8efb-4848-9bb6-97512990897c.jpg differ
diff --git a/docs/notes/pics/ef280699-da36-4b38-9735-9b048a3c7fe0.png b/docs/notes/pics/ef280699-da36-4b38-9735-9b048a3c7fe0.png
new file mode 100644
index 00000000..a54c85e1
Binary files /dev/null and b/docs/notes/pics/ef280699-da36-4b38-9735-9b048a3c7fe0.png differ
diff --git a/docs/notes/pics/ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png b/docs/notes/pics/ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png
new file mode 100644
index 00000000..f6256867
Binary files /dev/null and b/docs/notes/pics/ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png differ
diff --git a/docs/notes/pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg b/docs/notes/pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg
new file mode 100644
index 00000000..66a2ecbe
Binary files /dev/null and b/docs/notes/pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg differ
diff --git a/docs/notes/pics/f0a31c04-6e26-408c-8395-88f4e2ae928b.jpg b/docs/notes/pics/f0a31c04-6e26-408c-8395-88f4e2ae928b.jpg
new file mode 100644
index 00000000..99eb3168
Binary files /dev/null and b/docs/notes/pics/f0a31c04-6e26-408c-8395-88f4e2ae928b.jpg differ
diff --git a/docs/notes/pics/f0e35b7a-2948-488a-a5a9-97d3f6b5e2d7.png b/docs/notes/pics/f0e35b7a-2948-488a-a5a9-97d3f6b5e2d7.png
new file mode 100644
index 00000000..8f797bdf
Binary files /dev/null and b/docs/notes/pics/f0e35b7a-2948-488a-a5a9-97d3f6b5e2d7.png differ
diff --git a/docs/notes/pics/f1109d04-3c67-48a3-9963-2c475f94e175.jpg b/docs/notes/pics/f1109d04-3c67-48a3-9963-2c475f94e175.jpg
new file mode 100644
index 00000000..cdd1b55e
Binary files /dev/null and b/docs/notes/pics/f1109d04-3c67-48a3-9963-2c475f94e175.jpg differ
diff --git a/docs/notes/pics/f3080f83-6239-459b-8e9c-03b6641f7815.png b/docs/notes/pics/f3080f83-6239-459b-8e9c-03b6641f7815.png
new file mode 100644
index 00000000..77868686
Binary files /dev/null and b/docs/notes/pics/f3080f83-6239-459b-8e9c-03b6641f7815.png differ
diff --git a/docs/notes/pics/f3bfe11f-9cba-4ff2-8cc6-629068408a80.jpg b/docs/notes/pics/f3bfe11f-9cba-4ff2-8cc6-629068408a80.jpg
new file mode 100644
index 00000000..9dc7a1d5
Binary files /dev/null and b/docs/notes/pics/f3bfe11f-9cba-4ff2-8cc6-629068408a80.jpg differ
diff --git a/docs/notes/pics/f3d3e072-e947-43e9-b999-22385fd569a0.jpg b/docs/notes/pics/f3d3e072-e947-43e9-b999-22385fd569a0.jpg
new file mode 100644
index 00000000..7b08be6d
Binary files /dev/null and b/docs/notes/pics/f3d3e072-e947-43e9-b999-22385fd569a0.jpg differ
diff --git a/docs/notes/pics/f42443e0-208d-41ea-be44-c7fd97d2e3bf.png b/docs/notes/pics/f42443e0-208d-41ea-be44-c7fd97d2e3bf.png
new file mode 100644
index 00000000..4a5dbd1d
Binary files /dev/null and b/docs/notes/pics/f42443e0-208d-41ea-be44-c7fd97d2e3bf.png differ
diff --git a/docs/notes/pics/f48e2b92-2c2a-48cb-a443-bd313e187a25.jpg b/docs/notes/pics/f48e2b92-2c2a-48cb-a443-bd313e187a25.jpg
new file mode 100644
index 00000000..66c29824
Binary files /dev/null and b/docs/notes/pics/f48e2b92-2c2a-48cb-a443-bd313e187a25.jpg differ
diff --git a/docs/notes/pics/f4cdda3e-324c-49b5-8c14-08a3db634b29.png b/docs/notes/pics/f4cdda3e-324c-49b5-8c14-08a3db634b29.png
new file mode 100644
index 00000000..60fc81bb
Binary files /dev/null and b/docs/notes/pics/f4cdda3e-324c-49b5-8c14-08a3db634b29.png differ
diff --git a/docs/notes/pics/f50a8e52-a683-444c-8e32-63c1890fe84a.jpg b/docs/notes/pics/f50a8e52-a683-444c-8e32-63c1890fe84a.jpg
new file mode 100644
index 00000000..46a01b3e
Binary files /dev/null and b/docs/notes/pics/f50a8e52-a683-444c-8e32-63c1890fe84a.jpg differ
diff --git a/docs/notes/pics/f5477abd-c246-4851-89ab-6b1cde2549b1.png b/docs/notes/pics/f5477abd-c246-4851-89ab-6b1cde2549b1.png
new file mode 100644
index 00000000..f358a009
Binary files /dev/null and b/docs/notes/pics/f5477abd-c246-4851-89ab-6b1cde2549b1.png differ
diff --git a/docs/notes/pics/f5757d09-88e7-4bbd-8cfb-cecf55604854.png b/docs/notes/pics/f5757d09-88e7-4bbd-8cfb-cecf55604854.png
new file mode 100644
index 00000000..1664247b
Binary files /dev/null and b/docs/notes/pics/f5757d09-88e7-4bbd-8cfb-cecf55604854.png differ
diff --git a/docs/notes/pics/f61b5419-c94a-4df1-8d4d-aed9ae8cc6d5.png b/docs/notes/pics/f61b5419-c94a-4df1-8d4d-aed9ae8cc6d5.png
new file mode 100644
index 00000000..dc0d4e34
Binary files /dev/null and b/docs/notes/pics/f61b5419-c94a-4df1-8d4d-aed9ae8cc6d5.png differ
diff --git a/docs/notes/pics/f716427a-94f2-4875-9c86-98793cf5dcc3.jpg b/docs/notes/pics/f716427a-94f2-4875-9c86-98793cf5dcc3.jpg
new file mode 100644
index 00000000..15da1c6b
Binary files /dev/null and b/docs/notes/pics/f716427a-94f2-4875-9c86-98793cf5dcc3.jpg differ
diff --git a/docs/notes/pics/f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg b/docs/notes/pics/f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg
new file mode 100644
index 00000000..d710e659
Binary files /dev/null and b/docs/notes/pics/f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg differ
diff --git a/docs/notes/pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png b/docs/notes/pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png
new file mode 100644
index 00000000..26799762
Binary files /dev/null and b/docs/notes/pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png differ
diff --git a/docs/notes/pics/f7ecbb8d-bb8b-4d45-a3b7-f49425d6d83d.jpg b/docs/notes/pics/f7ecbb8d-bb8b-4d45-a3b7-f49425d6d83d.jpg
new file mode 100644
index 00000000..ab51d486
Binary files /dev/null and b/docs/notes/pics/f7ecbb8d-bb8b-4d45-a3b7-f49425d6d83d.jpg differ
diff --git a/docs/notes/pics/f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png b/docs/notes/pics/f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png
new file mode 100644
index 00000000..b85accf6
Binary files /dev/null and b/docs/notes/pics/f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png differ
diff --git a/docs/notes/pics/f8047846-efd4-42be-b6b7-27a7c4998b51.png b/docs/notes/pics/f8047846-efd4-42be-b6b7-27a7c4998b51.png
new file mode 100644
index 00000000..86e2294f
Binary files /dev/null and b/docs/notes/pics/f8047846-efd4-42be-b6b7-27a7c4998b51.png differ
diff --git a/docs/notes/pics/f87afe72-c2df-4c12-ac03-9b8d581a8af8.jpg b/docs/notes/pics/f87afe72-c2df-4c12-ac03-9b8d581a8af8.jpg
new file mode 100644
index 00000000..6a090993
Binary files /dev/null and b/docs/notes/pics/f87afe72-c2df-4c12-ac03-9b8d581a8af8.jpg differ
diff --git a/docs/notes/pics/f8b16d1e-7363-4544-94d6-4939fdf849dc.png b/docs/notes/pics/f8b16d1e-7363-4544-94d6-4939fdf849dc.png
new file mode 100644
index 00000000..300b6e06
Binary files /dev/null and b/docs/notes/pics/f8b16d1e-7363-4544-94d6-4939fdf849dc.png differ
diff --git a/docs/notes/pics/f8b3f73d-0fda-449f-b55b-fa36b7ac04cd.png b/docs/notes/pics/f8b3f73d-0fda-449f-b55b-fa36b7ac04cd.png
new file mode 100644
index 00000000..4d9e3e21
Binary files /dev/null and b/docs/notes/pics/f8b3f73d-0fda-449f-b55b-fa36b7ac04cd.png differ
diff --git a/docs/notes/pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg b/docs/notes/pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg
new file mode 100644
index 00000000..95b92d60
Binary files /dev/null and b/docs/notes/pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg differ
diff --git a/docs/notes/pics/f94389e9-55b1-4f49-9d37-00ed05900ae0.png b/docs/notes/pics/f94389e9-55b1-4f49-9d37-00ed05900ae0.png
new file mode 100644
index 00000000..49817697
Binary files /dev/null and b/docs/notes/pics/f94389e9-55b1-4f49-9d37-00ed05900ae0.png differ
diff --git a/docs/notes/pics/f9978fa6-9f49-4a0f-8540-02d269ac448f.png b/docs/notes/pics/f9978fa6-9f49-4a0f-8540-02d269ac448f.png
new file mode 100644
index 00000000..7da6d4b2
Binary files /dev/null and b/docs/notes/pics/f9978fa6-9f49-4a0f-8540-02d269ac448f.png differ
diff --git a/docs/notes/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg b/docs/notes/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg
new file mode 100644
index 00000000..67fac8fe
Binary files /dev/null and b/docs/notes/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg differ
diff --git a/docs/notes/pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg b/docs/notes/pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg
new file mode 100644
index 00000000..b6a0ba79
Binary files /dev/null and b/docs/notes/pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg differ
diff --git a/docs/notes/pics/f9f9f993-8ece-4da7-b848-af9b438fad76.png b/docs/notes/pics/f9f9f993-8ece-4da7-b848-af9b438fad76.png
new file mode 100644
index 00000000..824904db
Binary files /dev/null and b/docs/notes/pics/f9f9f993-8ece-4da7-b848-af9b438fad76.png differ
diff --git a/docs/notes/pics/fa2273c3-1b5f-48ce-8e8b-441a4116c1c4.jpg b/docs/notes/pics/fa2273c3-1b5f-48ce-8e8b-441a4116c1c4.jpg
new file mode 100644
index 00000000..42d3c743
Binary files /dev/null and b/docs/notes/pics/fa2273c3-1b5f-48ce-8e8b-441a4116c1c4.jpg differ
diff --git a/docs/notes/pics/fa568fac-ac58-48dd-a9bb-23b3065bf2dc.png b/docs/notes/pics/fa568fac-ac58-48dd-a9bb-23b3065bf2dc.png
new file mode 100644
index 00000000..736a2861
Binary files /dev/null and b/docs/notes/pics/fa568fac-ac58-48dd-a9bb-23b3065bf2dc.png differ
diff --git a/docs/notes/pics/faecea49-9974-40db-9821-c8636137df61.jpg b/docs/notes/pics/faecea49-9974-40db-9821-c8636137df61.jpg
new file mode 100644
index 00000000..1b236b6e
Binary files /dev/null and b/docs/notes/pics/faecea49-9974-40db-9821-c8636137df61.jpg differ
diff --git a/docs/notes/pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png b/docs/notes/pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png
new file mode 100644
index 00000000..774ecf10
Binary files /dev/null and b/docs/notes/pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png differ
diff --git a/docs/notes/pics/fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg b/docs/notes/pics/fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg
new file mode 100644
index 00000000..36c1d9b7
Binary files /dev/null and b/docs/notes/pics/fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg differ
diff --git a/docs/notes/pics/fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg b/docs/notes/pics/fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg
new file mode 100644
index 00000000..e15f11db
Binary files /dev/null and b/docs/notes/pics/fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg differ
diff --git a/docs/notes/pics/fbe54203-c005-48f0-8883-b05e564a3173.png b/docs/notes/pics/fbe54203-c005-48f0-8883-b05e564a3173.png
new file mode 100644
index 00000000..dee6a88d
Binary files /dev/null and b/docs/notes/pics/fbe54203-c005-48f0-8883-b05e564a3173.png differ
diff --git a/docs/notes/pics/fc0c6b2d-68c7-4de8-aaaa-97355a4f0472.jpg b/docs/notes/pics/fc0c6b2d-68c7-4de8-aaaa-97355a4f0472.jpg
new file mode 100644
index 00000000..55332ce3
Binary files /dev/null and b/docs/notes/pics/fc0c6b2d-68c7-4de8-aaaa-97355a4f0472.jpg differ
diff --git a/docs/notes/pics/ff0c019c-6461-467d-a266-0455341fd4f4.png b/docs/notes/pics/ff0c019c-6461-467d-a266-0455341fd4f4.png
new file mode 100644
index 00000000..658867d2
Binary files /dev/null and b/docs/notes/pics/ff0c019c-6461-467d-a266-0455341fd4f4.png differ
diff --git a/docs/notes/pics/ff396233-1bb1-4e74-8bc2-d7c90146f5dd.png b/docs/notes/pics/ff396233-1bb1-4e74-8bc2-d7c90146f5dd.png
new file mode 100644
index 00000000..4eaa11ba
Binary files /dev/null and b/docs/notes/pics/ff396233-1bb1-4e74-8bc2-d7c90146f5dd.png differ
diff --git a/docs/notes/pics/flow.png b/docs/notes/pics/flow.png
new file mode 100644
index 00000000..aa0492a4
Binary files /dev/null and b/docs/notes/pics/flow.png differ
diff --git a/docs/notes/pics/hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png b/docs/notes/pics/hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png
new file mode 100644
index 00000000..f19ceb66
Binary files /dev/null and b/docs/notes/pics/hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png differ
diff --git a/docs/notes/pics/image005.jpg b/docs/notes/pics/image005.jpg
new file mode 100644
index 00000000..a20df7d8
Binary files /dev/null and b/docs/notes/pics/image005.jpg differ
diff --git a/docs/notes/pics/image007.jpg b/docs/notes/pics/image007.jpg
new file mode 100644
index 00000000..822aa76e
Binary files /dev/null and b/docs/notes/pics/image007.jpg differ
diff --git a/docs/notes/pics/image008.jpg b/docs/notes/pics/image008.jpg
new file mode 100644
index 00000000..952f4aa8
Binary files /dev/null and b/docs/notes/pics/image008.jpg differ
diff --git a/docs/notes/pics/image009.jpg b/docs/notes/pics/image009.jpg
new file mode 100644
index 00000000..6e956fec
Binary files /dev/null and b/docs/notes/pics/image009.jpg differ
diff --git a/docs/notes/pics/inode_with_signatures.jpg b/docs/notes/pics/inode_with_signatures.jpg
new file mode 100644
index 00000000..518ba5ac
Binary files /dev/null and b/docs/notes/pics/inode_with_signatures.jpg differ
diff --git a/docs/notes/pics/java-collections.png b/docs/notes/pics/java-collections.png
new file mode 100644
index 00000000..6a68af89
Binary files /dev/null and b/docs/notes/pics/java-collections.png differ
diff --git a/docs/notes/pics/java-collections1.png b/docs/notes/pics/java-collections1.png
new file mode 100644
index 00000000..852282ef
Binary files /dev/null and b/docs/notes/pics/java-collections1.png differ
diff --git a/docs/notes/pics/linux-filesystem.png b/docs/notes/pics/linux-filesystem.png
new file mode 100644
index 00000000..ae965295
Binary files /dev/null and b/docs/notes/pics/linux-filesystem.png differ
diff --git a/docs/notes/pics/master-slave-proxy.png b/docs/notes/pics/master-slave-proxy.png
new file mode 100644
index 00000000..66be0d61
Binary files /dev/null and b/docs/notes/pics/master-slave-proxy.png differ
diff --git a/docs/notes/pics/master-slave.png b/docs/notes/pics/master-slave.png
new file mode 100644
index 00000000..594a183a
Binary files /dev/null and b/docs/notes/pics/master-slave.png differ
diff --git a/docs/notes/pics/monitor-lock-rule.png b/docs/notes/pics/monitor-lock-rule.png
new file mode 100644
index 00000000..6590d94b
Binary files /dev/null and b/docs/notes/pics/monitor-lock-rule.png differ
diff --git a/docs/notes/pics/mutualssl_small.png b/docs/notes/pics/mutualssl_small.png
new file mode 100644
index 00000000..1541eba8
Binary files /dev/null and b/docs/notes/pics/mutualssl_small.png differ
diff --git a/docs/notes/pics/n2U3N.png b/docs/notes/pics/n2U3N.png
new file mode 100644
index 00000000..cd58b5b9
Binary files /dev/null and b/docs/notes/pics/n2U3N.png differ
diff --git a/docs/notes/pics/network-of-networks.gif b/docs/notes/pics/network-of-networks.gif
new file mode 100644
index 00000000..7473f913
Binary files /dev/null and b/docs/notes/pics/network-of-networks.gif differ
diff --git a/docs/notes/pics/pcrypt.gif b/docs/notes/pics/pcrypt.gif
new file mode 100644
index 00000000..c17b9853
Binary files /dev/null and b/docs/notes/pics/pcrypt.gif differ
diff --git a/docs/notes/pics/ppt_img.gif b/docs/notes/pics/ppt_img.gif
new file mode 100644
index 00000000..8e5ad145
Binary files /dev/null and b/docs/notes/pics/ppt_img.gif differ
diff --git a/docs/notes/pics/scrypt.gif b/docs/notes/pics/scrypt.gif
new file mode 100644
index 00000000..150fea7f
Binary files /dev/null and b/docs/notes/pics/scrypt.gif differ
diff --git a/docs/notes/pics/single-thread-rule.png b/docs/notes/pics/single-thread-rule.png
new file mode 100644
index 00000000..d6583e9e
Binary files /dev/null and b/docs/notes/pics/single-thread-rule.png differ
diff --git a/docs/notes/pics/ssl-offloading.jpg b/docs/notes/pics/ssl-offloading.jpg
new file mode 100644
index 00000000..8f01a418
Binary files /dev/null and b/docs/notes/pics/ssl-offloading.jpg differ
diff --git a/docs/notes/pics/tGPV0.png b/docs/notes/pics/tGPV0.png
new file mode 100644
index 00000000..89fb7bfe
Binary files /dev/null and b/docs/notes/pics/tGPV0.png differ
diff --git a/docs/notes/pics/thread-join-rule.png b/docs/notes/pics/thread-join-rule.png
new file mode 100644
index 00000000..c17d0456
Binary files /dev/null and b/docs/notes/pics/thread-join-rule.png differ
diff --git a/docs/notes/pics/thread-start-rule.png b/docs/notes/pics/thread-start-rule.png
new file mode 100644
index 00000000..60ee7862
Binary files /dev/null and b/docs/notes/pics/thread-start-rule.png differ
diff --git a/docs/notes/pics/url_diagram.png b/docs/notes/pics/url_diagram.png
new file mode 100644
index 00000000..18bbd49b
Binary files /dev/null and b/docs/notes/pics/url_diagram.png differ
diff --git a/docs/notes/pics/urlnuri.jpg b/docs/notes/pics/urlnuri.jpg
new file mode 100644
index 00000000..be05f018
Binary files /dev/null and b/docs/notes/pics/urlnuri.jpg differ
diff --git a/docs/notes/pics/volatile-variable-rule.png b/docs/notes/pics/volatile-variable-rule.png
new file mode 100644
index 00000000..1747664b
Binary files /dev/null and b/docs/notes/pics/volatile-variable-rule.png differ
diff --git a/docs/notes/代码可读性.md b/docs/notes/代码可读性.md
index 45e624fa..08137284 100644
--- a/docs/notes/代码可读性.md
+++ b/docs/notes/代码可读性.md
@@ -49,7 +49,7 @@
- 用 first、last 表示访问空间的包含范围;
- begin、end 表示访问空间的排除范围,即 end 不包含尾部。
-
+
# 四、良好的代码风格
diff --git a/docs/notes/分布式.md b/docs/notes/分布式.md
index e829eb63..0f44d43d 100644
--- a/docs/notes/分布式.md
+++ b/docs/notes/分布式.md
@@ -70,7 +70,7 @@ EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了
Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父节点为 /app1。
-
+
### 2. 节点类型
@@ -111,7 +111,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
2. 之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。
3. 在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。
-
+
## 2PC
@@ -123,7 +123,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
协调者询问参与者事务是否执行成功,参与者发回事务执行结果。
-
+
#### 1.2 提交阶段
@@ -131,7 +131,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。
-
+
### 2. 存在的问题
@@ -155,7 +155,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容忍性(P:Partition Tolerance),最多只能同时满足其中两项。
-
+
## 一致性
@@ -184,7 +184,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
- 为了保证一致性(CP),不能访问未同步完成的节点,也就失去了部分可用性;
- 为了保证可用性(AP),允许读取所有节点的数据,但是数据可能不一致。
-
+
# 四、BASE
@@ -192,7 +192,7 @@ BASE 是基本可用(Basically Available)、软状态(Soft State)和最
BASE 理论是对 CAP 中一致性和可用性权衡的结果,它的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
-
+
## 基本可用
@@ -222,7 +222,7 @@ ACID 要求强一致性,通常运用在传统的数据库系统上。而 BASE
- 接受者(Acceptor):对每个提议进行投票;
- 告知者(Learner):被告知投票的结果,不参与投票过程。
-
+
## 执行过程
@@ -232,19 +232,19 @@ ACID 要求强一致性,通常运用在传统的数据库系统上。而 BASE
下图演示了两个 Proposer 和三个 Acceptor 的系统中运行该算法的初始过程,每个 Proposer 都会向所有 Acceptor 发送 Prepare 请求。
-
+
当 Acceptor 接收到一个 Prepare 请求,包含的提议为 [n1, v1],并且之前还未接收过 Prepare 请求,那么发送一个 Prepare 响应,设置当前接收到的提议为 [n1, v1],并且保证以后不会再接受序号小于 n1 的提议。
如下图,Acceptor X 在收到 [n=2, v=8] 的 Prepare 请求时,由于之前没有接收过提议,因此就发送一个 [no previous] 的 Prepare 响应,设置当前接收到的提议为 [n=2, v=8],并且保证以后不会再接受序号小于 2 的提议。其它的 Acceptor 类似。
-
+
如果 Acceptor 接收到一个 Prepare 请求,包含的提议为 [n2, v2],并且之前已经接收过提议 [n1, v1]。如果 n1 > n2,那么就丢弃该提议请求;否则,发送 Prepare 响应,该 Prepare 响应包含之前已经接收过的提议 [n1, v1],设置当前接收到的提议为 [n2, v2],并且保证以后不会再接受序号小于 n2 的提议。
如下图,Acceptor Z 收到 Proposer A 发来的 [n=2, v=8] 的 Prepare 请求,由于之前已经接收过 [n=4, v=5] 的提议,并且 n > 2,因此就抛弃该提议请求;Acceptor X 收到 Proposer B 发来的 [n=4, v=5] 的 Prepare 请求,因为之前接收到的提议为 [n=2, v=8],并且 2 <= 4,因此就发送 [n=2, v=8] 的 Prepare 响应,设置当前接收到的提议为 [n=4, v=5],并且保证以后不会再接受序号小于 4 的提议。Acceptor Y 类似。
-
+
### 2. Accept 阶段
@@ -254,13 +254,13 @@ Proposer A 接收到两个 Prepare 响应之后,就发送 [n=2, v=8] Accept
Proposer B 过后也收到了两个 Prepare 响应,因此也开始发送 Accept 请求。需要注意的是,Accept 请求的 v 需要取它收到的最大提议编号对应的 v 值,也就是 8。因此它发送 [n=4, v=8] 的 Accept 请求。
-
+
### 3. Learn 阶段
Acceptor 接收到 Accept 请求时,如果序号大于等于该 Acceptor 承诺的最小序号,那么就发送 Learn 提议给所有的 Learner。当 Learner 发现有大多数的 Acceptor 接收了某个提议,那么该提议的提议值就被 Paxos 选择出来。
-
+
## 约束条件
@@ -286,47 +286,47 @@ Raft 也是分布式一致性协议,主要是用来竞选主节点。
- 下图展示一个分布式系统的最初阶段,此时只有 Follower 没有 Leader。Node A 等待一个随机的竞选超时时间之后,没收到 Leader 发来的心跳包,因此进入竞选阶段。
-
+
- 此时 Node A 发送投票请求给其它所有节点。
-
+
- 其它节点会对请求进行回复,如果超过一半的节点回复了,那么该 Candidate 就会变成 Leader。
-
+
- 之后 Leader 会周期性地发送心跳包给 Follower,Follower 接收到心跳包,会重新开始计时。
-
+
## 多个 Candidate 竞选
- 如果有多个 Follower 成为 Candidate,并且所获得票数相同,那么就需要重新开始投票。例如下图中 Node B 和 Node D 都获得两票,需要重新开始投票。
-
+
- 由于每个节点设置的随机竞选超时时间不同,因此下一次再次出现多个 Candidate 并获得同样票数的概率很低。
-
+
## 数据同步
- 来自客户端的修改都会被传入 Leader。注意该修改还未被提交,只是写入日志中。
-
+
- Leader 会把修改复制到所有 Follower。
-
+
- Leader 会等待大多数的 Follower 也进行了修改,然后才将修改提交。
-
+
- 此时 Leader 会通知的所有 Follower 让它们也提交修改,此时所有节点的值达成一致。
-
+
# 参考
diff --git a/docs/notes/剑指 offer 题解.md b/docs/notes/剑指 offer 题解.md
index 6e54a559..a6a6d78d 100644
--- a/docs/notes/剑指 offer 题解.md
+++ b/docs/notes/剑指 offer 题解.md
@@ -182,7 +182,7 @@ Given target = 20, return false.
当前元素的查找区间为左下角的所有元素,例如元素 12 的查找区间如下:
-
+
```java
public boolean Find(int target, int[][] matrix) {
@@ -257,7 +257,7 @@ public String replaceSpace(StringBuffer str) {
输入链表的第一个节点,从尾到头反过来打印出每个结点的值。
-
+
## 解题思路
@@ -347,7 +347,7 @@ preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
```
-
+
## 解题思路
@@ -401,11 +401,11 @@ public class TreeLinkNode {
① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
-
+
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
-
+
```java
public TreeLinkNode GetNext(TreeLinkNode pNode) {
@@ -438,7 +438,7 @@ public TreeLinkNode GetNext(TreeLinkNode pNode) {
in 栈用来处理入栈(push)操作,out 栈用来处理出栈(pop)操作。一个元素进入 in 栈之后,出栈的顺序被反转。当元素要出栈时,需要先进入 out 栈,此时元素出栈顺序再一次被反转,因此出栈顺序就和最开始入栈顺序是相同的,先进入的元素先退出,这就是队列的顺序。
-
+
```java
Stack in = new Stack();
@@ -474,7 +474,7 @@ public int pop() throws Exception {
如果使用递归求解,会重复计算一些子问题。例如,计算 f(10) 需要计算 f(9) 和 f(8),计算 f(9) 需要计算 f(8) 和 f(7),可以看到 f(8) 被重复计算了。
-
+
递归是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。
@@ -707,7 +707,7 @@ private int minNumber(int[] nums, int l, int h) {
例如下面的矩阵包含了一条 bfce 路径。
-
+
## 解题思路
@@ -984,11 +984,11 @@ private void printNumber(char[] number) {
① 如果该节点不是尾节点,那么可以直接将下一个节点的值赋给该节点,然后令该节点指向下下个节点,再删除下一个节点,时间复杂度为 O(1)。
-
+
② 否则,就需要先遍历链表,找到节点的前一个节点,然后让前一个节点指向 null,时间复杂度为 O(N)。
-
+
综上,如果进行 N 次操作,那么大约需要操作节点的次数为 N-1+N=2N-1,其中 N-1 表示 N-1 个不是尾节点的每个节点以 O(1) 的时间复杂度操作节点的总次数,N 表示 1 个尾节点以 O(N) 的时间复杂度操作节点的总次数。(2N-1)/N \~ 2,因此该算法的平均时间复杂度为 O(1)。
@@ -1017,7 +1017,7 @@ public ListNode deleteNode(ListNode head, ListNode tobeDelete) {
## 题目描述
-
+
## 解题描述
@@ -1162,7 +1162,7 @@ public void reOrderArray(int[] nums) {
设链表的长度为 N。设两个指针 P1 和 P2,先让 P1 移动 K 个节点,则还有 N - K 个节点可以移动。此时让 P1 和 P2 同时移动,可以知道当 P1 移动到链表结尾时,P2 移动到 N - K 个节点处,该位置就是倒数第 K 个节点。
-
+
```java
public ListNode FindKthToTail(ListNode head, int k) {
@@ -1196,7 +1196,7 @@ public ListNode FindKthToTail(ListNode head, int k) {
在相遇点,slow 要到环的入口点还需要移动 z 个节点,如果让 fast 重新从头开始移动,并且速度变为每次移动一个节点,那么它到环入口点还需要移动 x 个节点。在上面已经推导出 x=z,因此 fast 和 slow 将在环入口点相遇。
-
+
```java
public ListNode EntryNodeOfLoop(ListNode pHead) {
@@ -1257,7 +1257,7 @@ public ListNode ReverseList(ListNode head) {
## 题目描述
-
+
## 解题思路
@@ -1309,7 +1309,7 @@ public ListNode Merge(ListNode list1, ListNode list2) {
## 题目描述
-
+
## 解题思路
@@ -1337,7 +1337,7 @@ private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) {
## 题目描述
-
+
## 解题思路
@@ -1363,7 +1363,7 @@ private void swap(TreeNode root) {
## 题目描述
-
+
## 解题思路
@@ -1393,7 +1393,7 @@ boolean isSymmetrical(TreeNode t1, TreeNode t2) {
下图的矩阵顺时针打印结果为:1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10
-
+
## 解题思路
@@ -1491,7 +1491,7 @@ public boolean IsPopOrder(int[] pushSequence, int[] popSequence) {
例如,以下二叉树层次遍历的结果为:1,2,3,4,5,6,7
-
+
## 解题思路
@@ -1599,7 +1599,7 @@ public ArrayList> Print(TreeNode pRoot) {
例如,下图是后序遍历序列 1,3,2 所对应的二叉搜索树。
-
+
## 解题思路
@@ -1634,7 +1634,7 @@ private boolean verify(int[] sequence, int first, int last) {
下图的二叉树有两条和为 22 的路径:10, 5, 7 和 10, 12
-
+
## 解题思路
@@ -1681,21 +1681,21 @@ public class RandomListNode {
}
```
-
+
## 解题思路
第一步,在每个节点的后面插入复制的节点。
-
+
第二步,对复制节点的 random 链接进行赋值。
-
+
第三步,拆分。
-
+
```java
public RandomListNode Clone(RandomListNode pHead) {
@@ -1737,7 +1737,7 @@ public RandomListNode Clone(RandomListNode pHead) {
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
-
+
## 解题思路
@@ -2377,7 +2377,7 @@ private void merge(int[] nums, int l, int m, int h) {
## 题目描述
-
+
## 解题思路
@@ -2469,7 +2469,7 @@ private void inOrder(TreeNode root, int k) {
从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
-
+
## 解题思路
@@ -2487,7 +2487,7 @@ public int TreeDepth(TreeNode root) {
平衡二叉树左右子树高度差不超过 1。
-
+
## 解题思路
@@ -2999,7 +2999,7 @@ public int StrToInt(String str) {
### 二叉查找树
-
+
[Leetcode : 235. Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/)
@@ -3019,7 +3019,7 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
### 普通二叉树
-
+
[Leetcode : 236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/)
diff --git a/docs/notes/数据库系统原理.md b/docs/notes/数据库系统原理.md
index 6e910f37..2b5339fd 100644
--- a/docs/notes/数据库系统原理.md
+++ b/docs/notes/数据库系统原理.md
@@ -47,7 +47,7 @@
事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。
-
+
## ACID
@@ -80,7 +80,7 @@
- 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
- 事务满足持久化是为了能应对数据库崩溃的情况。
-
+
## AUTOCOMMIT
@@ -94,25 +94,25 @@ MySQL 默认采用自动提交模式。也就是说,如果不显式使用`STAR
T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。
-
+
## 读脏数据
T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。
-
+
## 不可重复读
T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。
-
+
## 幻影读
T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
-
+
----
@@ -130,7 +130,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。
-
+
## 封锁类型
@@ -321,7 +321,7 @@ MVCC 在每行记录后面都保存着两个隐藏的列,用来存储两个版
MVCC 使用到的快照存储在 Undo 日志中,该日志通过回滚指针把一个数据行(Record)的所有快照连接起来。
-
+
## 实现过程
@@ -437,7 +437,7 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
高级别范式的依赖于低级别的范式,1NF 是最低级别的范式。
-
+
### 1. 第一范式 (1NF)
@@ -537,7 +537,7 @@ Entity-Relationship,有三个组成部分:实体、属性、联系。
下图的 Course 和 Student 是一对多的关系。
-
+
## 表示出现多次的关系
@@ -545,23 +545,23 @@ Entity-Relationship,有三个组成部分:实体、属性、联系。
下图表示一个课程的先修关系,先修关系出现两个 Course 实体,第一个是先修课程,后一个是后修课程,因此需要用两条线来表示这种关系。
-
+
## 联系的多向性
虽然老师可以开设多门课,并且可以教授多名学生,但是对于特定的学生和课程,只有一个老师教授,这就构成了一个三元联系。
-
+
一般只使用二元联系,可以把多元联系转换为二元联系。
-
+
## 表示子类
用一个三角形和两条线来连接类和子类,与子类有关的属性和联系都连到子类上,而与父类和子类都有关的连到父类上。
-
+
# 参考资料
diff --git a/docs/notes/构建工具.md b/docs/notes/构建工具.md
index ed38709e..f8dfbee5 100644
--- a/docs/notes/构建工具.md
+++ b/docs/notes/构建工具.md
@@ -34,7 +34,7 @@
主要包括 Ant、Maven 和 Gradle。
-
+
Gradle 和 Maven 的区别是,它使用 Groovy 这种特定领域语言(DSL)来管理构建脚本,而不再使用 XML 这种标记性语言。因为项目如果庞大的话,XML 很容易就变得臃肿。
diff --git a/docs/notes/正则表达式.md b/docs/notes/正则表达式.md
index c713da63..065e12d1 100644
--- a/docs/notes/正则表达式.md
+++ b/docs/notes/正则表达式.md
@@ -173,7 +173,7 @@ a.+c
^\s*\/\/.*$
```
-
+
**匹配结果**
diff --git a/docs/notes/消息队列.md b/docs/notes/消息队列.md
index 2226de74..18c16fd7 100644
--- a/docs/notes/消息队列.md
+++ b/docs/notes/消息队列.md
@@ -19,20 +19,20 @@
消息生产者向消息队列中发送了一个消息之后,只能被一个消费者消费一次。
-
+
## 发布/订阅
消息生产者向频道发送一个消息之后,多个消费者可以从该频道订阅到这条消息并消费。
-
+
发布与订阅模式和观察者模式有以下不同:
- 观察者模式中,观察者和主题都知道对方的存在;而在发布与订阅模式中,发布者与订阅者不知道对方的存在,它们之间通过频道进行通信。
- 观察者模式是同步的,当事件触发时,主题会调用观察者的方法,然后等待方法返回;而发布与订阅模式是异步的,发布者向频道发送一个消息之后,就不需要关心订阅者何时去订阅这个消息,可以立即返回。
-
+
# 二、使用场景
diff --git a/docs/notes/算法.md b/docs/notes/算法.md
index 777e3ecd..bc5de79e 100644
--- a/docs/notes/算法.md
+++ b/docs/notes/算法.md
@@ -293,7 +293,7 @@ public abstract class Sort> {
选择排序需要 \~N2 /2 次比较和 \~N 次交换,它的运行时间与输入无关,这个特点使得它对一个已经排序的数组也需要这么多的比较和交换操作。
-
+
```java
public class Selection> extends Sort {
@@ -322,7 +322,7 @@ public class Selection> extends Sort {
以下演示了在一轮循环中,将最大的元素 5 上浮到最右侧。
-
+
```java
public class Bubble> extends Sort {
@@ -358,7 +358,7 @@ public class Bubble> extends Sort {
以下演示了在一轮循环中,将元素 2 插入到左侧已经排序的数组中。
-
+
```java
public class Insertion> extends Sort {
@@ -383,7 +383,7 @@ public class Insertion> extends Sort {
希尔排序使用插入排序对间隔 h 的序列进行排序。通过不断减小 h,最后令 h=1,就可以使得整个数组是有序的。
-
+
```java
public class Shell> extends Sort {
@@ -417,7 +417,7 @@ public class Shell> extends Sort {
归并排序的思想是将数组分成两部分,分别进行排序,然后归并起来。
-
+
### 1. 归并方法
@@ -512,7 +512,7 @@ public class Down2UpMergeSort> extends MergeSort {
- 归并排序将数组分为两个子数组分别排序,并将有序的子数组归并使得整个数组排序;
- 快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。
-
+
```java
public class QuickSort> extends Sort {
@@ -543,7 +543,7 @@ public class QuickSort> extends Sort {
取 a[l] 作为切分元素,然后从数组的左端向右扫描直到找到第一个大于等于它的元素,再从数组的右端向左扫描找到第一个小于它的元素,交换这两个元素。不断进行这个过程,就可以保证左指针 i 的左侧元素都不大于切分元素,右指针 j 的右侧元素都不小于切分元素。当两个指针相遇时,将切分元素 a[l] 和 a[j] 交换位置。
-
+
```java
private int partition(T[] nums, int l, int h) {
@@ -647,7 +647,7 @@ public T select(T[] nums, int k) {
堆可以用数组来表示,这是因为堆是完全二叉树,而完全二叉树很容易就存储在数组中。位置 k 的节点的父节点位置为 k/2,而它的两个子节点的位置分别为 2k 和 2k+1。这里不使用数组索引为 0 的位置,是为了更清晰地描述节点的位置关系。
-
+
```java
public class Heap> {
@@ -683,7 +683,7 @@ public class Heap> {
在堆中,当一个节点比父节点大,那么需要交换这个两个节点。交换后还可能比它新的父节点大,因此需要不断地进行比较和交换操作,把这种操作称为上浮。
-
+
```java
private void swim(int k) {
@@ -696,7 +696,7 @@ private void swim(int k) {
类似地,当一个节点比子节点来得小,也需要不断地向下进行比较和交换操作,把这种操作称为下沉。一个节点如果有两个子节点,应当与两个子节点中最大那个节点进行交换。
-
+
```java
private void sink(int k) {
@@ -745,15 +745,15 @@ public T delMax() {
无序数组建立堆最直接的方法是从左到右遍历数组进行上浮操作。一个更高效的方法是从右至左进行下沉操作,如果一个节点的两个节点都已经是堆有序,那么进行下沉操作可以使得这个节点为根节点的堆有序。叶子节点不需要进行下沉操作,可以忽略叶子节点的元素,因此只需要遍历一半的元素即可。
-
+
#### 5.2 交换堆顶元素与最后一个元素
交换之后需要进行下沉操作维持堆的有序状态。
-
+
-
+
```java
public class HeapSort> extends Sort {
@@ -825,7 +825,7 @@ Java 主要排序方法为 java.util.Arrays.sort(),对于原始数据类型使
用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。
-
+
| 方法 | 描述 |
| :---: | :---: |
@@ -864,7 +864,7 @@ public abstract class UF {
但是 union 操作代价却很高,需要将其中一个连通分量中的所有节点 id 值都修改为另一个节点的 id 值。
-
+
```java
public class QuickFindUF extends UF {
@@ -904,7 +904,7 @@ public class QuickFindUF extends UF {
但是 find 操作开销很大,因为同一个连通分量的节点 id 值不同,id 值只是用来指向另一个节点。因此需要一直向上查找操作,直到找到最上层的节点。
-
+
```java
public class QuickUnionUF extends UF {
@@ -937,7 +937,7 @@ public class QuickUnionUF extends UF {
这种方法可以快速进行 union 操作,但是 find 操作和树高成正比,最坏的情况下树的高度为节点的数目。
-
+
## 加权 Quick Union
@@ -945,7 +945,7 @@ public class QuickUnionUF extends UF {
理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。
-
+
```java
public class WeightedQuickUnionUF extends UF {
@@ -1534,15 +1534,15 @@ public class BinarySearchOrderedST, Value> implement
**二叉树** 是一个空链接,或者是一个有左右两个链接的节点,每个链接都指向一颗子二叉树。
-
+
**二叉查找树** (BST)是一颗二叉树,并且每个节点的值都大于等于其左子树中的所有节点的值而小于等于右子树的所有节点的值。
-
+
BST 有一个重要性质,就是它的中序遍历结果递增排序。
-
+
基本数据结构:
@@ -1616,7 +1616,7 @@ private Value get(Node x, Key key) {
当插入的键不存在于树中,需要创建一个新节点,并且更新上层节点的链接指向该节点,使得该节点正确地链接到树中。
-
+
```java
@Override
@@ -1645,11 +1645,11 @@ private Node put(Node x, Key key, Value value) {
最好的情况下树是完全平衡的,每条空链接和根节点的距离都为 logN。
-
+
在最坏的情况下,树的高度为 N。
-
+
### 4. floor()
@@ -1727,7 +1727,7 @@ private Node min(Node x) {
令指向最小节点的链接指向最小节点的右子树。
-
+
```java
public void deleteMin() {
@@ -1748,7 +1748,7 @@ public Node deleteMin(Node x) {
- 如果待删除的节点只有一个子树, 那么只需要让指向待删除节点的链接指向唯一的子树即可;
- 否则,让右子树的最小节点替换该节点。
-
+
```java
public void delete(Key key) {
@@ -1811,7 +1811,7 @@ private List keys(Node x, Key l, Key h) {
2-3 查找树引入了 2- 节点和 3- 节点,目的是为了让树平衡。一颗完美平衡的 2-3 查找树的所有空链接到根节点的距离应该是相同的。
-
+
### 1. 插入操作
@@ -1821,11 +1821,11 @@ private List keys(Node x, Key l, Key h) {
- 如果插入到 2- 节点上,那么直接将新节点和原来的节点组成 3- 节点即可。
-
+
- 如果是插入到 3- 节点上,就会产生一个临时 4- 节点时,需要将 4- 节点分裂成 3 个 2- 节点,并将中间的 2- 节点移到上层节点中。如果上移操作继续产生临时 4- 节点则一直进行分裂上移,直到不存在临时 4- 节点。
-
+
### 2. 性质
@@ -1837,7 +1837,7 @@ private List keys(Node x, Key l, Key h) {
红黑树是 2-3 查找树,但它不需要分别定义 2- 节点和 3- 节点,而是在普通的二叉查找树之上,为节点添加颜色。指向一个节点的链接颜色如果为红色,那么这个节点和上层节点表示的是一个 3- 节点,而黑色则是普通链接。
-
+
红黑树具有以下性质:
@@ -1846,7 +1846,7 @@ private List keys(Node x, Key l, Key h) {
画红黑树时可以将红链接画平。
-
+
```java
public class RedBlackBST, Value> extends BST {
@@ -1866,7 +1866,7 @@ public class RedBlackBST, Value> extends BST
+
```java
public Node rotateLeft(Node h) {
@@ -1885,7 +1885,7 @@ public Node rotateLeft(Node h) {
进行右旋转是为了转换两个连续的左红链接,这会在之后的插入过程中探讨。
-
+
```java
public Node rotateRight(Node h) {
@@ -1903,7 +1903,7 @@ public Node rotateRight(Node h) {
一个 4- 节点在红黑树中表现为一个节点的左右子节点都是红色的。分裂 4- 节点除了需要将子节点的颜色由红变黑之外,同时需要将父节点的颜色由黑变红,从 2-3 树的角度看就是将中间节点移到上层节点。
-
+
```java
void flipColors(Node h) {
@@ -1921,7 +1921,7 @@ void flipColors(Node h) {
- 如果左子节点是红色的,而且左子节点的左子节点也是红色的,进行右旋转;
- 如果左右子节点均为红色的,进行颜色转换。
-
+
```java
@Override
@@ -2046,7 +2046,7 @@ public class Transaction {
对于 N 个键,M 条链表 (N>M),如果哈希函数能够满足均匀性的条件,每条链表的大小趋向于 N/M,因此未命中的查找和插入操作所需要的比较次数为 \~N/M。
-
+
### 3. 线性探测法
@@ -2054,7 +2054,7 @@ public class Transaction {
使用线性探测法,数组的大小 M 应当大于键的个数 N(M>N)。
-
+
```java
public class LinearProbingHashST implements UnorderedST {
@@ -2155,7 +2155,7 @@ public void delete(Key key) {
线性探测法的成本取决于连续条目的长度,连续条目也叫聚簇。当聚簇很长时,在查找和插入时也需要进行很多次探测。例如下图中 2\~5 位置就是一个聚簇。
-
+
α = N/M,把 α 称为使用率。理论证明,当 α 小于 1/2 时探测的预计次数只在 1.5 到 2.5 之间。为了保证散列表的性能,应当调整数组的大小,使得 α 在 [1/4, 1/2] 之间。
@@ -2231,21 +2231,21 @@ public class SparseVector {
## 汉诺塔
-
+
这是一个经典的递归问题,分为三步求解:
① 将 n-1 个圆盘从 from -> buffer
-
+
② 将 1 个圆盘从 from -> to
-
+
③ 将 n-1 个圆盘从 buffer -> to
-
+
如果只有一个圆盘,那么只需要进行一次移动操作。
@@ -2296,7 +2296,7 @@ from H1 to H3
生成编码时,从根节点出发,向左遍历则添加二进制位 0,向右则添加二进制位 1,直到遍历到叶子节点,叶子节点代表的字符的编码就是这个路径编码。
-
+
```java
public class Huffman {
diff --git a/docs/notes/缓存.md b/docs/notes/缓存.md
index 0a700d21..a8f9e77b 100644
--- a/docs/notes/缓存.md
+++ b/docs/notes/缓存.md
@@ -201,7 +201,7 @@ CDN 主要有以下优点:
- 通过部署多台服务器,从而提高系统整体的带宽性能;
- 多台服务器可以看成是一种冗余机制,从而具有高可用性。
-
+
# 五、缓存问题
@@ -262,11 +262,11 @@ Distributed Hash Table(DHT) 是一种哈希分布方式,其目的是为了
将哈希空间 [0, 2n -1] 看成一个哈希环,每个服务器节点都配置到哈希环上。每个数据对象通过哈希取模得到哈希值之后,存放到哈希环中顺时针方向第一个大于等于该哈希值的节点上。
-
+
一致性哈希在增加或者删除节点时只会影响到哈希环中相邻的节点,例如下图中新增节点 X,只需要将它前一个节点 C 上的数据重新进行分布即可,对于节点 A、B、D 都没有影响。
-
+
## 虚拟节点
diff --git a/docs/notes/计算机操作系统.md b/docs/notes/计算机操作系统.md
index 7ea7a118..cdd90834 100644
--- a/docs/notes/计算机操作系统.md
+++ b/docs/notes/计算机操作系统.md
@@ -96,7 +96,7 @@
如果一个进程在用户态需要使用内核态的功能,就进行系统调用从而陷入内核,由操作系统代为完成。
-
+
Linux 的系统调用主要有以下这些:
@@ -125,7 +125,7 @@ Linux 的系统调用主要有以下这些:
因为需要频繁地在用户态和核心态之间进行切换,所以会有一定的性能损失。
-
+
## 中断分类
@@ -153,7 +153,7 @@ Linux 的系统调用主要有以下这些:
下图显示了 4 个程序创建了 4 个进程,这 4 个进程可以并发地执行。
-
+
### 2. 线程
@@ -163,7 +163,7 @@ Linux 的系统调用主要有以下这些:
QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。
-
+
### 3. 区别
@@ -185,7 +185,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
## 进程状态的切换
-
+
- 就绪状态(ready):等待被调度
- 运行状态(running)
@@ -233,7 +233,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
- 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。
- 而如果时间片过长,那么实时性就不能得到保证。
-
+
**2.2 优先级调度**
@@ -251,7 +251,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。
-
+
### 3. 实时系统
@@ -570,7 +570,7 @@ void reader()
### 2. 哲学家进餐问题
-
+
五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。
@@ -664,7 +664,7 @@ int pipe(int fd[2]);
- 只支持半双工通信(单向交替传输);
- 只能在父子进程中使用。
-
+
### 2. FIFO
@@ -678,7 +678,7 @@ int mkfifoat(int fd, const char *path, mode_t mode);
FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。
-
+
### 3. 消息队列
@@ -708,7 +708,7 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
## 必要条件
-
+
- 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。
- 占有和等待:已经得到了某个资源的进程可以再请求新的资源。
@@ -740,7 +740,7 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
### 1. 每种类型一个资源的死锁检测
-
+
上图为资源分配图,其中方框表示资源,圆圈表示进程。资源指向进程表示该资源已经分配给该进程,进程指向资源表示进程请求获取该资源。
@@ -750,7 +750,7 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
### 2. 每种类型多个资源的死锁检测
-
+
上图中,有三个进程四个资源,每个数据代表的含义如下:
@@ -799,7 +799,7 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
### 1. 安全状态
-
+
图 a 的第二列 Has 表示已拥有的资源数,第三列 Max 表示总共需要的资源数,Free 表示还有可以使用的资源数。从图 a 开始出发,先让 B 拥有所需的所有资源(图 b),运行结束后释放 B,此时 Free 变为 5(图 c);接着以同样的方式运行 C 和 A,使得所有进程都能成功运行,因此可以称图 a 所示的状态时安全的。
@@ -811,13 +811,13 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,算法要做的是判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求;否则予以分配。
-
+
上图 c 为不安全状态,因此算法会拒绝之前的请求,从而避免进入图 c 中的状态。
### 3. 多个资源的银行家算法
-
+
上图中有五个进程,四个资源。左边的图表示已经分配的资源,右边的图表示还需要分配的资源。最右边的 E、P 以及 A 分别表示:总资源、已分配资源以及可用资源,注意这三个为向量,而不是具体数值,例如 A=(1020),表示 4 个资源分别还剩下 1/0/2/0。
@@ -839,7 +839,7 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0\~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。
-
+
## 分页系统地址映射
@@ -849,7 +849,7 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址(0010 000000000100),前 4 位是存储页面号 2,读取表项内容为(110 1),页表项最后一位表示是否存在于内存中,1 表示存在。后 12 位存储偏移量。这个页对应的页框的地址为 (110 000000000100)。
-
+
## 页面置换算法
@@ -885,7 +885,7 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
-
+
### 3. 最近未使用
@@ -916,7 +916,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。
-
+
### 6. 时钟
@@ -924,7 +924,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。
-
+
## 分段
@@ -932,11 +932,11 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
下图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。
-
+
分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。
-
+
## 段页式
@@ -963,7 +963,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
- 制动手臂(Actuator arm):用于在磁道之间移动磁头;
- 主轴(Spindle):使整个盘面转动。
-
+
## 磁盘调度算法
@@ -991,7 +991,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现饥饿现象。具体来说,两端的磁道请求更容易出现饥饿现象。
-
+
### 3. 电梯算法
@@ -1003,7 +1003,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。
-
+
# 六、链接
@@ -1029,7 +1029,7 @@ gcc -o hello hello.c
这个过程大致如下:
-
+
- 预处理阶段:处理以 # 开头的预处理命令;
- 编译阶段:翻译成汇编文件;
@@ -1043,7 +1043,7 @@ gcc -o hello hello.c
- 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。
- 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。
-
+
## 目标文件
@@ -1063,7 +1063,7 @@ gcc -o hello hello.c
- 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中;
- 在内存中,一个共享库的 .text 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。
-
+
# 参考资料
diff --git a/docs/notes/计算机网络.md b/docs/notes/计算机网络.md
index 301effcf..8fb2e6d7 100644
--- a/docs/notes/计算机网络.md
+++ b/docs/notes/计算机网络.md
@@ -59,17 +59,17 @@
网络把主机连接起来,而互联网是把多种不同的网络连接起来,因此互联网是网络的网络。
-
+
## ISP
互联网服务提供商 ISP 可以从互联网管理机构获得许多 IP 地址,同时拥有通信线路以及路由器等联网设备,个人或机构向 ISP 缴纳一定的费用就可以接入互联网。
-
+
目前的互联网是一种多层次 ISP 结构,ISP 根据覆盖面积的大小分为第一层 ISP、区域 ISP 和接入 ISP。互联网交换点 IXP 允许两个 ISP 直接相连而不用经过第三个 ISP。
-
+
## 主机之间的通信方式
@@ -77,7 +77,7 @@
- 对等(P2P):不区分客户和服务器。
-
+
## 电路交换与分组交换
@@ -95,7 +95,7 @@
总时延 = 传输时延 + 传播时延 + 处理时延 + 排队时延
-
+
### 1. 传输时延
@@ -123,7 +123,7 @@
## 计算机网络体系结构
-
+
### 1. 五层协议
@@ -153,11 +153,11 @@
TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接使用 IP 层或者网络接口层。
-
+
TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中占据举足轻重的地位。
-
+
### 4. 数据在各层之间的传递过程
@@ -165,7 +165,7 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
路由器只有下面三层协议,因为路由器位于网络核心中,不需要为进程或者应用程序提供服务,因此也就不需要传输层和应用层。
-
+
# 二、物理层
@@ -181,7 +181,7 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
模拟信号是连续的信号,数字信号是离散的信号。带通调制把数字信号转换为模拟信号。
-
+
# 三、数据链路层
@@ -191,7 +191,7 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
将网络层传下来的分组添加首部和尾部,用于标记帧的开始和结束。
-
+
### 2. 透明传输
@@ -199,7 +199,7 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
帧使用首部和尾部进行定界,如果帧的数据部分含有和首部尾部相同的内容,那么帧的开始和结束位置就会被错误的判定。需要在数据部分出现首部尾部相同的内容前面插入转义字符。如果数据部分出现转义字符,那么就在转义字符前面再加个转义字符。在接收端进行处理之后可以还原出原始数据。这个过程透明传输的内容是转义字符,用户察觉不到转义字符的存在。
-
+
### 3. 差错检测
@@ -227,13 +227,13 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
频分复用的所有主机在相同的时间占用不同的频率带宽资源。
-
+
### 2. 时分复用
时分复用的所有主机在不同的时间占用相同的频率带宽资源。
-
+
使用频分复用和时分复用进行通信,在通信的过程中主机会一直占用一部分信道资源。但是由于计算机数据的突发性质,通信过程没必要一直占用信道资源而不让出给其它用户使用,因此这两种方式对信道的利用率都不高。
@@ -241,13 +241,13 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
是对时分复用的一种改进,不固定每个用户在时分复用帧中的位置,只要有数据就集中起来组成统计时分复用帧然后发送。
-
+
### 4. 波分复用
光的频分复用。由于光的频率很高,因此习惯上用波长而不是频率来表示所使用的光载波。
-
+
### 5. 码分复用
@@ -269,7 +269,7 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
码分复用需要发送的数据量为原先的 m 倍。
-
+
## CSMA/CD 协议
@@ -283,13 +283,13 @@ CSMA/CD 表示载波监听多点接入 / 碰撞检测。
当发生碰撞时,站点要停止发送,等待一段时间再发送。这个时间采用 **截断二进制指数退避算法** 来确定。从离散的整数集合 {0, 1, .., (2k -1)} 中随机取出一个数,记作 r,然后取 r 倍的争用期作为重传等待时间。
-
+
## PPP 协议
互联网用户通常需要连接到某个 ISP 之后才能接入到互联网,PPP 协议是用户计算机和 ISP 进行通信时所使用的数据链路层协议。
-
+
PPP 的帧格式:
@@ -298,7 +298,7 @@ PPP 的帧格式:
- FCS 字段是使用 CRC 的检验序列
- 信息部分的长度不超过 1500
-
+
## MAC 地址
@@ -314,7 +314,7 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
可以按照网络拓扑结构对局域网进行分类:
-
+
## 以太网
@@ -331,7 +331,7 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
- **FCS** :帧检验序列,使用的是 CRC 检验方法;
- **前同步码** :只是为了计算 FCS 临时加入的,计算结束之后会丢弃。
-
+
## 交换机
@@ -341,7 +341,7 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
下图中,交换机有 4 个接口,主机 A 向主机 B 发送数据帧时,交换机把主机 A 到接口 1 的映射写入交换表中。为了发送数据帧到 B,先查交换表,此时没有主机 B 的表项,那么主机 A 就发送广播帧,主机 C 和主机 D 会丢弃该帧。主机 B 收下之后,查找交换表得到主机 A 映射的接口为 1,就发送数据帧到接口 1,同时交换机添加主机 B 到接口 3 的映射。
-
+
## 虚拟局域网
@@ -351,7 +351,7 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
使用 VLAN 干线连接来建立虚拟局域网,每台交换机上的一个特殊接口被设置为干线接口,以互连 VLAN 交换机。IEEE 定义了一种扩展的以太网帧格式 802.1Q,它在标准以太网帧上加进了 4 字节首部 VLAN 标签,用于表示该帧属于哪一个虚拟局域网。
-
+
# 四、网络层
@@ -361,7 +361,7 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
使用 IP 协议,可以把异构的物理网络连接起来,使得在网络层看起来好像是一个统一的网络。
-
+
与 IP 协议配套使用的还有三个协议:
@@ -369,11 +369,11 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
- 网际控制报文协议 ICMP(Internet Control Message Protocol)
- 网际组管理协议 IGMP(Internet Group Management Protocol)
-
+
## IP 数据报格式
-
+
- **版本** : 有 4(IPv4)和 6(IPv6)两个值;
@@ -393,7 +393,7 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
- **片偏移** : 和标识符一起,用于发生分片的情况。片偏移的单位为 8 字节。
-
+
## IP 地址编址方式
@@ -409,7 +409,7 @@ IP 地址的编址方式经历了三个历史阶段:
IP 地址 ::= {< 网络号 >, < 主机号 >}
-
+
### 2. 子网划分
@@ -439,27 +439,27 @@ CIDR 的地址掩码可以继续称为子网掩码,子网掩码首 1 长度为
网络层实现主机之间的通信,而链路层实现具体每段链路之间的通信。因此在通信过程中,IP 数据报的源地址和目的地址始终不变,而 MAC 地址随着链路的改变而改变。
-
+
ARP 实现由 IP 地址得到 MAC 地址。
-
+
每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到 MAC 地址的映射表。
如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到 MAC 地址的映射。
-
+
## 网际控制报文协议 ICMP
ICMP 是为了更有效地转发 IP 数据报和提高交付成功的机会。它封装在 IP 数据报中,但是不属于高层协议。
-
+
ICMP 报文分为差错报告报文和询问报文。
-
+
### 1. Ping
@@ -492,7 +492,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
下图中,场所 A 和 B 的通信经过互联网,如果场所 A 的主机 X 要和另一个场所 B 的主机 Y 通信,IP 数据报的源地址是 10.1.0.1,目的地址是 10.2.0.3。数据报先发送到与互联网相连的路由器 R1,R1 对内部数据进行加密,然后重新加上数据报的首部,源地址是路由器 R1 的全球地址 125.1.2.3,目的地址是路由器 R2 的全球地址 194.4.5.6。路由器 R2 收到数据报后将数据部分进行解密,恢复原来的数据报,此时目的地址为 10.2.0.3,就交付给 Y。
-
+
## 网络地址转换 NAT
@@ -500,7 +500,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
在以前,NAT 将本地 IP 和全球 IP 一一对应,这种方式下拥有 n 个全球 IP 地址的专用网内最多只可以同时有 n 台主机接入互联网。为了更有效地利用全球 IP 地址,现在常用的 NAT 转换表把传输层的端口号也用上了,使得多个专用网内部的主机共用一个全球 IP 地址。使用端口号的 NAT 也叫做网络地址与端口转换 NAPT。
-
+
## 路由器的结构
@@ -508,7 +508,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
分组转发结构由三个部分组成:交换结构、一组输入端口和一组输出端口。
-
+
## 路由器分组转发流程
@@ -519,7 +519,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
- 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;
- 报告转发分组出错。
-
+
## 路由选择协议
@@ -576,7 +576,7 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
每个 AS 都必须配置 BGP 发言人,通过在两个相邻 BGP 发言人之间建立 TCP 连接来交换路由信息。
-
+
# 五、传输层
@@ -590,13 +590,13 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
## UDP 首部格式
-
+
首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。
## TCP 首部格式
-
+
- **序号** :用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。
@@ -614,7 +614,7 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
## TCP 的三次握手
-
+
假设 A 为客户端,B 为服务器端。
@@ -636,7 +636,7 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
## TCP 的四次挥手
-
+
以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。
@@ -684,7 +684,7 @@ TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文
接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {34, 35} 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。
-
+
## TCP 流量控制
@@ -696,7 +696,7 @@ TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文
如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
-
+
TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
@@ -707,7 +707,7 @@ TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、
- 接收方有足够大的接收缓存,因此不会发生流量控制;
- 虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。
-
+
### 1. 慢开始与拥塞避免
@@ -727,7 +727,7 @@ TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、
慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。
-
+
# 六、应用层
@@ -737,7 +737,7 @@ DNS 是一个分布式数据库,提供了主机名和 IP 地址之间相互转
域名具有层次结构,从上到下依次为:根域名、顶级域名、二级域名。
-
+
DNS 可以使用 UDP 或者 TCP 进行传输,使用的端口号都为 53。大多数情况下 DNS 使用 UDP 进行传输,这就要求域名解析器和域名服务器都必须自己处理超时和重传来保证可靠性。在两种情况下会使用 TCP 进行传输:
@@ -755,11 +755,11 @@ FTP 使用 TCP 进行连接,它需要两个连接来传送一个文件:
- 主动模式:服务器端主动建立数据连接,其中服务器端的端口号为 20,客户端的端口号随机,但是必须大于 1024,因为 0\~1023 是熟知端口号。
-
+
- 被动模式:客户端主动建立数据连接,其中客户端的端口号由客户端自己指定,服务器端的端口号随机。
-
+
主动模式要求客户端开放端口号给服务器端,需要去配置客户端的防火墙。被动模式只需要服务器端开放端口号即可,无需客户端配置防火墙。但是被动模式会导致服务器端的安全性减弱,因为开放了过多的端口号。
@@ -776,7 +776,7 @@ DHCP 工作过程如下:
3. 如果客户端选择了某个 DHCP 服务器提供的信息,那么就发送 Request 报文给该 DHCP 服务器。
4. DHCP 服务器发送 Ack 报文,表示客户端此时可以使用提供给它的信息。
-
+
## 远程登录协议
@@ -790,13 +790,13 @@ TELNET 可以适应许多计算机和操作系统的差异,例如不同操作
邮件协议包含发送协议和读取协议,发送协议常用 SMTP,读取协议常用 POP3 和 IMAP。
-
+
### 1. SMTP
SMTP 只能发送 ASCII 码,而互联网邮件扩充 MIME 可以发送二进制文件。MIME 并没有改动或者取代 SMTP,而是增加邮件主体的结构,定义了非 ASCII 码的编码规则。
-
+
### 2. POP3
diff --git a/docs/notes/设计模式.md b/docs/notes/设计模式.md
index 4e1be4c6..c83a888f 100644
--- a/docs/notes/设计模式.md
+++ b/docs/notes/设计模式.md
@@ -54,7 +54,7 @@
私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。
-
+
### Implementation
@@ -255,7 +255,7 @@ secondName
这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。
-
+
### Implementation
@@ -338,7 +338,7 @@ public class Client {
下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
-
+
### Implementation
@@ -402,7 +402,7 @@ public class ConcreteFactory2 extends Factory {
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承。
-
+
### Implementation
@@ -492,7 +492,7 @@ public class Client {
### Class Diagram
-
+
### Implementation
@@ -582,7 +582,7 @@ abcdefghijklmnopqrstuvwxyz
### Class Diagram
-
+
### Implementation
@@ -643,7 +643,7 @@ abc
- Handler:定义处理请求的接口,并且实现后继链(successor)
-
+
### Implementation
@@ -781,13 +781,13 @@ request2 is handle by ConcreteHandler2
- Invoker:通过它来调用命令
- Client:可以设置命令与命令的接收者
-
+
### Implementation
设计一个遥控器,可以控制电灯开关。
-
+
```java
public interface Command {
@@ -902,7 +902,7 @@ public class Client {
- TerminalExpression:终结符表达式,每个终结符都需要一个 TerminalExpression。
- Context:上下文,包含解释器之外的一些全局信息。
-
+
### Implementation
@@ -1027,7 +1027,7 @@ false
- Iterator 主要定义了 hasNext() 和 next() 方法。
- Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。
-
+
### Implementation
@@ -1116,17 +1116,17 @@ public class Client {
- Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。
- Colleague:同事,相关对象
-
+
### Implementation
Alarm(闹钟)、CoffeePot(咖啡壶)、Calendar(日历)、Sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构:
-
+
使用中介者模式可以将复杂的依赖结构变成星形结构:
-
+
```java
public abstract class Colleague {
@@ -1286,7 +1286,7 @@ doSprinkler()
- Caretaker:负责保存好备忘录
- Menento:备忘录,存储原始对象的的状态。备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
-
+
### Implementation
@@ -1459,7 +1459,7 @@ public class Client {
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。
-
+
### Class Diagram
@@ -1467,13 +1467,13 @@ public class Client {
观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。
-
+
### Implementation
天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。
-
+
```java
public interface Subject {
@@ -1594,13 +1594,13 @@ StatisticsDisplay.update: 1.0 1.0 1.0
### Class Diagram
-
+
### Implementation
糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。
-
+
```java
public interface State {
@@ -1901,7 +1901,7 @@ No gumball dispensed
- Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。
-
+
### 与状态模式的比较
@@ -1988,13 +1988,13 @@ quack!
### Class Diagram
-
+
### Implementation
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。
-
+
```java
public abstract class CaffeineBeverage {
@@ -2091,7 +2091,7 @@ Tea.addCondiments
- ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
- ObjectStructure:对象结构,可以是组合结构,或者是一个集合。
-
+
### Implementation
@@ -2296,7 +2296,7 @@ Number of items: 6
### Class Diagram
-
+
### Implementation
@@ -2348,11 +2348,11 @@ public class Client {
把一个类接口转换成另一个用户需要的接口。
-
+
### Class Diagram
-
+
### Implementation
@@ -2424,7 +2424,7 @@ public class Client {
- Abstraction:定义抽象类的接口
- Implementor:定义实现类接口
-
+
### Implementation
@@ -2582,7 +2582,7 @@ public class Client {
组合对象拥有一个或者多个组件对象,因此组合对象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。
-
+
### Implementation
@@ -2714,7 +2714,7 @@ Composite:root
装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。
-
+
### Implementation
@@ -2722,7 +2722,7 @@ Composite:root
下图表示在 DarkRoast 饮料上新增新添加 Mocha 配料,之后又添加了 Whip 配料。DarkRoast 被 Mocha 包裹,Mocha 又被 Whip 包裹。它们都继承自相同父类,都有 cost() 方法,外层类的 cost() 方法调用了内层类的 cost() 方法。
-
+
```java
public interface Beverage {
@@ -2820,7 +2820,7 @@ public class Client {
### Class Diagram
-
+
### Implementation
@@ -2879,7 +2879,7 @@ public class Client {
- IntrinsicState:内部状态,享元对象共享内部状态
- ExtrinsicState:外部状态,每个享元对象的外部状态不同
-
+
### Implementation
@@ -2968,7 +2968,7 @@ Java 利用缓存来加速大量小对象的访问时间。
- 保护代理(Protection Proxy):按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。
- 智能代理(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作:记录对象的引用次数;当第一次引用一个对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。
-
+
### Implementation
diff --git a/docs/notes/重构.md b/docs/notes/重构.md
index e90fa84e..7f22460d 100644
--- a/docs/notes/重构.md
+++ b/docs/notes/重构.md
@@ -126,7 +126,7 @@
包括三个类:Movie、Rental 和 Customer。
-
+
最开始的实现是把所有的计费代码都放在 Customer 类中。可以发现,该代码没有使用 Customer 类中的任何信息,更多的是使用 Rental 类的信息,因此第一个可以重构的点就是把具体计费的代码移到 Rental 类中,然后 Customer 类的 getTotalCharge() 方法只需要调用 Rental 类中的计费方法即可。
@@ -220,19 +220,19 @@ public class App {
以下是继承 Movie 的多态解决方案,这种方案可以解决上述的 switch 问题,因为每种电影类别的计费方式都被放到了对应 Movie 子类中,当变化发生时,只需要去修改对应子类中的代码即可。
-
+
有一条设计原则指示应该多用组合少用继承,这是因为组合比继承具有更高的灵活性。例如上面的继承方案,一部电影要改变它的计费方式,就要改变它所属的类,但是对象所属的类在编译时期就确定了,无法在运行过程中改变。(运行时多态可以在运行过程中改变一个父类引用指向的子类对象,但是无法改变一个对象所属的类。)
策略模式就是使用组合替代继承的一种解决方案。引入 Price 类,它有多种实现。Movie 组合了一个 Price 对象,并且在运行时可以改变组合的 Price 对象,从而使得它的计费方式发生改变。
-
+
重构后整体的类图和时序图如下:
-
+
-
+
重构后的代码:
@@ -833,7 +833,7 @@ Hide Delegate 有很大好处,但是它的代价是:每当客户要使用受
将该数据赋值到一个领域对象中,建立一个 Oberver 模式,用于同步领域对象和 GUI 对象内的重复数据。
-
+
## 7. 将单向关联改为双向关联
@@ -904,7 +904,7 @@ public 字段应当改为 private,并提供相应的访问函数。
类中有一个数值类型码,但它并不影响类的行为,就用一个新类替换该数值类型码。如果类型码出现在 switch 语句中,需要使用 Replace Conditional with Polymorphism 去掉 switch,首先必须运用 Replace Type Code with Subcalss 或 Replace Type Code with State/Strategy 去掉类型码。
-
+
## 14. 以子类取代类型码
@@ -912,7 +912,7 @@ public 字段应当改为 private,并提供相应的访问函数。
有一个不可变的类型码,它会影响类的行为,以子类取代这个类型码。
-
+
## 15. 以 State/Strategy 取代类型码
@@ -922,7 +922,7 @@ public 字段应当改为 private,并提供相应的访问函数。
和 Replace Type Code with Subcalsses 的区别是 Replace Type Code with State/Strategy 的类型码是动态可变的,前者通过继承的方式来实现,后者通过组合的方式来实现。因为类型码可变,如果通过继承的方式,一旦一个对象的类型码改变,那么就要改变用新的对象来取代旧对象,而客户端难以改变新的对象。但是通过组合的方式,改变引用的状态类是很容易的。
-
+
## 16. 以字段取代子类
@@ -930,7 +930,7 @@ public 字段应当改为 private,并提供相应的访问函数。
各个子类的唯一差别只在“返回常量数据”的函数上。
-
+
# 八、简化条件表达式
@@ -1064,7 +1064,7 @@ double getSpeed() {
}
```
-
+
## 7. 引入 Null 对象
@@ -1227,7 +1227,7 @@ double finalPrice = discountedPrice (basePrice);
以一个对象取代这些参数。
-
+
## 10. 移除设值函数
diff --git a/docs/notes/集群.md b/docs/notes/集群.md
index cd2af078..ee5a65d7 100644
--- a/docs/notes/集群.md
+++ b/docs/notes/集群.md
@@ -33,11 +33,11 @@
下图中,一共有 6 个客户端产生了 6 个请求,这 6 个请求按 (1, 2, 3, 4, 5, 6) 的顺序发送。(1, 3, 5) 的请求会被发送到服务器 1,(2, 4, 6) 的请求会被发送到服务器 2。
-
+
该算法比较适合每个服务器的性能差不多的场景,如果有性能存在差异的情况下,那么性能较差的服务器可能无法承担过大的负载(下图的 Server 2)。
-
+
### 2. 加权轮询(Weighted Round Robbin)
@@ -45,7 +45,7 @@
例如下图中,服务器 1 被赋予的权值为 5,服务器 2 被赋予的权值为 1,那么 (1, 2, 3, 4, 5) 请求会被发送到服务器 1,(6) 请求会被发送到服务器 2。
-
+
### 3. 最少连接(least Connections)
@@ -53,19 +53,19 @@
例如下图中,(1, 3, 5) 请求会被发送到服务器 1,但是 (1, 3) 很快就断开连接,此时只有 (5) 请求连接服务器 1;(2, 4, 6) 请求被发送到服务器 2,只有 (2) 的连接断开,此时 (6, 4) 请求连接服务器 2。该系统继续运行时,服务器 2 会承担过大的负载。
-
+
最少连接算法就是将请求发送给当前最少连接数的服务器上。
例如下图中,服务器 1 当前连接数最小,那么新到来的请求 6 就会被发送到服务器 1 上。
-
+
### 4. 加权最少连接(Weighted Least Connection)
在最少连接的基础上,根据服务器的性能为每台服务器分配权重,再根据权重计算出每台服务器能处理的连接数。
-
+
### 5. 随机算法(Random)
@@ -73,7 +73,7 @@
和轮询算法类似,该算法比较适合服务器性能差不多的场景。
-
+
### 6. 源地址哈希法 (IP Hash)
@@ -81,7 +81,7 @@
可以保证同一 IP 的客户端的请求会转发到同一台服务器上,用来实现会话粘滞(Sticky Session)
-
+
## 转发实现
@@ -96,7 +96,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
该负载均衡转发的缺点比较明显,实际场景中很少使用它。
-
+
### 2. DNS 域名解析
@@ -112,7 +112,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
大型网站基本使用了 DNS 做为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。也就是说,域名解析的结果为内部的负载均衡服务器 IP 地址。
-
+
### 3. 反向代理服务器
@@ -169,7 +169,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
- 当服务器宕机时,将丢失该服务器上的所有 Session。
-
+
## Session Replication
@@ -180,7 +180,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
- 占用过多内存;
- 同步过程占用网络带宽以及服务器处理器时间。
-
+
## Session Server
@@ -194,7 +194,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
- 需要去实现存取 Session 的代码。
-
+
参考:
diff --git a/docs/notes/面向对象思想.md b/docs/notes/面向对象思想.md
index 154e44a7..51bff5f7 100644
--- a/docs/notes/面向对象思想.md
+++ b/docs/notes/面向对象思想.md
@@ -130,7 +130,7 @@ public class Music {
用来描述继承关系,在 Java 中使用 extends 关键字。
-
+
```text
@startuml
@@ -151,7 +151,7 @@ Vihical <|-- Trunck
用来实现一个接口,在 Java 中使用 implements 关键字。
-
+
```text
@startuml
@@ -172,7 +172,7 @@ MoveBehavior <|.. Run
表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还是会存在。
-
+
```text
@startuml
@@ -195,7 +195,7 @@ Computer o-- Screen
和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在了。比如公司和部门,公司没了部门就不存在了。但是公司和员工就属于聚合关系了,因为公司没了员工还在。
-
+
```text
@startuml
@@ -216,7 +216,7 @@ Company *-- DepartmentB
表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定。
-
+
```text
@startuml
@@ -239,7 +239,7 @@ School "1" - "n" Student
- A 类是 B 类方法当中的一个参数;
- A 类向 B 类发送消息,从而影响 B 类发生变化。
-
+
```text
@startuml
diff --git a/docs1/docs/.nojekyll b/docs1/docs/.nojekyll
new file mode 100644
index 00000000..e69de29b
diff --git a/docs1/docs/README.md b/docs1/docs/README.md
new file mode 100644
index 00000000..2f646ca9
--- /dev/null
+++ b/docs1/docs/README.md
@@ -0,0 +1,84 @@
+| Ⅰ | Ⅱ | Ⅲ | Ⅳ | Ⅴ | Ⅵ | Ⅶ | Ⅷ | Ⅸ | Ⅹ |
+| :----------------------------: | :--------------------------------------: | :------------------------: | :----------------------------------: | :----------------------------------------: | :---------------------------: | :------------------------------: | :--------------------------: | :------------------------------------------------: | :----------------------: |
+| 算法[:pencil2:](#pencil2-算法) | 操作系统[:computer:](#computer-操作系统) | 网络[:cloud:](#cloud-网络) | 面向对象[:couple:](#couple-面向对象) | 数据库[:floppy_disk:](#floppy_disk-数据库) | Java [:coffee:](#coffee-java) | 系统设计[:bulb:](#bulb-系统设计) | 工具[:hammer:](#hammer-工具) | 编码实践[:speak_no_evil:](#speak_no_evil-编码实践) | 后记[:memo:](#memo-后记) |
+
+
+#### About
+
+本仓库主要是根据计算机经典书籍以及官方技术文档进行总结的学习笔记,希望对大家有所帮助。
+
+学习笔记不是从网上到处拼凑而来,除了少部分引用书上和技术文档的原文,其余都是笔者的原创。在您引用本仓库内容或者对内容进行修改演绎时,请遵循文末的开源协议,谢谢。
+
+#### How To Contribute
+
+笔记内容是笔者一个字一个字打上去的,难免会有一些笔误,如果发现笔误可直接对相应文档进行编辑修改。
+
+如果想要提交一个仓库现在还没有的全新内容,可以先将相应的文档放到 other 目录下。
+
+欢迎在 Issue 中提交对本仓库的改进建议~
+
+#### BookList
+
+本仓库参考的书目:[BOOKLIST](https://github.com/CyC2018/Interview-Notebook/blob/master/BOOKLIST.md)。
+
+#### Typesetting
+
+笔记内容按照 [中文文案排版指北](https://mazhuang.org/wiki/chinese-copywriting-guidelines/) 进行排版,以保证内容的可读性。
+
+笔记不使用 `![]()` 这种方式来引用图片,而是用 ` ` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 GFM 不支持 ` ![]() ` 让图片居中显示,只能使用 `` 达到居中的效果。
+
+笔者将自己实现的文档排版功能提取出来,放在 Github Page 中,无需下载安装即可免费使用:[Text-Typesetting](https://github.com/CyC2018/Markdown-Typesetting)。
+
+#### Uploading
+
+笔者在本地使用为知笔记软件进行书写,为了方便将本地笔记内容上传到 Github 上,实现了一整套自动化上传方案,包括文本文件的导出、提取图片、Markdown 文档转换、Git 同步。
+
+进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。
+
+笔者将自己实现文档转换功能提取出来,方便大家在需要将本地 Markdown 上传到 Github,或者制作项目 README 文档时生成目录时使用:[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
+
+#### Logo
+
+Power by [logomakr](https://logomakr.com/).
+
+#### Statement
+
+本仓库不参与商业行为,不向读者收取任何费用。(This repository is not engaging in business activities, and does not charge readers any fee.)
+
+#### Acknowledgements
+
+感谢以下人员对本仓库做出的贡献,当然不仅仅只有这些贡献者,这里就不一一列举了。如果你希望被添加到这个名单中,并且提交过 Issue 或者 PR,请与笔者联系。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### License
+
+在对本作品进行演绎时,请署名并以相同方式共享。
+
+
\ No newline at end of file
diff --git a/docs1/docs/_coverpage.md b/docs1/docs/_coverpage.md
new file mode 100644
index 00000000..32719dd9
--- /dev/null
+++ b/docs1/docs/_coverpage.md
@@ -0,0 +1,15 @@
+
+
+# CS-Notes
+
+> Computer Sicence Learning Notes.
+
+- Algorithm
+- Computer Networks
+- Operating System
+- ...
+
+[GitHub](https://github.com/CyC2018/CS-Notes)
+
+
+
diff --git a/docs1/docs/_media/LogoMakr_1J56bI.png b/docs1/docs/_media/LogoMakr_1J56bI.png
new file mode 100644
index 00000000..8fdee22a
Binary files /dev/null and b/docs1/docs/_media/LogoMakr_1J56bI.png differ
diff --git a/docs1/docs/_media/logomakr-3sxxzw-128x128.png b/docs1/docs/_media/logomakr-3sxxzw-128x128.png
new file mode 100644
index 00000000..80092a94
Binary files /dev/null and b/docs1/docs/_media/logomakr-3sxxzw-128x128.png differ
diff --git a/docs1/docs/_navbar.md b/docs1/docs/_navbar.md
new file mode 100644
index 00000000..47a2356a
--- /dev/null
+++ b/docs1/docs/_navbar.md
@@ -0,0 +1,6 @@
+- Translations
+ - [:uk: English](/)
+ - [:cn: 中文](/zh-cn/)
+ - [:de: Deutsch](/de-de/)
+ - [:es: Spanish](/es/)
+ - [:ru: Russian](/ru/)
diff --git a/docs1/docs/_sidebar.md b/docs1/docs/_sidebar.md
new file mode 100644
index 00000000..a0fd729a
--- /dev/null
+++ b/docs1/docs/_sidebar.md
@@ -0,0 +1,53 @@
+- :pencil2: 算法
+
+ - [剑指 Offer 题解](notes/剑指%20offer%20题解.md)
+ - [Leetcode 题解](notes/Leetcode%20题解)
+ - [算法](notes/算法.md)
+
+- :computer: 操作系统
+
+ - [计算机操作系统](notes/计算机操作系统.md)
+ - [Linux](notes/Linux.md)
+
+- :cloud: 网络
+
+ - [计算机网络](notes/计算机网络.md)
+ - [HTTP](notes/HTTP.md)
+ - [Sockets](notes/Sockets.md)
+
+- :couple: 面向对象
+
+ - [设计模式](notes/设计模式.md)
+ - [面向对象思想](notes/面向对象思想.md)
+
+- :floppy_disk: 数据库
+
+ - [数据库系统原理](notes/数据库系统原理.md)
+ - [SQL](notes/SQL.md)
+ - [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md)
+ - [MySQL](notes/MySQL.md)
+ - [Redis](notes/Redis.md)
+
+- :coffee: Java
+
+ - [Java 基础](notes/Java%20基础.md)
+ - [Java 容器](notes/Java%20容器.md)
+ - [Java 并发](notes/Java%20并发.md)
+ - [Java 虚拟机](notes/Java%20虚拟机.md)
+ - [Java I/O](notes/Java%20IO.md)
+
+- :bulb: 系统设计
+
+ - [系统设计基础](notes/系统设计基础.md)
+ - [分布式](notes/分布式.md)
+ - [集群](notes/集群.md)
+ - [攻击技术](notes/攻击技术.md)
+ - [缓存](notes/缓存.md)
+ - [消息队列](notes/消息队列.md)
+
+- :hammer:工具
+
+ - [Git](notes/Git.md)
+ - [Docker](notes/Docker.md)
+ - [正则表达式](notes/正则表达式.md)
+ - [构建工具](notes/构建工具.md)
diff --git a/docs1/docs/guide.md b/docs1/docs/guide.md
new file mode 100644
index 00000000..1fa6a742
--- /dev/null
+++ b/docs1/docs/guide.md
@@ -0,0 +1 @@
+# test
\ No newline at end of file
diff --git a/docs1/docs/index.html b/docs1/docs/index.html
new file mode 100644
index 00000000..e875a412
--- /dev/null
+++ b/docs1/docs/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+
+
+ Github
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs1/docs/notes/Docker.md b/docs1/docs/notes/Docker.md
new file mode 100644
index 00000000..1b61a7fe
--- /dev/null
+++ b/docs1/docs/notes/Docker.md
@@ -0,0 +1,91 @@
+
+* [一、解决的问题](#一解决的问题)
+* [二、与虚拟机的比较](#二与虚拟机的比较)
+* [三、优势](#三优势)
+* [四、使用场景](#四使用场景)
+* [五、镜像与容器](#五镜像与容器)
+* [参考资料](#参考资料)
+
+
+
+
+
+# 一、解决的问题
+
+由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环境配置操作。
+
+Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其他机器中。
+
+# 二、与虚拟机的比较
+
+虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
+
+
+
+
+
+## 启动速度
+
+启动虚拟机需要启动虚拟机的操作系统,再启动应用,这个过程非常慢;
+
+而启动 Docker 相当于启动宿主操作系统上的一个进程。
+
+## 占用资源
+
+虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU,一台机器只能开启几十个的虚拟机。
+
+而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。
+
+# 三、优势
+
+除了启动速度快以及占用资源少之外,Docker 具有以下优势:
+
+## 更容易迁移
+
+提供一致性的运行环境,可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。
+
+## 更容易维护
+
+使用分层技术和镜像,使得应用可以更容易复用重复部分。复用程度越高,维护工作也越容易。
+
+## 更容易扩展
+
+可以使用基础镜像进一步扩展得到新的镜像,并且官方和开源社区提供了大量的镜像,通过扩展这些镜像可以非常容易得到我们想要的镜像。
+
+# 四、使用场景
+
+## 持续集成
+
+持续集成指的是频繁地将代码集成到主干上,这样能够更快地发现错误。
+
+Docker 具有轻量级以及隔离性的特点,在将代码集成到一个 Docker 中不会对其它 Docker 产生影响。
+
+## 提供可伸缩的云服务
+
+根据应用的负载情况,可以很容易地增加或者减少 Docker。
+
+## 搭建微服务架构
+
+Docker 轻量级的特点使得它很适合用于部署、维护、组合微服务。
+
+# 五、镜像与容器
+
+镜像是一种静态的结构,可以看成面向对象里面的类,而容器是镜像的一个实例。
+
+镜像包含着容器运行时所需要的代码以及其它组件,它是一种分层结构,每一层都是只读的(read-only layers)。构建镜像时,会一层一层构建,前一层是后一层的基础。镜像的这种分层存储结构很适合镜像的复用以及定制。
+
+构建容器时,通过在镜像的基础上添加一个可写层(writable layer),用来保存着容器运行过程中的修改。
+
+
+
+# 参考资料
+
+- [DOCKER 101: INTRODUCTION TO DOCKER WEBINAR RECAP](https://blog.docker.com/2017/08/docker-101-introduction-docker-webinar-recap/)
+- [Docker 入门教程](http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html)
+- [Docker container vs Virtual machine](http://www.bogotobogo.com/DevOps/Docker/Docker_Container_vs_Virtual_Machine.php)
+- [How to Create Docker Container using Dockerfile](https://linoxide.com/linux-how-to/dockerfile-create-docker-container/)
+- [理解 Docker(2):Docker 镜像](http://www.cnblogs.com/sammyliu/p/5877964.html)
+- [为什么要使用 Docker?](https://yeasy.gitbooks.io/docker_practice/introduction/why.html)
+- [What is Docker](https://www.docker.com/what-docker)
+- [持续集成是什么?](http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html)
+
diff --git a/docs1/docs/notes/Git.md b/docs1/docs/notes/Git.md
new file mode 100644
index 00000000..4d4cbb2b
--- /dev/null
+++ b/docs1/docs/notes/Git.md
@@ -0,0 +1,158 @@
+
+* [集中式与分布式](#集中式与分布式)
+* [中心服务器](#中心服务器)
+* [工作流](#工作流)
+* [分支实现](#分支实现)
+* [冲突](#冲突)
+* [Fast forward](#fast-forward)
+* [分支管理策略](#分支管理策略)
+* [储藏(Stashing)](#储藏stashing)
+* [SSH 传输设置](#ssh-传输设置)
+* [.gitignore 文件](#gitignore-文件)
+* [Git 命令一览](#git-命令一览)
+* [参考资料](#参考资料)
+
+
+
+# 集中式与分布式
+
+Git 属于分布式版本控制系统,而 SVN 属于集中式。
+
+集中式版本控制只有中心服务器拥有一份代码,而分布式版本控制每个人的电脑上就有一份完整的代码。
+
+集中式版本控制有安全性问题,当中心服务器挂了所有人都没办法工作了。
+
+集中式版本控制需要连网才能工作,如果网速过慢,那么提交一个文件的会慢的无法让人忍受。而分布式版本控制不需要连网就能工作。
+
+分布式版本控制新建分支、合并分支操作速度非常快,而集中式版本控制新建一个分支相当于复制一份完整代码。
+
+# 中心服务器
+
+中心服务器用来交换每个用户的修改,没有中心服务器也能工作,但是中心服务器能够 24 小时保持开机状态,这样就能更方便的交换修改。
+
+Github 就是一个中心服务器。
+
+# 工作流
+
+
+
+新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git,它属于 Git 的版本库。
+
+Git 版本库有一个称为 stage 的暂存区,还有自动创建的 master 分支以及指向分支的 HEAD 指针。
+
+
+
+- git add files 把文件的修改添加到暂存区
+- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
+- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
+- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
+
+
+
+可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
+
+- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
+- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
+
+# 分支实现
+
+使用指针将每个提交连接成一条时间线,HEAD 指针指向当前分支指针。
+
+
+
+新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
+
+
+
+每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
+
+
+
+合并分支也只需要改变指针即可。
+
+
+
+# 冲突
+
+当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
+
+
+
+Git 会使用 <<<<<<< ,======= ,>>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
+
+```
+<<<<<<< HEAD
+Creating a new branch is quick & simple.
+=======
+Creating a new branch is quick AND simple.
+>>>>>>> feature1
+```
+
+# Fast forward
+
+"快进式合并"(fast-farward merge),会直接将 master 分支指向合并的分支,这种模式下进行分支合并会丢失分支信息,也就不能在分支历史上看出分支信息。
+
+可以在合并时加上 --no-ff 参数来禁用 Fast forward 模式,并且加上 -m 参数让合并时产生一个新的 commit。
+
+```
+$ git merge --no-ff -m "merge with no-ff" dev
+```
+
+
+
+# 分支管理策略
+
+master 分支应该是非常稳定的,只用来发布新版本;
+
+日常开发在开发分支 dev 上进行。
+
+
+
+# 储藏(Stashing)
+
+在一个分支上操作之后,如果还没有将修改提交到分支上,此时进行切换分支,那么另一个分支上也能看到新的修改。这是因为所有分支都共用一个工作区的缘故。
+
+可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈上,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。
+
+```
+$ git stash
+Saved working directory and index state \ "WIP on master: 049d078 added the index file"
+HEAD is now at 049d078 added the index file (To restore them type "git stash apply")
+```
+
+该功能可以用于 bug 分支的实现。如果当前正在 dev 分支上进行开发,但是此时 master 上有个 bug 需要修复,但是 dev 分支上的开发还未完成,不想立即提交。在新建 bug 分支并切换到 bug 分支之前就需要使用 git stash 将 dev 分支的未提交修改储藏起来。
+
+# SSH 传输设置
+
+Git 仓库和 Github 中心仓库之间的传输是通过 SSH 加密。
+
+如果工作区下没有 .ssh 目录,或者该目录下没有 id_rsa 和 id_rsa.pub 这两个文件,可以通过以下命令来创建 SSH Key:
+
+```
+$ ssh-keygen -t rsa -C "youremail@example.com"
+```
+
+然后把公钥 id_rsa.pub 的内容复制到 Github "Account settings" 的 SSH Keys 中。
+
+# .gitignore 文件
+
+忽略以下文件:
+
+- 操作系统自动生成的文件,比如缩略图;
+- 编译生成的中间文件,比如 Java 编译产生的 .class 文件;
+- 自己的敏感信息,比如存放口令的配置文件。
+
+不需要全部自己编写,可以到 [https://github.com/github/gitignore](https://github.com/github/gitignore) 中进行查询。
+
+# Git 命令一览
+
+
+
+比较详细的地址:http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
+
+# 参考资料
+
+- [Git - 简明指南](http://rogerdudler.github.io/git-guide/index.zh.html)
+- [图解 Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)
+- [廖雪峰 : Git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
+- [Learn Git Branching](https://learngitbranching.js.org/)
diff --git a/docs1/docs/notes/HTTP.md b/docs1/docs/notes/HTTP.md
new file mode 100644
index 00000000..ffe01382
--- /dev/null
+++ b/docs1/docs/notes/HTTP.md
@@ -0,0 +1,891 @@
+
+* [一 、基础概念](#一-基础概念)
+ * [URL](#url)
+ * [请求和响应报文](#请求和响应报文)
+* [二、HTTP 方法](#二http-方法)
+ * [GET](#get)
+ * [HEAD](#head)
+ * [POST](#post)
+ * [PUT](#put)
+ * [PATCH](#patch)
+ * [DELETE](#delete)
+ * [OPTIONS](#options)
+ * [CONNECT](#connect)
+ * [TRACE](#trace)
+* [三、HTTP 状态码](#三http-状态码)
+ * [1XX 信息](#1xx-信息)
+ * [2XX 成功](#2xx-成功)
+ * [3XX 重定向](#3xx-重定向)
+ * [4XX 客户端错误](#4xx-客户端错误)
+ * [5XX 服务器错误](#5xx-服务器错误)
+* [四、HTTP 首部](#四http-首部)
+ * [通用首部字段](#通用首部字段)
+ * [请求首部字段](#请求首部字段)
+ * [响应首部字段](#响应首部字段)
+ * [实体首部字段](#实体首部字段)
+* [五、具体应用](#五具体应用)
+ * [连接管理](#连接管理)
+ * [Cookie](#cookie)
+ * [缓存](#缓存)
+ * [内容协商](#内容协商)
+ * [内容编码](#内容编码)
+ * [范围请求](#范围请求)
+ * [分块传输编码](#分块传输编码)
+ * [多部分对象集合](#多部分对象集合)
+ * [虚拟主机](#虚拟主机)
+ * [通信数据转发](#通信数据转发)
+* [六、HTTPs](#六https)
+ * [加密](#加密)
+ * [认证](#认证)
+ * [完整性保护](#完整性保护)
+ * [HTTPs 的缺点](#https-的缺点)
+* [七、HTTP/2.0](#七http20)
+ * [HTTP/1.x 缺陷](#http1x-缺陷)
+ * [二进制分帧层](#二进制分帧层)
+ * [服务端推送](#服务端推送)
+ * [首部压缩](#首部压缩)
+* [八、HTTP/1.1 新特性](#八http11-新特性)
+* [九、GET 和 POST 比较](#九get-和-post-比较)
+ * [作用](#作用)
+ * [参数](#参数)
+ * [安全](#安全)
+ * [幂等性](#幂等性)
+ * [可缓存](#可缓存)
+ * [XMLHttpRequest](#xmlhttprequest)
+* [参考资料](#参考资料)
+
+
+
+# 一 、基础概念
+
+## URL
+
+URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基本都是 URL。
+
+- URI(Uniform Resource Identifier,统一资源标识符)
+- URL(Uniform Resource Locator,统一资源定位符)
+- URN(Uniform Resource Name,统一资源名称)
+
+
+
+## 请求和响应报文
+
+### 1. 请求报文
+
+
+
+### 2. 响应报文
+
+
+
+# 二、HTTP 方法
+
+客户端发送的 **请求报文** 第一行为请求行,包含了方法字段。
+
+## GET
+
+> 获取资源
+
+当前网络请求中,绝大部分使用的是 GET 方法。
+
+## HEAD
+
+> 获取报文首部
+
+和 GET 方法一样,但是不返回报文实体主体部分。
+
+主要用于确认 URL 的有效性以及资源更新的日期时间等。
+
+## POST
+
+> 传输实体主体
+
+POST 主要用来传输数据,而 GET 主要用来获取资源。
+
+更多 POST 与 GET 的比较请见第九章。
+
+## PUT
+
+> 上传文件
+
+由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。
+
+```html
+PUT /new.html HTTP/1.1
+Host: example.com
+Content-type: text/html
+Content-length: 16
+
+New File
+```
+
+## PATCH
+
+> 对资源进行部分修改
+
+PUT 也可以用于修改资源,但是只能完全替代原始资源,PATCH 允许部分修改。
+
+```html
+PATCH /file.txt HTTP/1.1
+Host: www.example.com
+Content-Type: application/example
+If-Match: "e0023aa4e"
+Content-Length: 100
+
+[description of changes]
+```
+
+## DELETE
+
+> 删除文件
+
+与 PUT 功能相反,并且同样不带验证机制。
+
+```html
+DELETE /file.html HTTP/1.1
+```
+
+## OPTIONS
+
+> 查询支持的方法
+
+查询指定的 URL 能够支持的方法。
+
+会返回 Allow: GET, POST, HEAD, OPTIONS 这样的内容。
+
+## CONNECT
+
+> 要求在与代理服务器通信时建立隧道
+
+使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。
+
+```html
+CONNECT www.example.com:443 HTTP/1.1
+```
+
+
+
+## TRACE
+
+> 追踪路径
+
+服务器会将通信路径返回给客户端。
+
+发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。
+
+通常不会使用 TRACE,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪)。
+# 三、HTTP 状态码
+
+服务器返回的 **响应报文** 中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。
+
+| 状态码 | 类别 | 原因短语 |
+| :---: | :---: | :---: |
+| 1XX | Informational(信息性状态码) | 接收的请求正在处理 |
+| 2XX | Success(成功状态码) | 请求正常处理完毕 |
+| 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
+| 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
+| 5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
+
+## 1XX 信息
+
+- **100 Continue** :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
+
+## 2XX 成功
+
+- **200 OK**
+
+- **204 No Content** :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
+
+- **206 Partial Content** :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。
+
+## 3XX 重定向
+
+- **301 Moved Permanently** :永久性重定向
+
+- **302 Found** :临时性重定向
+
+- **303 See Other** :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
+
+- 注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
+
+- **304 Not Modified** :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
+
+- **307 Temporary Redirect** :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
+
+## 4XX 客户端错误
+
+- **400 Bad Request** :请求报文中存在语法错误。
+
+- **401 Unauthorized** :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
+
+- **403 Forbidden** :请求被拒绝。
+
+- **404 Not Found**
+
+## 5XX 服务器错误
+
+- **500 Internal Server Error** :服务器正在执行请求时发生错误。
+
+- **503 Service Unavailable** :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
+
+# 四、HTTP 首部
+
+有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。
+
+各种首部字段及其含义如下(不需要全记,仅供查阅):
+
+## 通用首部字段
+
+| 首部字段名 | 说明 |
+| :--: | :--: |
+| Cache-Control | 控制缓存的行为 |
+| Connection | 控制不再转发给代理的首部字段、管理持久连接|
+| Date | 创建报文的日期时间 |
+| Pragma | 报文指令 |
+| Trailer | 报文末端的首部一览 |
+| Transfer-Encoding | 指定报文主体的传输编码方式 |
+| Upgrade | 升级为其他协议 |
+| Via | 代理服务器的相关信息 |
+| Warning | 错误通知 |
+
+## 请求首部字段
+
+| 首部字段名 | 说明 |
+| :--: | :--: |
+| Accept | 用户代理可处理的媒体类型 |
+| Accept-Charset | 优先的字符集 |
+| Accept-Encoding | 优先的内容编码 |
+| Accept-Language | 优先的语言(自然语言) |
+| Authorization | Web 认证信息 |
+| Expect | 期待服务器的特定行为 |
+| From | 用户的电子邮箱地址 |
+| Host | 请求资源所在服务器 |
+| If-Match | 比较实体标记(ETag) |
+| If-Modified-Since | 比较资源的更新时间 |
+| If-None-Match | 比较实体标记(与 If-Match 相反) |
+| If-Range | 资源未更新时发送实体 Byte 的范围请求 |
+| If-Unmodified-Since | 比较资源的更新时间(与 If-Modified-Since 相反) |
+| Max-Forwards | 最大传输逐跳数 |
+| Proxy-Authorization | 代理服务器要求客户端的认证信息 |
+| Range | 实体的字节范围请求 |
+| Referer | 对请求中 URI 的原始获取方 |
+| TE | 传输编码的优先级 |
+| User-Agent | HTTP 客户端程序的信息 |
+
+## 响应首部字段
+
+| 首部字段名 | 说明 |
+| :--: | :--: |
+| Accept-Ranges | 是否接受字节范围请求 |
+| Age | 推算资源创建经过时间 |
+| ETag | 资源的匹配信息 |
+| Location | 令客户端重定向至指定 URI |
+| Proxy-Authenticate | 代理服务器对客户端的认证信息 |
+| Retry-After | 对再次发起请求的时机要求 |
+| Server | HTTP 服务器的安装信息 |
+| Vary | 代理服务器缓存的管理信息 |
+| WWW-Authenticate | 服务器对客户端的认证信息 |
+
+## 实体首部字段
+
+| 首部字段名 | 说明 |
+| :--: | :--: |
+| Allow | 资源可支持的 HTTP 方法 |
+| Content-Encoding | 实体主体适用的编码方式 |
+| Content-Language | 实体主体的自然语言 |
+| Content-Length | 实体主体的大小 |
+| Content-Location | 替代对应资源的 URI |
+| Content-MD5 | 实体主体的报文摘要 |
+| Content-Range | 实体主体的位置范围 |
+| Content-Type | 实体主体的媒体类型 |
+| Expires | 实体主体过期的日期时间 |
+| Last-Modified | 资源的最后修改日期时间 |
+
+# 五、具体应用
+
+## 连接管理
+
+
+
+### 1. 短连接与长连接
+
+当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。
+
+长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。
+
+- 从 HTTP/1.1 开始默认是长连接的,如果要断开连接,需要由客户端或者服务器端提出断开,使用 `Connection : close`;
+- 在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用 `Connection : Keep-Alive`。
+
+### 2. 流水线
+
+默认情况下,HTTP 请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出。由于会受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。
+
+流水线是在同一条长连接上发出连续的请求,而不用等待响应返回,这样可以避免连接延迟。
+
+## Cookie
+
+HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。
+
+Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带 Cookie 数据,因此会带来额外的性能开销(尤其是在移动环境下)。
+
+Cookie 曾一度用于客户端数据的存储,因为当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。新的浏览器 API 已经允许开发者直接将数据存储到本地,如使用 Web storage API(本地存储和会话存储)或 IndexedDB。
+
+### 1. 用途
+
+- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
+- 个性化设置(如用户自定义设置、主题等)
+- 浏览器行为跟踪(如跟踪分析用户行为等)
+
+### 2. 创建过程
+
+服务器发送的响应报文包含 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。
+
+```html
+HTTP/1.0 200 OK
+Content-type: text/html
+Set-Cookie: yummy_cookie=choco
+Set-Cookie: tasty_cookie=strawberry
+
+[page content]
+```
+
+客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。
+
+```html
+GET /sample_page.html HTTP/1.1
+Host: www.example.org
+Cookie: yummy_cookie=choco; tasty_cookie=strawberry
+```
+
+### 3. 分类
+
+- 会话期 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。
+- 持久性 Cookie:指定一个特定的过期时间(Expires)或有效期(max-age)之后就成为了持久性的 Cookie。
+
+```html
+Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
+```
+
+### 4. 作用域
+
+Domain 标识指定了哪些主机可以接受 Cookie。如果不指定,默认为当前文档的主机(不包含子域名)。如果指定了 Domain,则一般包含子域名。例如,如果设置 Domain=mozilla.org,则 Cookie 也包含在子域名中(如 developer.mozilla.org)。
+
+Path 标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F ("/") 作为路径分隔符,子路径也会被匹配。例如,设置 Path=/docs,则以下地址都会匹配:
+
+- /docs
+- /docs/Web/
+- /docs/Web/HTTP
+
+### 5. JavaScript
+
+通过 `document.cookie` 属性可创建新的 Cookie,也可通过该属性访问非 HttpOnly 标记的 Cookie。
+
+```html
+document.cookie = "yummy_cookie=choco";
+document.cookie = "tasty_cookie=strawberry";
+console.log(document.cookie);
+```
+
+### 6. HttpOnly
+
+标记为 HttpOnly 的 Cookie 不能被 JavaScript 脚本调用。跨站脚本攻击 (XSS) 常常使用 JavaScript 的 `document.cookie` API 窃取用户的 Cookie 信息,因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击。
+
+```html
+Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
+```
+
+### 7. Secure
+
+标记为 Secure 的 Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障。
+
+### 8. Session
+
+除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。
+
+Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。
+
+使用 Session 维护用户登录状态的过程如下:
+
+- 用户进行登录时,用户提交包含用户名和密码的表单,放入 HTTP 请求报文中;
+- 服务器验证该用户名和密码,如果正确则把用户信息存储到 Redis 中,它在 Redis 中的 Key 称为 Session ID;
+- 服务器返回的响应报文的 Set-Cookie 首部字段包含了这个 Session ID,客户端收到响应报文之后将该 Cookie 值存入浏览器中;
+- 客户端之后对同一个服务器进行请求时会包含该 Cookie 值,服务器收到之后提取出 Session ID,从 Redis 中取出用户信息,继续之前的业务操作。
+
+应该注意 Session ID 的安全性问题,不能让它被恶意攻击者轻易获取,那么就不能产生一个容易被猜到的 Session ID 值。此外,还需要经常重新生成 Session ID。在对安全性要求极高的场景下,例如转账等操作,除了使用 Session 管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证码等方式。
+
+### 9. 浏览器禁用 Cookie
+
+此时无法使用 Cookie 来保存用户信息,只能使用 Session。除此之外,不能再将 Session ID 存放到 Cookie 中,而是使用 URL 重写技术,将 Session ID 作为 URL 的参数进行传递。
+
+### 10. Cookie 与 Session 选择
+
+- Cookie 只能存储 ASCII 码字符串,而 Session 则可以存取任何类型的数据,因此在考虑数据复杂性时首选 Session;
+- Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密;
+- 对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。
+
+## 缓存
+
+### 1. 优点
+
+- 缓解服务器压力;
+- 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存在地理位置上也有可能比源服务器来得近,例如浏览器缓存。
+
+### 2. 实现方法
+
+- 让代理服务器进行缓存;
+- 让客户端浏览器进行缓存。
+
+### 3. Cache-Control
+
+HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。
+
+**3.1 禁止进行缓存**
+
+no-store 指令规定不能对请求或响应的任何一部分进行缓存。
+
+```html
+Cache-Control: no-store
+```
+
+**3.2 强制确认缓存**
+
+no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效才将能使用该缓存对客户端的请求进行响应。
+
+```html
+Cache-Control: no-cache
+```
+
+**3.3 私有缓存和公共缓存**
+
+private 指令规定了将资源作为私有缓存,只能被单独用户所使用,一般存储在用户浏览器中。
+
+```html
+Cache-Control: private
+```
+
+public 指令规定了将资源作为公共缓存,可以被多个用户所使用,一般存储在代理服务器中。
+
+```html
+Cache-Control: public
+```
+
+**3.4 缓存过期机制**
+
+max-age 指令出现在请求报文中,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。
+
+max-age 指令出现在响应报文中,表示缓存资源在缓存服务器中保存的时间。
+
+```html
+Cache-Control: max-age=31536000
+```
+
+Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。
+
+```html
+Expires: Wed, 04 Jul 2012 08:26:05 GMT
+```
+
+- 在 HTTP/1.1 中,会优先处理 max-age 指令;
+- 在 HTTP/1.0 中,max-age 指令会被忽略掉。
+
+### 4. 缓存验证
+
+需要先了解 ETag 首部字段的含义,它是资源的唯一标识。URL 不能唯一表示资源,例如 `http://www.google.com/` 有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。
+
+```html
+ETag: "82e22293907ce725faf67773957acd12"
+```
+
+可以将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到该请求后,判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致,如果一致则表示缓存资源有效,返回 304 Not Modified。
+
+```html
+If-None-Match: "82e22293907ce725faf67773957acd12"
+```
+
+Last-Modified 首部字段也可以用于缓存验证,它包含在源服务器发送的响应报文中,指示源服务器对资源的最后修改时间。但是它是一种弱校验器,因为只能精确到一秒,所以它通常作为 ETag 的备用方案。如果响应首部字段里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 OK。如果请求的资源从那时起未经修改,那么返回一个不带有消息主体的 304 Not Modified 响应。
+
+```html
+Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
+```
+
+```html
+If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
+```
+
+## 内容协商
+
+通过内容协商返回最合适的内容,例如根据浏览器的默认语言选择返回中文界面还是英文界面。
+
+### 1. 类型
+
+**1.1 服务端驱动型**
+
+客户端设置特定的 HTTP 首部字段,例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language,服务器根据这些字段返回特定的资源。
+
+它存在以下问题:
+
+- 服务器很难知道客户端浏览器的全部信息;
+- 客户端提供的信息相当冗长(HTTP/2 协议的首部压缩机制缓解了这个问题),并且存在隐私风险(HTTP 指纹识别技术);
+- 给定的资源需要返回不同的展现形式,共享缓存的效率会降低,而服务器端的实现会越来越复杂。
+
+**1.2 代理驱动型**
+
+服务器返回 300 Multiple Choices 或者 406 Not Acceptable,客户端从中选出最合适的那个资源。
+
+### 2. Vary
+
+```html
+Vary: Accept-Language
+```
+
+在使用内容协商的情况下,只有当缓存服务器中的缓存满足内容协商条件时,才能使用该缓存,否则应该向源服务器请求该资源。
+
+例如,一个客户端发送了一个包含 Accept-Language 首部字段的请求之后,源服务器返回的响应包含 `Vary: Accept-Language` 内容,缓存服务器对这个响应进行缓存之后,在客户端下一次访问同一个 URL 资源,并且 Accept-Language 与缓存中的对应的值相同时才会返回该缓存。
+
+## 内容编码
+
+内容编码将实体主体进行压缩,从而减少传输的数据量。
+
+常用的内容编码有:gzip、compress、deflate、identity。
+
+浏览器发送 Accept-Encoding 首部,其中包含有它所支持的压缩算法,以及各自的优先级。服务器则从中选择一种,使用该算法对响应的消息主体进行压缩,并且发送 Content-Encoding 首部来告知浏览器它选择了哪一种算法。由于该内容协商过程是基于编码类型来选择资源的展现形式的,在响应的 Vary 首部至少要包含 Content-Encoding。
+
+## 范围请求
+
+如果网络出现中断,服务器只发送了一部分数据,范围请求可以使得客户端只请求服务器未发送的那部分数据,从而避免服务器重新发送所有数据。
+
+### 1. Range
+
+在请求报文中添加 Range 首部字段指定请求的范围。
+
+```html
+GET /z4d4kWk.jpg HTTP/1.1
+Host: i.imgur.com
+Range: bytes=0-1023
+```
+
+请求成功的话服务器返回的响应包含 206 Partial Content 状态码。
+
+```html
+HTTP/1.1 206 Partial Content
+Content-Range: bytes 0-1023/146515
+Content-Length: 1024
+...
+(binary content)
+```
+
+### 2. Accept-Ranges
+
+响应首部字段 Accept-Ranges 用于告知客户端是否能处理范围请求,可以处理使用 bytes,否则使用 none。
+
+```html
+Accept-Ranges: bytes
+```
+
+### 3. 响应状态码
+
+- 在请求成功的情况下,服务器会返回 206 Partial Content 状态码。
+- 在请求的范围越界的情况下,服务器会返回 416 Requested Range Not Satisfiable 状态码。
+- 在不支持范围请求的情况下,服务器会返回 200 OK 状态码。
+
+## 分块传输编码
+
+Chunked Transfer Coding,可以把数据分割成多块,让浏览器逐步显示页面。
+
+## 多部分对象集合
+
+一份报文主体内可含有多种类型的实体同时发送,每个部分之间用 boundary 字段定义的分隔符进行分隔,每个部分都可以有首部字段。
+
+例如,上传多个表单时可以使用如下方式:
+
+```html
+Content-Type: multipart/form-data; boundary=AaB03x
+
+--AaB03x
+Content-Disposition: form-data; name="submit-name"
+
+Larry
+--AaB03x
+Content-Disposition: form-data; name="files"; filename="file1.txt"
+Content-Type: text/plain
+
+... contents of file1.txt ...
+--AaB03x--
+```
+
+## 虚拟主机
+
+HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,并且在逻辑上可以看成多个服务器。
+
+## 通信数据转发
+
+### 1. 代理
+
+代理服务器接受客户端的请求,并且转发给其它服务器。
+
+使用代理的主要目的是:
+
+- 缓存
+- 负载均衡
+- 网络访问控制
+- 访问日志记录
+
+代理服务器分为正向代理和反向代理两种:
+
+- 用户察觉得到正向代理的存在。
+
+
+
+- 而反向代理一般位于内部网络中,用户察觉不到。
+
+
+
+### 2. 网关
+
+与代理服务器不同的是,网关服务器会将 HTTP 转化为其它协议进行通信,从而请求其它非 HTTP 服务器的服务。
+
+### 3. 隧道
+
+使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。
+
+# 六、HTTPs
+
+HTTP 有以下安全性问题:
+
+- 使用明文进行通信,内容可能会被窃听;
+- 不验证通信方的身份,通信方的身份有可能遭遇伪装;
+- 无法证明报文的完整性,报文有可能遭篡改。
+
+HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是说 HTTPs 使用了隧道进行通信。
+
+通过使用 SSL,HTTPs 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
+
+
+
+## 加密
+
+### 1. 对称密钥加密
+
+对称密钥加密(Symmetric-Key Encryption),加密和解密使用同一密钥。
+
+- 优点:运算速度快;
+- 缺点:无法安全地将密钥传输给通信方。
+
+
+
+### 2.非对称密钥加密
+
+非对称密钥加密,又称公开密钥加密(Public-Key Encryption),加密和解密使用不同的密钥。
+
+公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。
+
+非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确。
+
+- 优点:可以更安全地将公开密钥传输给通信发送方;
+- 缺点:运算速度慢。
+
+
+
+### 3. HTTPs 采用的加密方式
+
+HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
+
+
+
+## 认证
+
+通过使用 **证书** 来对通信方进行认证。
+
+数字证书认证机构(CA,Certificate Authority)是客户端与服务器双方都可信赖的第三方机构。
+
+服务器的运营人员向 CA 提出公开密钥的申请,CA 在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定在一起。
+
+进行 HTTPs 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。
+
+通信开始时,客户端需要使用服务器的公开密钥将自己的私有密钥传输给服务器,之后再进行对称密钥加密。
+
+
+
+## 完整性保护
+
+SSL 提供报文摘要功能来进行完整性保护。
+
+HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。
+
+HTTPs 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。
+
+## HTTPs 的缺点
+
+- 因为需要进行加密解密等过程,因此速度会更慢;
+- 需要支付证书授权的高额费用。
+# 七、HTTP/2.0
+
+## HTTP/1.x 缺陷
+
+HTTP/1.x 实现简单是以牺牲性能为代价的:
+
+- 客户端需要使用多个连接才能实现并发和缩短延迟;
+- 不会压缩请求和响应首部,从而导致不必要的网络流量;
+- 不支持有效的资源优先级,致使底层 TCP 连接的利用率低下。
+
+## 二进制分帧层
+
+HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
+
+
+
+在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。
+
+- 一个数据流(Stream)都有一个唯一标识符和可选的优先级信息,用于承载双向信息。
+- 消息(Message)是与逻辑请求或响应对应的完整的一系列帧。
+- 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
+
+
+
+## 服务端推送
+
+HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
+
+
+
+## 首部压缩
+
+HTTP/1.1 的首部带有大量信息,而且每次都要重复发送。
+
+HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输。
+
+不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
+
+
+
+# 八、HTTP/1.1 新特性
+
+详细内容请见上文
+
+- 默认是长连接
+
+- 支持流水线
+
+- 支持同时打开多个 TCP 连接
+
+- 支持虚拟主机
+
+- 新增状态码 100
+
+- 支持分块传输编码
+
+- 新增缓存处理指令 max-age
+
+# 九、GET 和 POST 比较
+
+## 作用
+
+GET 用于获取资源,而 POST 用于传输实体主体。
+
+## 参数
+
+GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看。
+
+因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`,而空格会转换为 `%20`。POST 参考支持标准字符集。
+
+```
+GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
+```
+
+```
+POST /test/demo_form.asp HTTP/1.1
+Host: w3schools.com
+name1=value1&name2=value2
+```
+
+## 安全
+
+安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。
+
+GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。
+
+安全的方法除了 GET 之外还有:HEAD、OPTIONS。
+
+不安全的方法除了 POST 之外还有 PUT、DELETE。
+
+## 幂等性
+
+幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。
+
+所有的安全方法也都是幂等的。
+
+在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。
+
+GET /pageX HTTP/1.1 是幂等的,连续调用多次,客户端接收到的结果都是一样的:
+
+```
+GET /pageX HTTP/1.1
+GET /pageX HTTP/1.1
+GET /pageX HTTP/1.1
+GET /pageX HTTP/1.1
+```
+
+POST /add_row HTTP/1.1 不是幂等的,如果调用多次,就会增加多行记录:
+
+```
+POST /add_row HTTP/1.1 -> Adds a 1nd row
+POST /add_row HTTP/1.1 -> Adds a 2nd row
+POST /add_row HTTP/1.1 -> Adds a 3rd row
+```
+
+DELETE /idX/delete HTTP/1.1 是幂等的,即便不同的请求接收到的状态码不一样:
+
+```
+DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists
+DELETE /idX/delete HTTP/1.1 -> Returns 404 as it just got deleted
+DELETE /idX/delete HTTP/1.1 -> Returns 404
+```
+
+## 可缓存
+
+如果要对响应进行缓存,需要满足以下条件:
+
+- 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,POST 在多数情况下不可缓存的。
+- 响应报文的状态码是可缓存的,包括:200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。
+- 响应报文的 Cache-Control 首部字段没有指定不进行缓存。
+
+## XMLHttpRequest
+
+为了阐述 POST 和 GET 的另一个区别,需要先了解 XMLHttpRequest:
+
+> XMLHttpRequest 是一个 API,它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。XMLHttpRequest 在 AJAX 中被大量使用。
+
+- 在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做,例如火狐就不会。
+- 而 GET 方法 Header 和 Data 会一起发送。
+
+
+
+# 参考资料
+
+- 上野宣. 图解 HTTP[M]. 人民邮电出版社, 2014.
+- [MDN : HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP)
+- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
+- [htmlspecialchars](http://php.net/manual/zh/function.htmlspecialchars.php)
+- [Difference between file URI and URL in java](http://java2db.com/java-io/how-to-get-and-the-difference-between-file-uri-and-url-in-java)
+- [How to Fix SQL Injection Using Java PreparedStatement & CallableStatement](https://software-security.sans.org/developer-how-to/fix-sql-injection-in-java-using-prepared-callable-statement)
+- [浅谈 HTTP 中 Get 与 Post 的区别](https://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html)
+- [Are http:// and www really necessary?](https://www.webdancers.com/are-http-and-www-necesary/)
+- [HTTP (HyperText Transfer Protocol)](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html)
+- [Web-VPN: Secure Proxies with SPDY & Chrome](https://www.igvita.com/2011/12/01/web-vpn-secure-proxies-with-spdy-chrome/)
+- [File:HTTP persistent connection.svg](http://en.wikipedia.org/wiki/File:HTTP_persistent_connection.svg)
+- [Proxy server](https://en.wikipedia.org/wiki/Proxy_server)
+- [What Is This HTTPS/SSL Thing And Why Should You Care?](https://www.x-cart.com/blog/what-is-https-and-ssl.html)
+- [What is SSL Offloading?](https://securebox.comodo.com/ssl-sniffing/ssl-offloading/)
+- [Sun Directory Server Enterprise Edition 7.0 Reference - Key Encryption](https://docs.oracle.com/cd/E19424-01/820-4811/6ng8i26bn/index.html)
+- [An Introduction to Mutual SSL Authentication](https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication)
+- [The Difference Between URLs and URIs](https://danielmiessler.com/study/url-uri/)
+- [Cookie 与 Session 的区别](https://juejin.im/entry/5766c29d6be3ff006a31b84e#comment)
+- [COOKIE 和 SESSION 有什么区别](https://www.zhihu.com/question/19786827)
+- [Cookie/Session 的机制与安全](https://harttle.land/2015/08/10/cookie-session.html)
+- [HTTPS 证书原理](https://shijianan.com/2017/06/11/https/)
+- [What is the difference between a URI, a URL and a URN?](https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn)
+- [XMLHttpRequest](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest)
+- [XMLHttpRequest (XHR) Uses Multiple Packets for HTTP POST?](https://blog.josephscott.org/2009/08/27/xmlhttprequest-xhr-uses-multiple-packets-for-http-post/)
+- [Symmetric vs. Asymmetric Encryption – What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences)
+- [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2)
+- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
diff --git a/docs1/docs/notes/Java IO.md b/docs1/docs/notes/Java IO.md
new file mode 100644
index 00000000..1b857bc7
--- /dev/null
+++ b/docs1/docs/notes/Java IO.md
@@ -0,0 +1,620 @@
+
+* [一、概览](#一概览)
+* [二、磁盘操作](#二磁盘操作)
+* [三、字节操作](#三字节操作)
+ * [实现文件复制](#实现文件复制)
+ * [装饰者模式](#装饰者模式)
+* [四、字符操作](#四字符操作)
+ * [编码与解码](#编码与解码)
+ * [String 的编码方式](#string-的编码方式)
+ * [Reader 与 Writer](#reader-与-writer)
+ * [实现逐行输出文本文件的内容](#实现逐行输出文本文件的内容)
+* [五、对象操作](#五对象操作)
+ * [序列化](#序列化)
+ * [Serializable](#serializable)
+ * [transient](#transient)
+* [六、网络操作](#六网络操作)
+ * [InetAddress](#inetaddress)
+ * [URL](#url)
+ * [Sockets](#sockets)
+ * [Datagram](#datagram)
+* [七、NIO](#七nio)
+ * [流与块](#流与块)
+ * [通道与缓冲区](#通道与缓冲区)
+ * [缓冲区状态变量](#缓冲区状态变量)
+ * [文件 NIO 实例](#文件-nio-实例)
+ * [选择器](#选择器)
+ * [套接字 NIO 实例](#套接字-nio-实例)
+ * [内存映射文件](#内存映射文件)
+ * [对比](#对比)
+* [八、参考资料](#八参考资料)
+
+
+
+# 一、概览
+
+Java 的 I/O 大概可以分成以下几类:
+
+- 磁盘操作:File
+- 字节操作:InputStream 和 OutputStream
+- 字符操作:Reader 和 Writer
+- 对象操作:Serializable
+- 网络操作:Socket
+- 新的输入/输出:NIO
+
+# 二、磁盘操作
+
+File 类可以用于表示文件和目录的信息,但是它不表示文件的内容。
+
+递归地列出一个目录下所有文件:
+
+```java
+public static void listAllFiles(File dir) {
+ if (dir == null || !dir.exists()) {
+ return;
+ }
+ if (dir.isFile()) {
+ System.out.println(dir.getName());
+ return;
+ }
+ for (File file : dir.listFiles()) {
+ listAllFiles(file);
+ }
+}
+```
+
+从 Java7 开始,可以使用 Paths 和 Files 代替 File。
+
+# 三、字节操作
+
+## 实现文件复制
+
+```java
+public static void copyFile(String src, String dist) throws IOException {
+ FileInputStream in = new FileInputStream(src);
+ FileOutputStream out = new FileOutputStream(dist);
+
+ byte[] buffer = new byte[20 * 1024];
+ int cnt;
+
+ // read() 最多读取 buffer.length 个字节
+ // 返回的是实际读取的个数
+ // 返回 -1 的时候表示读到 eof,即文件尾
+ while ((cnt = in.read(buffer, 0, buffer.length)) != -1) {
+ out.write(buffer, 0, cnt);
+ }
+
+ in.close();
+ out.close();
+}
+```
+
+## 装饰者模式
+
+Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
+
+- InputStream 是抽象组件;
+- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
+- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
+
+
+
+实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
+
+```java
+FileInputStream fileInputStream = new FileInputStream(filePath);
+BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
+```
+
+DataInputStream 装饰者提供了对更多数据类型进行输入的操作,比如 int、double 等基本类型。
+
+# 四、字符操作
+
+## 编码与解码
+
+编码就是把字符转换为字节,而解码是把字节重新组合成字符。
+
+如果编码和解码过程使用不同的编码方式那么就出现了乱码。
+
+- GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节;
+- UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节;
+- UTF-16be 编码中,中文字符和英文字符都占 2 个字节。
+
+UTF-16be 中的 be 指的是 Big Endian,也就是大端。相应地也有 UTF-16le,le 指的是 Little Endian,也就是小端。
+
+Java 的内存编码使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,而是说 char 这种类型使用 UTF-16be 进行编码。char 类型占 16 位,也就是两个字节,Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。
+
+## String 的编码方式
+
+String 可以看成一个字符序列,可以指定一个编码方式将它编码为字节序列,也可以指定一个编码方式将一个字节序列解码为 String。
+
+```java
+String str1 = "中文";
+byte[] bytes = str1.getBytes("UTF-8");
+String str2 = new String(bytes, "UTF-8");
+System.out.println(str2);
+```
+
+在调用无参数 getBytes() 方法时,默认的编码方式不是 UTF-16be。双字节编码的好处是可以使用一个 char 存储中文和英文,而将 String 转为 bytes[] 字节数组就不再需要这个好处,因此也就不再需要双字节编码。getBytes() 的默认编码方式与平台有关,一般为 UTF-8。
+
+```java
+byte[] bytes = str1.getBytes();
+```
+
+## Reader 与 Writer
+
+不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符。但是在程序中操作的通常是字符形式的数据,因此需要提供对字符进行操作的方法。
+
+- InputStreamReader 实现从字节流解码成字符流;
+- OutputStreamWriter 实现字符流编码成为字节流。
+
+## 实现逐行输出文本文件的内容
+
+```java
+public static void readFileContent(String filePath) throws IOException {
+
+ FileReader fileReader = new FileReader(filePath);
+ BufferedReader bufferedReader = new BufferedReader(fileReader);
+
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ System.out.println(line);
+ }
+
+ // 装饰者模式使得 BufferedReader 组合了一个 Reader 对象
+ // 在调用 BufferedReader 的 close() 方法时会去调用 Reader 的 close() 方法
+ // 因此只要一个 close() 调用即可
+ bufferedReader.close();
+}
+```
+
+# 五、对象操作
+
+## 序列化
+
+序列化就是将一个对象转换成字节序列,方便存储和传输。
+
+- 序列化:ObjectOutputStream.writeObject()
+- 反序列化:ObjectInputStream.readObject()
+
+不会对静态变量进行序列化,因为序列化只是保存对象的状态,静态变量属于类的状态。
+
+## Serializable
+
+序列化的类需要实现 Serializable 接口,它只是一个标准,没有任何方法需要实现,但是如果不去实现它的话而进行序列化,会抛出异常。
+
+```java
+public static void main(String[] args) throws IOException, ClassNotFoundException {
+
+ A a1 = new A(123, "abc");
+ String objectFile = "file/a1";
+
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(objectFile));
+ objectOutputStream.writeObject(a1);
+ objectOutputStream.close();
+
+ ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(objectFile));
+ A a2 = (A) objectInputStream.readObject();
+ objectInputStream.close();
+ System.out.println(a2);
+}
+
+private static class A implements Serializable {
+
+ private int x;
+ private String y;
+
+ A(int x, String y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public String toString() {
+ return "x = " + x + " " + "y = " + y;
+ }
+}
+```
+
+## transient
+
+transient 关键字可以使一些属性不会被序列化。
+
+ArrayList 中存储数据的数组 elementData 是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。
+
+```java
+private transient Object[] elementData;
+```
+
+# 六、网络操作
+
+Java 中的网络支持:
+
+- InetAddress:用于表示网络上的硬件资源,即 IP 地址;
+- URL:统一资源定位符;
+- Sockets:使用 TCP 协议实现网络通信;
+- Datagram:使用 UDP 协议实现网络通信。
+
+## InetAddress
+
+没有公有的构造函数,只能通过静态方法来创建实例。
+
+```java
+InetAddress.getByName(String host);
+InetAddress.getByAddress(byte[] address);
+```
+
+## URL
+
+可以直接从 URL 中读取字节流数据。
+
+```java
+public static void main(String[] args) throws IOException {
+
+ URL url = new URL("http://www.baidu.com");
+
+ /* 字节流 */
+ InputStream is = url.openStream();
+
+ /* 字符流 */
+ InputStreamReader isr = new InputStreamReader(is, "utf-8");
+
+ /* 提供缓存功能 */
+ BufferedReader br = new BufferedReader(isr);
+
+ String line;
+ while ((line = br.readLine()) != null) {
+ System.out.println(line);
+ }
+
+ br.close();
+}
+```
+
+## Sockets
+
+- ServerSocket:服务器端类
+- Socket:客户端类
+- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
+
+
+
+## Datagram
+
+- DatagramSocket:通信类
+- DatagramPacket:数据包类
+
+# 七、NIO
+
+新的输入/输出 (NIO) 库是在 JDK 1.4 中引入的,弥补了原来的 I/O 的不足,提供了高速的、面向块的 I/O。
+
+## 流与块
+
+I/O 与 NIO 最重要的区别是数据打包和传输的方式,I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
+
+面向流的 I/O 一次处理一个字节数据:一个输入流产生一个字节数据,一个输出流消费一个字节数据。为流式数据创建过滤器非常容易,链接几个过滤器,以便每个过滤器只负责复杂处理机制的一部分。不利的一面是,面向流的 I/O 通常相当慢。
+
+面向块的 I/O 一次处理一个数据块,按块处理数据比按流处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。
+
+I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重新实现了,所以现在它可以利用 NIO 的一些特性。例如,java.io.\* 包中的一些类包含以块的形式读写数据的方法,这使得即使在面向流的系统中,处理速度也会更快。
+
+## 通道与缓冲区
+
+### 1. 通道
+
+通道 Channel 是对原 I/O 包中的流的模拟,可以通过它读取和写入数据。
+
+通道与流的不同之处在于,流只能在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类),而通道是双向的,可以用于读、写或者同时用于读写。
+
+通道包括以下类型:
+
+- FileChannel:从文件中读写数据;
+- DatagramChannel:通过 UDP 读写网络中数据;
+- SocketChannel:通过 TCP 读写网络中数据;
+- ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。
+
+### 2. 缓冲区
+
+发送给一个通道的所有数据都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要先读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是要先经过缓冲区。
+
+缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
+
+缓冲区包括以下类型:
+
+- ByteBuffer
+- CharBuffer
+- ShortBuffer
+- IntBuffer
+- LongBuffer
+- FloatBuffer
+- DoubleBuffer
+
+## 缓冲区状态变量
+
+- capacity:最大容量;
+- position:当前已经读写的字节数;
+- limit:还可以读写的字节数。
+
+状态变量的改变过程举例:
+
+① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
+
+
+
+② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5,limit 保持不变。
+
+
+
+③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。
+
+
+
+④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
+
+
+
+⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
+
+
+
+## 文件 NIO 实例
+
+以下展示了使用 NIO 快速复制文件的实例:
+
+```java
+public static void fastCopy(String src, String dist) throws IOException {
+
+ /* 获得源文件的输入字节流 */
+ FileInputStream fin = new FileInputStream(src);
+
+ /* 获取输入字节流的文件通道 */
+ FileChannel fcin = fin.getChannel();
+
+ /* 获取目标文件的输出字节流 */
+ FileOutputStream fout = new FileOutputStream(dist);
+
+ /* 获取输出字节流的文件通道 */
+ FileChannel fcout = fout.getChannel();
+
+ /* 为缓冲区分配 1024 个字节 */
+ ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
+
+ while (true) {
+
+ /* 从输入通道中读取数据到缓冲区中 */
+ int r = fcin.read(buffer);
+
+ /* read() 返回 -1 表示 EOF */
+ if (r == -1) {
+ break;
+ }
+
+ /* 切换读写 */
+ buffer.flip();
+
+ /* 把缓冲区的内容写入输出文件中 */
+ fcout.write(buffer);
+
+ /* 清空缓冲区 */
+ buffer.clear();
+ }
+}
+```
+
+## 选择器
+
+NIO 常常被叫做非阻塞 IO,主要是因为 NIO 在网络通信中的非阻塞特性被广泛使用。
+
+NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用一个选择器 Selector 通过轮询的方式去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。
+
+通过配置监听的通道 Channel 为非阻塞,那么当 Channel 上的 IO 事件还未到达时,就不会进入阻塞状态一直等待,而是继续轮询其它 Channel,找到 IO 事件已经到达的 Channel 执行。
+
+因为创建和切换线程的开销很大,因此使用一个线程来处理多个事件而不是一个线程处理一个事件,对于 IO 密集型的应用具有很好地性能。
+
+应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
+
+
+
+### 1. 创建选择器
+
+```java
+Selector selector = Selector.open();
+```
+
+### 2. 将通道注册到选择器上
+
+```java
+ServerSocketChannel ssChannel = ServerSocketChannel.open();
+ssChannel.configureBlocking(false);
+ssChannel.register(selector, SelectionKey.OP_ACCEPT);
+```
+
+通道必须配置为非阻塞模式,否则使用选择器就没有任何意义了,因为如果通道在某个事件上被阻塞,那么服务器就不能响应其它事件,必须等待这个事件处理完毕才能去处理其它事件,显然这和选择器的作用背道而驰。
+
+在将通道注册到选择器上时,还需要指定要注册的具体事件,主要有以下几类:
+
+- SelectionKey.OP_CONNECT
+- SelectionKey.OP_ACCEPT
+- SelectionKey.OP_READ
+- SelectionKey.OP_WRITE
+
+它们在 SelectionKey 的定义如下:
+
+```java
+public static final int OP_READ = 1 << 0;
+public static final int OP_WRITE = 1 << 2;
+public static final int OP_CONNECT = 1 << 3;
+public static final int OP_ACCEPT = 1 << 4;
+```
+
+可以看出每个事件可以被当成一个位域,从而组成事件集整数。例如:
+
+```java
+int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
+```
+
+### 3. 监听事件
+
+```java
+int num = selector.select();
+```
+
+使用 select() 来监听到达的事件,它会一直阻塞直到有至少一个事件到达。
+
+### 4. 获取到达的事件
+
+```java
+Set keys = selector.selectedKeys();
+Iterator keyIterator = keys.iterator();
+while (keyIterator.hasNext()) {
+ SelectionKey key = keyIterator.next();
+ if (key.isAcceptable()) {
+ // ...
+ } else if (key.isReadable()) {
+ // ...
+ }
+ keyIterator.remove();
+}
+```
+
+### 5. 事件循环
+
+因为一次 select() 调用不能处理完所有的事件,并且服务器端有可能需要一直监听事件,因此服务器端处理事件的代码一般会放在一个死循环内。
+
+```java
+while (true) {
+ int num = selector.select();
+ Set keys = selector.selectedKeys();
+ Iterator keyIterator = keys.iterator();
+ while (keyIterator.hasNext()) {
+ SelectionKey key = keyIterator.next();
+ if (key.isAcceptable()) {
+ // ...
+ } else if (key.isReadable()) {
+ // ...
+ }
+ keyIterator.remove();
+ }
+}
+```
+
+## 套接字 NIO 实例
+
+```java
+public class NIOServer {
+
+ public static void main(String[] args) throws IOException {
+
+ Selector selector = Selector.open();
+
+ ServerSocketChannel ssChannel = ServerSocketChannel.open();
+ ssChannel.configureBlocking(false);
+ ssChannel.register(selector, SelectionKey.OP_ACCEPT);
+
+ ServerSocket serverSocket = ssChannel.socket();
+ InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
+ serverSocket.bind(address);
+
+ while (true) {
+
+ selector.select();
+ Set keys = selector.selectedKeys();
+ Iterator keyIterator = keys.iterator();
+
+ while (keyIterator.hasNext()) {
+
+ SelectionKey key = keyIterator.next();
+
+ if (key.isAcceptable()) {
+
+ ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();
+
+ // 服务器会为每个新连接创建一个 SocketChannel
+ SocketChannel sChannel = ssChannel1.accept();
+ sChannel.configureBlocking(false);
+
+ // 这个新连接主要用于从客户端读取数据
+ sChannel.register(selector, SelectionKey.OP_READ);
+
+ } else if (key.isReadable()) {
+
+ SocketChannel sChannel = (SocketChannel) key.channel();
+ System.out.println(readDataFromSocketChannel(sChannel));
+ sChannel.close();
+ }
+
+ keyIterator.remove();
+ }
+ }
+ }
+
+ private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {
+
+ ByteBuffer buffer = ByteBuffer.allocate(1024);
+ StringBuilder data = new StringBuilder();
+
+ while (true) {
+
+ buffer.clear();
+ int n = sChannel.read(buffer);
+ if (n == -1) {
+ break;
+ }
+ buffer.flip();
+ int limit = buffer.limit();
+ char[] dst = new char[limit];
+ for (int i = 0; i < limit; i++) {
+ dst[i] = (char) buffer.get(i);
+ }
+ data.append(dst);
+ buffer.clear();
+ }
+ return data.toString();
+ }
+}
+```
+
+```java
+public class NIOClient {
+
+ public static void main(String[] args) throws IOException {
+ Socket socket = new Socket("127.0.0.1", 8888);
+ OutputStream out = socket.getOutputStream();
+ String s = "hello world";
+ out.write(s.getBytes());
+ out.close();
+ }
+}
+```
+
+## 内存映射文件
+
+内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。
+
+向内存映射文件写入可能是危险的,只是改变数组的单个元素这样的简单操作,就可能会直接修改磁盘上的文件。修改数据与将数据保存到磁盘是没有分开的。
+
+下面代码行将文件的前 1024 个字节映射到内存中,map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,可以像使用其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行映射。
+
+```java
+MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
+```
+
+## 对比
+
+NIO 与普通 I/O 的区别主要有以下两点:
+
+- NIO 是非阻塞的;
+- NIO 面向块,I/O 面向流。
+
+# 八、参考资料
+
+- Eckel B, 埃克尔, 昊鹏, 等. Java 编程思想 [M]. 机械工业出版社, 2002.
+- [IBM: NIO 入门](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html)
+- [Java NIO Tutorial](http://tutorials.jenkov.com/java-nio/index.html)
+- [Java NIO 浅析](https://tech.meituan.com/nio.html)
+- [IBM: 深入分析 Java I/O 的工作机制](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html)
+- [IBM: 深入分析 Java 中的中文编码问题](https://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/index.html)
+- [IBM: Java 序列化的高级认识](https://www.ibm.com/developerworks/cn/java/j-lo-serial/index.html)
+- [NIO 与传统 IO 的区别](http://blog.csdn.net/shimiso/article/details/24990499)
+- [Decorator Design Pattern](http://stg-tud.github.io/sedc/Lecture/ws13-14/5.3-Decorator.html#mode=document)
+- [Socket Multicast](http://labojava.blogspot.com/2012/12/socket-multicast.html)
diff --git a/docs1/docs/notes/Java 基础.md b/docs1/docs/notes/Java 基础.md
new file mode 100644
index 00000000..6707cc28
--- /dev/null
+++ b/docs1/docs/notes/Java 基础.md
@@ -0,0 +1,1315 @@
+
+* [一、数据类型](#一数据类型)
+ * [包装类型](#包装类型)
+ * [缓存池](#缓存池)
+* [二、String](#二string)
+ * [概览](#概览)
+ * [不可变的好处](#不可变的好处)
+ * [String, StringBuffer and StringBuilder](#string,-stringbuffer-and-stringbuilder)
+ * [String Pool](#string-pool)
+ * [new String("abc")](#new-string"abc")
+* [三、运算](#三运算)
+ * [参数传递](#参数传递)
+ * [float 与 double](#float-与-double)
+ * [隐式类型转换](#隐式类型转换)
+ * [switch](#switch)
+* [四、继承](#四继承)
+ * [访问权限](#访问权限)
+ * [抽象类与接口](#抽象类与接口)
+ * [super](#super)
+ * [重写与重载](#重写与重载)
+* [五、Object 通用方法](#五object-通用方法)
+ * [概览](#概览)
+ * [equals()](#equals)
+ * [hashCode()](#hashcode)
+ * [toString()](#tostring)
+ * [clone()](#clone)
+* [六、关键字](#六关键字)
+ * [final](#final)
+ * [static](#static)
+* [七、反射](#七反射)
+* [八、异常](#八异常)
+* [九、泛型](#九泛型)
+* [十、注解](#十注解)
+* [十一、特性](#十一特性)
+ * [Java 各版本的新特性](#java-各版本的新特性)
+ * [Java 与 C++ 的区别](#java-与-c-的区别)
+ * [JRE or JDK](#jre-or-jdk)
+* [参考资料](#参考资料)
+
+
+
+# 一、数据类型
+
+## 包装类型
+
+八个基本类型:
+
+- boolean/1
+- byte/8
+- char/16
+- short/16
+- int/32
+- float/32
+- long/64
+- double/64
+
+基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
+
+```java
+Integer x = 2; // 装箱
+int y = x; // 拆箱
+```
+
+## 缓存池
+
+new Integer(123) 与 Integer.valueOf(123) 的区别在于:
+
+- new Integer(123) 每次都会新建一个对象;
+- Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
+
+```java
+Integer x = new Integer(123);
+Integer y = new Integer(123);
+System.out.println(x == y); // false
+Integer z = Integer.valueOf(123);
+Integer k = Integer.valueOf(123);
+System.out.println(z == k); // true
+```
+
+valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。
+
+```java
+public static Integer valueOf(int i) {
+ if (i >= IntegerCache.low && i <= IntegerCache.high)
+ return IntegerCache.cache[i + (-IntegerCache.low)];
+ return new Integer(i);
+}
+```
+
+在 Java 8 中,Integer 缓存池的大小默认为 -128\~127。
+
+```java
+static final int low = -128;
+static final int high;
+static final Integer cache[];
+
+static {
+ // high value may be configured by property
+ int h = 127;
+ String integerCacheHighPropValue =
+ sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
+ if (integerCacheHighPropValue != null) {
+ try {
+ int i = parseInt(integerCacheHighPropValue);
+ i = Math.max(i, 127);
+ // Maximum array size is Integer.MAX_VALUE
+ h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
+ } catch( NumberFormatException nfe) {
+ // If the property cannot be parsed into an int, ignore it.
+ }
+ }
+ high = h;
+
+ cache = new Integer[(high - low) + 1];
+ int j = low;
+ for(int k = 0; k < cache.length; k++)
+ cache[k] = new Integer(j++);
+
+ // range [-128, 127] must be interned (JLS7 5.1.7)
+ assert IntegerCache.high >= 127;
+}
+```
+
+编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。
+
+```java
+Integer m = 123;
+Integer n = 123;
+System.out.println(m == n); // true
+```
+
+基本类型对应的缓冲池如下:
+
+- boolean values true and false
+- all byte values
+- short values between -128 and 127
+- int values between -128 and 127
+- char in the range \u0000 to \u007F
+
+在使用这些基本类型对应的包装类型时,就可以直接使用缓冲池中的对象。
+
+[StackOverflow : Differences between new Integer(123), Integer.valueOf(123) and just 123
+](https://stackoverflow.com/questions/9030817/differences-between-new-integer123-integer-valueof123-and-just-123)
+
+# 二、String
+
+## 概览
+
+String 被声明为 final,因此它不可被继承。
+
+内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
+
+```java
+public final class String
+ implements java.io.Serializable, Comparable, CharSequence {
+ /** The value is used for character storage. */
+ private final char value[];
+```
+
+## 不可变的好处
+
+**1. 可以缓存 hash 值**
+
+因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
+
+**2. String Pool 的需要**
+
+如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
+
+
+
+**3. 安全性**
+
+String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。
+
+**4. 线程安全**
+
+String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
+
+[Program Creek : Why String is immutable in Java?](https://www.programcreek.com/2013/04/why-string-is-immutable-in-java/)
+
+## String, StringBuffer and StringBuilder
+
+**1. 可变性**
+
+- String 不可变
+- StringBuffer 和 StringBuilder 可变
+
+**2. 线程安全**
+
+- String 不可变,因此是线程安全的
+- StringBuilder 不是线程安全的
+- StringBuffer 是线程安全的,内部使用 synchronized 进行同步
+
+[StackOverflow : String, StringBuffer, and StringBuilder](https://stackoverflow.com/questions/2971315/string-stringbuffer-and-stringbuilder)
+
+## String Pool
+
+字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。
+
+当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
+
+下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同字符串,而 s3 和 s4 是通过 s1.intern() 方法取得一个字符串引用。intern() 首先把 s1 引用的字符串放到 String Pool 中,然后返回这个字符串引用。因此 s3 和 s4 引用的是同一个字符串。
+
+```java
+String s1 = new String("aaa");
+String s2 = new String("aaa");
+System.out.println(s1 == s2); // false
+String s3 = s1.intern();
+String s4 = s1.intern();
+System.out.println(s3 == s4); // true
+```
+
+如果是采用 "bbb" 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。
+
+```java
+String s5 = "bbb";
+String s6 = "bbb";
+System.out.println(s5 == s6); // true
+```
+
+在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。
+
+- [StackOverflow : What is String interning?](https://stackoverflow.com/questions/10578984/what-is-string-interning)
+- [深入解析 String#intern](https://tech.meituan.com/in_depth_understanding_string_intern.html)
+
+## new String("abc")
+
+使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 "abc" 字符串对象)。
+
+- "abc" 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,指向这个 "abc" 字符串字面量;
+- 而使用 new 的方式会在堆中创建一个字符串对象。
+
+创建一个测试类,其 main 方法中使用这种方式来创建字符串对象。
+
+```java
+public class NewStringTest {
+ public static void main(String[] args) {
+ String s = new String("abc");
+ }
+}
+```
+
+使用 javap -verbose 进行反编译,得到以下内容:
+
+```java
+// ...
+Constant pool:
+// ...
+ #2 = Class #18 // java/lang/String
+ #3 = String #19 // abc
+// ...
+ #18 = Utf8 java/lang/String
+ #19 = Utf8 abc
+// ...
+
+ public static void main(java.lang.String[]);
+ descriptor: ([Ljava/lang/String;)V
+ flags: ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=2, args_size=1
+ 0: new #2 // class java/lang/String
+ 3: dup
+ 4: ldc #3 // String abc
+ 6: invokespecial #4 // Method java/lang/String."":(Ljava/lang/String;)V
+ 9: astore_1
+// ...
+```
+
+在 Constant Pool 中,#19 存储这字符串字面量 "abc",#3 是 String Pool 的字符串对象,它指向 #19 这个字符串字面量。在 main 方法中,0: 行使用 new #2 在堆中创建一个字符串对象,并且使用 ldc #3 将 String Pool 中的字符串对象作为 String 构造函数的参数。
+
+以下是 String 构造函数的源码,可以看到,在将一个字符串对象作为另一个字符串对象的构造函数参数时,并不会完全复制 value 数组内容,而是都会指向同一个 value 数组。
+
+```java
+public String(String original) {
+ this.value = original.value;
+ this.hash = original.hash;
+}
+```
+
+# 三、运算
+
+## 参数传递
+
+Java 的参数是以值传递的形式传入方法中,而不是引用传递。
+
+以下代码中 Dog dog 的 dog 是一个指针,存储的是对象的地址。在将一个参数传入一个方法时,本质上是将对象的地址以值的方式传递到形参中。因此在方法中使指针引用其它对象,那么这两个指针此时指向的是完全不同的对象,在一方改变其所指向对象的内容时对另一方没有影响。
+
+```java
+public class Dog {
+
+ String name;
+
+ Dog(String name) {
+ this.name = name;
+ }
+
+ String getName() {
+ return this.name;
+ }
+
+ void setName(String name) {
+ this.name = name;
+ }
+
+ String getObjectAddress() {
+ return super.toString();
+ }
+}
+```
+
+```java
+public class PassByValueExample {
+ public static void main(String[] args) {
+ Dog dog = new Dog("A");
+ System.out.println(dog.getObjectAddress()); // Dog@4554617c
+ func(dog);
+ System.out.println(dog.getObjectAddress()); // Dog@4554617c
+ System.out.println(dog.getName()); // A
+ }
+
+ private static void func(Dog dog) {
+ System.out.println(dog.getObjectAddress()); // Dog@4554617c
+ dog = new Dog("B");
+ System.out.println(dog.getObjectAddress()); // Dog@74a14482
+ System.out.println(dog.getName()); // B
+ }
+}
+```
+
+如果在方法中改变对象的字段值会改变原对象该字段值,因为改变的是同一个地址指向的内容。
+
+```java
+class PassByValueExample {
+ public static void main(String[] args) {
+ Dog dog = new Dog("A");
+ func(dog);
+ System.out.println(dog.getName()); // B
+ }
+
+ private static void func(Dog dog) {
+ dog.setName("B");
+ }
+}
+```
+
+[StackOverflow: Is Java “pass-by-reference” or “pass-by-value”?](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value)
+
+## float 与 double
+
+Java 不能隐式执行向下转型,因为这会使得精度降低。
+
+1.1 字面量属于 double 类型,不能直接将 1.1 直接赋值给 float 变量,因为这是向下转型。
+
+```java
+// float f = 1.1;
+```
+
+1.1f 字面量才是 float 类型。
+
+```java
+float f = 1.1f;
+```
+
+## 隐式类型转换
+
+因为字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型。
+
+```java
+short s1 = 1;
+// s1 = s1 + 1;
+```
+
+但是使用 += 或者 ++ 运算符可以执行隐式类型转换。
+
+```java
+s1 += 1;
+// s1++;
+```
+
+上面的语句相当于将 s1 + 1 的计算结果进行了向下转型:
+
+```java
+s1 = (short) (s1 + 1);
+```
+
+[StackOverflow : Why don't Java's +=, -=, *=, /= compound assignment operators require casting?](https://stackoverflow.com/questions/8710619/why-dont-javas-compound-assignment-operators-require-casting)
+
+## switch
+
+从 Java 7 开始,可以在 switch 条件判断语句中使用 String 对象。
+
+```java
+String s = "a";
+switch (s) {
+ case "a":
+ System.out.println("aaa");
+ break;
+ case "b":
+ System.out.println("bbb");
+ break;
+}
+```
+
+switch 不支持 long,是因为 switch 的设计初衷是对那些只有少数的几个值进行等值判断,如果值过于复杂,那么还是用 if 比较合适。
+
+```java
+// long x = 111;
+// switch (x) { // Incompatible types. Found: 'long', required: 'char, byte, short, int, Character, Byte, Short, Integer, String, or an enum'
+// case 111:
+// System.out.println(111);
+// break;
+// case 222:
+// System.out.println(222);
+// break;
+// }
+```
+
+[StackOverflow : Why can't your switch statement data type be long, Java?](https://stackoverflow.com/questions/2676210/why-cant-your-switch-statement-data-type-be-long-java)
+
+# 四、继承
+
+## 访问权限
+
+Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。
+
+可以对类或类中的成员(字段以及方法)加上访问修饰符。
+
+- 类可见表示其它类可以用这个类创建实例对象。
+- 成员可见表示其它类可以用这个类的实例对象访问到该成员;
+
+protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。
+
+设计良好的模块会隐藏所有的实现细节,把它的 API 与它的实现清晰地隔离开来。模块之间只通过它们的 API 进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念被称为信息隐藏或封装。因此访问权限应当尽可能地使每个类或者成员不被外界访问。
+
+如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例,也就是确保满足里氏替换原则。
+
+字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。例如下面的例子中,AccessExample 拥有 id 公有字段,如果在某个时刻,我们想要使用 int 存储 id 字段,那么就需要修改所有的客户端代码。
+
+```java
+public class AccessExample {
+ public String id;
+}
+```
+
+可以使用公有的 getter 和 setter 方法来替换公有字段,这样的话就可以控制对字段的修改行为。
+
+
+```java
+public class AccessExample {
+
+ private int id;
+
+ public String getId() {
+ return id + "";
+ }
+
+ public void setId(String id) {
+ this.id = Integer.valueOf(id);
+ }
+}
+```
+
+但是也有例外,如果是包级私有的类或者私有的嵌套类,那么直接暴露成员不会有特别大的影响。
+
+```java
+public class AccessWithInnerClassExample {
+
+ private class InnerClass {
+ int x;
+ }
+
+ private InnerClass innerClass;
+
+ public AccessWithInnerClassExample() {
+ innerClass = new InnerClass();
+ }
+
+ public int getValue() {
+ return innerClass.x; // 直接访问
+ }
+}
+```
+
+## 抽象类与接口
+
+**1. 抽象类**
+
+抽象类和抽象方法都使用 abstract 关键字进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。
+
+抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。
+
+```java
+public abstract class AbstractClassExample {
+
+ protected int x;
+ private int y;
+
+ public abstract void func1();
+
+ public void func2() {
+ System.out.println("func2");
+ }
+}
+```
+
+```java
+public class AbstractExtendClassExample extends AbstractClassExample {
+ @Override
+ public void func1() {
+ System.out.println("func1");
+ }
+}
+```
+
+```java
+// AbstractClassExample ac1 = new AbstractClassExample(); // 'AbstractClassExample' is abstract; cannot be instantiated
+AbstractClassExample ac2 = new AbstractExtendClassExample();
+ac2.func1();
+```
+
+**2. 接口**
+
+接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
+
+从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。
+
+接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。
+
+接口的字段默认都是 static 和 final 的。
+
+```java
+public interface InterfaceExample {
+
+ void func1();
+
+ default void func2(){
+ System.out.println("func2");
+ }
+
+ int x = 123;
+ // int y; // Variable 'y' might not have been initialized
+ public int z = 0; // Modifier 'public' is redundant for interface fields
+ // private int k = 0; // Modifier 'private' not allowed here
+ // protected int l = 0; // Modifier 'protected' not allowed here
+ // private void fun3(); // Modifier 'private' not allowed here
+}
+```
+
+```java
+public class InterfaceImplementExample implements InterfaceExample {
+ @Override
+ public void func1() {
+ System.out.println("func1");
+ }
+}
+```
+
+```java
+// InterfaceExample ie1 = new InterfaceExample(); // 'InterfaceExample' is abstract; cannot be instantiated
+InterfaceExample ie2 = new InterfaceImplementExample();
+ie2.func1();
+System.out.println(InterfaceExample.x);
+```
+
+**3. 比较**
+
+- 从设计层面上看,抽象类提供了一种 IS-A 关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
+- 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
+- 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
+- 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。
+
+**4. 使用选择**
+
+使用接口:
+
+- 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable 接口中的 compareTo() 方法;
+- 需要使用多重继承。
+
+使用抽象类:
+
+- 需要在几个相关的类中共享代码。
+- 需要能控制继承来的成员的访问权限,而不是都为 public。
+- 需要继承非静态和非常量字段。
+
+在很多情况下,接口优先于抽象类。因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。并且从 Java 8 开始,接口也可以有默认的方法实现,使得修改接口的成本也变的很低。
+
+- [深入理解 abstract class 和 interface](https://www.ibm.com/developerworks/cn/java/l-javainterface-abstract/)
+- [When to Use Abstract Class and Interface](https://dzone.com/articles/when-to-use-abstract-class-and-intreface)
+
+## super
+
+- 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
+- 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。
+
+```java
+public class SuperExample {
+
+ protected int x;
+ protected int y;
+
+ public SuperExample(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public void func() {
+ System.out.println("SuperExample.func()");
+ }
+}
+```
+
+```java
+public class SuperExtendExample extends SuperExample {
+
+ private int z;
+
+ public SuperExtendExample(int x, int y, int z) {
+ super(x, y);
+ this.z = z;
+ }
+
+ @Override
+ public void func() {
+ super.func();
+ System.out.println("SuperExtendExample.func()");
+ }
+}
+```
+
+```java
+SuperExample e = new SuperExtendExample(1, 2, 3);
+e.func();
+```
+
+```html
+SuperExample.func()
+SuperExtendExample.func()
+```
+
+[Using the Keyword super](https://docs.oracle.com/javase/tutorial/java/IandI/super.html)
+
+## 重写与重载
+
+**1. 重写(Override)**
+
+存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
+
+为了满足里式替换原则,重写有有以下两个限制:
+
+- 子类方法的访问权限必须大于等于父类方法;
+- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
+
+使用 @Override 注解,可以让编译器帮忙检查是否满足上面的两个限制条件。
+
+**2. 重载(Overload)**
+
+存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。
+
+应该注意的是,返回值不同,其它都相同不算是重载。
+
+# 五、Object 通用方法
+
+## 概览
+
+```java
+
+public native int hashCode()
+
+public boolean equals(Object obj)
+
+protected native Object clone() throws CloneNotSupportedException
+
+public String toString()
+
+public final native Class> getClass()
+
+protected void finalize() throws Throwable {}
+
+public final native void notify()
+
+public final native void notifyAll()
+
+public final native void wait(long timeout) throws InterruptedException
+
+public final void wait(long timeout, int nanos) throws InterruptedException
+
+public final void wait() throws InterruptedException
+```
+
+## equals()
+
+**1. 等价关系**
+
+Ⅰ 自反性
+
+```java
+x.equals(x); // true
+```
+
+Ⅱ 对称性
+
+```java
+x.equals(y) == y.equals(x); // true
+```
+
+Ⅲ 传递性
+
+```java
+if (x.equals(y) && y.equals(z))
+ x.equals(z); // true;
+```
+
+Ⅳ 一致性
+
+多次调用 equals() 方法结果不变
+
+```java
+x.equals(y) == x.equals(y); // true
+```
+
+Ⅴ 与 null 的比较
+
+对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
+
+```java
+x.equals(null); // false;
+```
+
+**2. 等价与相等**
+
+- 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
+- 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
+
+```java
+Integer x = new Integer(1);
+Integer y = new Integer(1);
+System.out.println(x.equals(y)); // true
+System.out.println(x == y); // false
+```
+
+**3. 实现**
+
+- 检查是否为同一个对象的引用,如果是直接返回 true;
+- 检查是否是同一个类型,如果不是,直接返回 false;
+- 将 Object 对象进行转型;
+- 判断每个关键域是否相等。
+
+```java
+public class EqualExample {
+
+ private int x;
+ private int y;
+ private int z;
+
+ public EqualExample(int x, int y, int z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ EqualExample that = (EqualExample) o;
+
+ if (x != that.x) return false;
+ if (y != that.y) return false;
+ return z == that.z;
+ }
+}
+```
+
+## hashCode()
+
+hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
+
+在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。
+
+下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。
+
+```java
+EqualExample e1 = new EqualExample(1, 1, 1);
+EqualExample e2 = new EqualExample(1, 1, 1);
+System.out.println(e1.equals(e2)); // true
+HashSet set = new HashSet<>();
+set.add(e1);
+set.add(e2);
+System.out.println(set.size()); // 2
+```
+
+理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来。可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。
+
+一个数与 31 相乘可以转换成移位和减法:`31*x == (x<<5)-x`,编译器会自动进行这个优化。
+
+```java
+@Override
+public int hashCode() {
+ int result = 17;
+ result = 31 * result + x;
+ result = 31 * result + y;
+ result = 31 * result + z;
+ return result;
+}
+```
+
+## toString()
+
+默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。
+
+```java
+public class ToStringExample {
+
+ private int number;
+
+ public ToStringExample(int number) {
+ this.number = number;
+ }
+}
+```
+
+```java
+ToStringExample example = new ToStringExample(123);
+System.out.println(example.toString());
+```
+
+```html
+ToStringExample@4554617c
+```
+
+## clone()
+
+**1. cloneable**
+
+clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。
+
+```java
+public class CloneExample {
+ private int a;
+ private int b;
+}
+```
+
+```java
+CloneExample e1 = new CloneExample();
+// CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'
+```
+
+重写 clone() 得到以下实现:
+
+```java
+public class CloneExample {
+ private int a;
+ private int b;
+
+ @Override
+ public CloneExample clone() throws CloneNotSupportedException {
+ return (CloneExample)super.clone();
+ }
+}
+```
+
+```java
+CloneExample e1 = new CloneExample();
+try {
+ CloneExample e2 = e1.clone();
+} catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+}
+```
+
+```html
+java.lang.CloneNotSupportedException: CloneExample
+```
+
+以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。
+
+应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。
+
+```java
+public class CloneExample implements Cloneable {
+ private int a;
+ private int b;
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+}
+```
+
+**2. 浅拷贝**
+
+拷贝对象和原始对象的引用类型引用同一个对象。
+
+```java
+public class ShallowCloneExample implements Cloneable {
+
+ private int[] arr;
+
+ public ShallowCloneExample() {
+ arr = new int[10];
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = i;
+ }
+ }
+
+ public void set(int index, int value) {
+ arr[index] = value;
+ }
+
+ public int get(int index) {
+ return arr[index];
+ }
+
+ @Override
+ protected ShallowCloneExample clone() throws CloneNotSupportedException {
+ return (ShallowCloneExample) super.clone();
+ }
+}
+```
+
+```java
+ShallowCloneExample e1 = new ShallowCloneExample();
+ShallowCloneExample e2 = null;
+try {
+ e2 = e1.clone();
+} catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+}
+e1.set(2, 222);
+System.out.println(e2.get(2)); // 222
+```
+
+**3. 深拷贝**
+
+拷贝对象和原始对象的引用类型引用不同对象。
+
+```java
+public class DeepCloneExample implements Cloneable {
+
+ private int[] arr;
+
+ public DeepCloneExample() {
+ arr = new int[10];
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = i;
+ }
+ }
+
+ public void set(int index, int value) {
+ arr[index] = value;
+ }
+
+ public int get(int index) {
+ return arr[index];
+ }
+
+ @Override
+ protected DeepCloneExample clone() throws CloneNotSupportedException {
+ DeepCloneExample result = (DeepCloneExample) super.clone();
+ result.arr = new int[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ result.arr[i] = arr[i];
+ }
+ return result;
+ }
+}
+```
+
+```java
+DeepCloneExample e1 = new DeepCloneExample();
+DeepCloneExample e2 = null;
+try {
+ e2 = e1.clone();
+} catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+}
+e1.set(2, 222);
+System.out.println(e2.get(2)); // 2
+```
+
+**4. clone() 的替代方案**
+
+使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。
+
+```java
+public class CloneConstructorExample {
+
+ private int[] arr;
+
+ public CloneConstructorExample() {
+ arr = new int[10];
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = i;
+ }
+ }
+
+ public CloneConstructorExample(CloneConstructorExample original) {
+ arr = new int[original.arr.length];
+ for (int i = 0; i < original.arr.length; i++) {
+ arr[i] = original.arr[i];
+ }
+ }
+
+ public void set(int index, int value) {
+ arr[index] = value;
+ }
+
+ public int get(int index) {
+ return arr[index];
+ }
+}
+```
+
+```java
+CloneConstructorExample e1 = new CloneConstructorExample();
+CloneConstructorExample e2 = new CloneConstructorExample(e1);
+e1.set(2, 222);
+System.out.println(e2.get(2)); // 2
+```
+
+# 六、关键字
+
+## final
+
+**1. 数据**
+
+声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。
+
+- 对于基本类型,final 使数值不变;
+- 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
+
+```java
+final int x = 1;
+// x = 2; // cannot assign value to final variable 'x'
+final A y = new A();
+y.a = 1;
+```
+
+**2. 方法**
+
+声明方法不能被子类重写。
+
+private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。
+
+**3. 类**
+
+声明类不允许被继承。
+
+## static
+
+**1. 静态变量**
+
+- 静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
+- 实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。
+
+```java
+public class A {
+
+ private int x; // 实例变量
+ private static int y; // 静态变量
+
+ public static void main(String[] args) {
+ // int x = A.x; // Non-static field 'x' cannot be referenced from a static context
+ A a = new A();
+ int x = a.x;
+ int y = A.y;
+ }
+}
+```
+
+**2. 静态方法**
+
+静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
+
+```java
+public abstract class A {
+ public static void func1(){
+ }
+ // public abstract static void func2(); // Illegal combination of modifiers: 'abstract' and 'static'
+}
+```
+
+只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。
+
+```java
+public class A {
+
+ private static int x;
+ private int y;
+
+ public static void func1(){
+ int a = x;
+ // int b = y; // Non-static field 'y' cannot be referenced from a static context
+ // int b = this.y; // 'A.this' cannot be referenced from a static context
+ }
+}
+```
+
+**3. 静态语句块**
+
+静态语句块在类初始化时运行一次。
+
+```java
+public class A {
+ static {
+ System.out.println("123");
+ }
+
+ public static void main(String[] args) {
+ A a1 = new A();
+ A a2 = new A();
+ }
+}
+```
+
+```html
+123
+```
+
+**4. 静态内部类**
+
+非静态内部类依赖于外部类的实例,而静态内部类不需要。
+
+```java
+public class OuterClass {
+
+ class InnerClass {
+ }
+
+ static class StaticInnerClass {
+ }
+
+ public static void main(String[] args) {
+ // InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
+ OuterClass outerClass = new OuterClass();
+ InnerClass innerClass = outerClass.new InnerClass();
+ StaticInnerClass staticInnerClass = new StaticInnerClass();
+ }
+}
+```
+
+静态内部类不能访问外部类的非静态的变量和方法。
+
+**5. 静态导包**
+
+在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低。
+
+```java
+import static com.xxx.ClassName.*
+```
+
+**6. 初始化顺序**
+
+静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
+
+```java
+public static String staticField = "静态变量";
+```
+
+```java
+static {
+ System.out.println("静态语句块");
+}
+```
+
+```java
+public String field = "实例变量";
+```
+
+```java
+{
+ System.out.println("普通语句块");
+}
+```
+
+最后才是构造函数的初始化。
+
+```java
+public InitialOrderTest() {
+ System.out.println("构造函数");
+}
+```
+
+存在继承的情况下,初始化顺序为:
+
+- 父类(静态变量、静态语句块)
+- 子类(静态变量、静态语句块)
+- 父类(实例变量、普通语句块)
+- 父类(构造函数)
+- 子类(实例变量、普通语句块)
+- 子类(构造函数)
+
+
+# 七、反射
+
+每个类都有一个 **Class** 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
+
+类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用 `Class.forName("com.mysql.jdbc.Driver")` 这种方式来控制类的加载,该方法会返回一个 Class 对象。
+
+反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。
+
+Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
+
+- **Field** :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
+- **Method** :可以使用 invoke() 方法调用与 Method 对象关联的方法;
+- **Constructor** :可以用 Constructor 创建新的对象。
+
+**反射的优点:**
+
+* **可扩展性** :应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
+* **类浏览器和可视化开发环境** :一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
+* **调试器和测试工具** : 调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。
+
+**反射的缺点:**
+
+尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心。
+
+* **性能开销** :反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
+
+* **安全限制** :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
+
+* **内部暴露** :由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
+
+
+- [Trail: The Reflection API](https://docs.oracle.com/javase/tutorial/reflect/index.html)
+- [深入解析 Java 反射(1)- 基础](http://www.sczyh30.com/posts/Java/java-reflection-1/)
+
+# 八、异常
+
+Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: **Error** 和 **Exception**。其中 Error 用来表示 JVM 无法处理的错误,Exception 分为两种:
+
+- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
+- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
+
+
+
+- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
+- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
+
+# 九、泛型
+
+```java
+public class Box {
+ // T stands for "Type"
+ private T t;
+ public void set(T t) { this.t = t; }
+ public T get() { return t; }
+}
+```
+
+- [Java 泛型详解](http://www.importnew.com/24029.html)
+- [10 道 Java 泛型面试题](https://cloud.tencent.com/developer/article/1033693)
+
+# 十、注解
+
+Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
+
+[注解 Annotation 实现原理与自定义注解例子](https://www.cnblogs.com/acm-bingzi/p/javaAnnotation.html)
+
+# 十一、特性
+
+## Java 各版本的新特性
+
+**New highlights in Java SE 8**
+
+1. Lambda Expressions
+2. Pipelines and Streams
+3. Date and Time API
+4. Default Methods
+5. Type Annotations
+6. Nashhorn JavaScript Engine
+7. Concurrent Accumulators
+8. Parallel operations
+9. PermGen Error Removed
+
+**New highlights in Java SE 7**
+
+1. Strings in Switch Statement
+2. Type Inference for Generic Instance Creation
+3. Multiple Exception Handling
+4. Support for Dynamic Languages
+5. Try with Resources
+6. Java nio Package
+7. Binary Literals, Underscore in literals
+8. Diamond Syntax
+
+- [Difference between Java 1.8 and Java 1.7?](http://www.selfgrowth.com/articles/difference-between-java-18-and-java-17)
+- [Java 8 特性](http://www.importnew.com/19345.html)
+
+## Java 与 C++ 的区别
+
+- Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 即支持面向对象也支持面向过程。
+- Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
+- Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
+- Java 支持自动垃圾回收,而 C++ 需要手动回收。
+- Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
+- Java 不支持操作符重载,虽然可以对两个 String 对象执行加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。
+- Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。
+- Java 不支持条件编译,C++ 通过 #ifdef #ifndef 等预处理命令从而实现条件编译。
+
+[What are the main differences between Java and C++?](http://cs-fundamentals.com/tech-interview/java/differences-between-java-and-cpp.php)
+
+## JRE or JDK
+
+- JRE is the JVM program, Java application need to run on JRE.
+- JDK is a superset of JRE, JRE + tools for developing java programs. e.g, it provides the compiler "javac"
+
+# 参考资料
+
+- Eckel B. Java 编程思想[M]. 机械工业出版社, 2002.
+- Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.
diff --git a/docs1/docs/notes/Java 容器.md b/docs1/docs/notes/Java 容器.md
new file mode 100644
index 00000000..dbd41edc
--- /dev/null
+++ b/docs1/docs/notes/Java 容器.md
@@ -0,0 +1,1193 @@
+
+* [一、概览](#一概览)
+ * [Collection](#collection)
+ * [Map](#map)
+* [二、容器中的设计模式](#二容器中的设计模式)
+ * [迭代器模式](#迭代器模式)
+ * [适配器模式](#适配器模式)
+* [三、源码分析](#三源码分析)
+ * [ArrayList](#arraylist)
+ * [Vector](#vector)
+ * [CopyOnWriteArrayList](#copyonwritearraylist)
+ * [LinkedList](#linkedlist)
+ * [HashMap](#hashmap)
+ * [ConcurrentHashMap](#concurrenthashmap)
+ * [LinkedHashMap](#linkedhashmap)
+ * [WeakHashMap](#weakhashmap)
+* [附录](#附录)
+* [参考资料](#参考资料)
+
+
+
+# 一、概览
+
+容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。
+
+## Collection
+
+
+
+### 1. Set
+
+- TreeSet:基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。
+
+- HashSet:基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。
+
+- LinkedHashSet:具有 HashSet 的查找效率,且内部使用双向链表维护元素的插入顺序。
+
+### 2. List
+
+- ArrayList:基于动态数组实现,支持随机访问。
+
+- Vector:和 ArrayList 类似,但它是线程安全的。
+
+- LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。
+
+### 3. Queue
+
+- LinkedList:可以用它来实现双向队列。
+
+- PriorityQueue:基于堆结构实现,可以用它来实现优先队列。
+
+## Map
+
+
+
+- TreeMap:基于红黑树实现。
+
+- HashMap:基于哈希表实现。
+
+- HashTable:和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。它是遗留类,不应该去使用它。现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁。
+
+- LinkedHashMap:使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。
+
+
+# 二、容器中的设计模式
+
+## 迭代器模式
+
+
+
+Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
+
+从 JDK 1.5 之后可以使用 foreach 方法来遍历实现了 Iterable 接口的聚合对象。
+
+```java
+List list = new ArrayList<>();
+list.add("a");
+list.add("b");
+for (String item : list) {
+ System.out.println(item);
+}
+```
+
+## 适配器模式
+
+java.util.Arrays#asList() 可以把数组类型转换为 List 类型。
+
+```java
+@SafeVarargs
+public static List asList(T... a)
+```
+
+应该注意的是 asList() 的参数为泛型的变长参数,不能使用基本类型数组作为参数,只能使用相应的包装类型数组。
+
+```java
+Integer[] arr = {1, 2, 3};
+List list = Arrays.asList(arr);
+```
+
+也可以使用以下方式调用 asList():
+
+```java
+List list = Arrays.asList(1, 2, 3);
+```
+
+# 三、源码分析
+
+如果没有特别说明,以下源码分析基于 JDK 1.8。
+
+在 IDEA 中 double shift 调出 Search EveryWhere,查找源码文件,找到之后就可以阅读源码。
+
+## ArrayList
+
+### 1. 概览
+
+实现了 RandomAccess 接口,因此支持随机访问。这是理所当然的,因为 ArrayList 是基于数组实现的。
+
+```java
+public class ArrayList extends AbstractList
+ implements List, RandomAccess, Cloneable, java.io.Serializable
+```
+
+数组的默认大小为 10。
+
+```java
+private static final int DEFAULT_CAPACITY = 10;
+```
+
+### 2. 扩容
+
+添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够时,需要使用 grow() 方法进行扩容,新容量的大小为 `oldCapacity + (oldCapacity >> 1)`,也就是旧容量的 1.5 倍。
+
+扩容操作需要调用 `Arrays.copyOf()` 把原数组整个复制到新数组中,这个操作代价很高,因此最好在创建 ArrayList 对象时就指定大概的容量大小,减少扩容操作的次数。
+
+```java
+public boolean add(E e) {
+ ensureCapacityInternal(size + 1); // Increments modCount!!
+ elementData[size++] = e;
+ return true;
+}
+
+private void ensureCapacityInternal(int minCapacity) {
+ if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
+ minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
+ }
+ ensureExplicitCapacity(minCapacity);
+}
+
+private void ensureExplicitCapacity(int minCapacity) {
+ modCount++;
+ // overflow-conscious code
+ if (minCapacity - elementData.length > 0)
+ grow(minCapacity);
+}
+
+private void grow(int minCapacity) {
+ // overflow-conscious code
+ int oldCapacity = elementData.length;
+ int newCapacity = oldCapacity + (oldCapacity >> 1);
+ if (newCapacity - minCapacity < 0)
+ newCapacity = minCapacity;
+ if (newCapacity - MAX_ARRAY_SIZE > 0)
+ newCapacity = hugeCapacity(minCapacity);
+ // minCapacity is usually close to size, so this is a win:
+ elementData = Arrays.copyOf(elementData, newCapacity);
+}
+```
+
+### 3. 删除元素
+
+需要调用 System.arraycopy() 将 index+1 后面的元素都复制到 index 位置上,该操作的时间复杂度为 O(N),可以看出 ArrayList 删除元素的代价是非常高的。
+
+```java
+public E remove(int index) {
+ rangeCheck(index);
+ modCount++;
+ E oldValue = elementData(index);
+ int numMoved = size - index - 1;
+ if (numMoved > 0)
+ System.arraycopy(elementData, index+1, elementData, index, numMoved);
+ elementData[--size] = null; // clear to let GC do its work
+ return oldValue;
+}
+```
+
+### 4. Fail-Fast
+
+modCount 用来记录 ArrayList 结构发生变化的次数。结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化。
+
+在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了需要抛出 ConcurrentModificationException。
+
+```java
+private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException{
+ // Write out element count, and any hidden stuff
+ int expectedModCount = modCount;
+ s.defaultWriteObject();
+
+ // Write out size as capacity for behavioural compatibility with clone()
+ s.writeInt(size);
+
+ // Write out all elements in the proper order.
+ for (int i=0; i 0) {
+ // be like clone(), allocate array based upon size not capacity
+ ensureCapacityInternal(size);
+
+ Object[] a = elementData;
+ // Read in all elements in the proper order.
+ for (int i=0; i= elementCount)
+ throw new ArrayIndexOutOfBoundsException(index);
+
+ return elementData(index);
+}
+```
+
+### 2. 与 ArrayList 的比较
+
+- Vector 是同步的,因此开销就比 ArrayList 要大,访问速度更慢。最好使用 ArrayList 而不是 Vector,因为同步操作完全可以由程序员自己来控制;
+- Vector 每次扩容请求其大小的 2 倍空间,而 ArrayList 是 1.5 倍。
+
+### 3. 替代方案
+
+可以使用 `Collections.synchronizedList();` 得到一个线程安全的 ArrayList。
+
+```java
+List list = new ArrayList<>();
+List synList = Collections.synchronizedList(list);
+```
+
+也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。
+
+```java
+List list = new CopyOnWriteArrayList<>();
+```
+
+## CopyOnWriteArrayList
+
+### 读写分离
+
+写操作在一个复制的数组上进行,读操作还是在原始数组中进行,读写分离,互不影响。
+
+写操作需要加锁,防止并发写入时导致写入数据丢失。
+
+写操作结束之后需要把原始数组指向新的复制数组。
+
+```java
+public boolean add(E e) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ Object[] elements = getArray();
+ int len = elements.length;
+ Object[] newElements = Arrays.copyOf(elements, len + 1);
+ newElements[len] = e;
+ setArray(newElements);
+ return true;
+ } finally {
+ lock.unlock();
+ }
+}
+
+final void setArray(Object[] a) {
+ array = a;
+}
+```
+
+```java
+@SuppressWarnings("unchecked")
+private E get(Object[] a, int index) {
+ return (E) a[index];
+}
+```
+
+### 适用场景
+
+CopyOnWriteArrayList 在写操作的同时允许读操作,大大提高了读操作的性能,因此很适合读多写少的应用场景。
+
+但是 CopyOnWriteArrayList 有其缺陷:
+
+- 内存占用:在写操作时需要复制一个新的数组,使得内存占用为原来的两倍左右;
+- 数据不一致:读操作不能读取实时性的数据,因为部分写操作的数据还未同步到读数组中。
+
+所以 CopyOnWriteArrayList 不适合内存敏感以及对实时性要求很高的场景。
+
+## LinkedList
+
+### 1. 概览
+
+基于双向链表实现,使用 Node 存储链表节点信息。
+
+```java
+private static class Node {
+ E item;
+ Node next;
+ Node prev;
+}
+```
+
+每个链表存储了 first 和 last 指针:
+
+```java
+transient Node first;
+transient Node last;
+```
+
+
+
+### 2. 与 ArrayList 的比较
+
+- ArrayList 基于动态数组实现,LinkedList 基于双向链表实现;
+- ArrayList 支持随机访问,LinkedList 不支持;
+- LinkedList 在任意位置添加删除元素更快。
+
+## HashMap
+
+为了便于理解,以下源码分析以 JDK 1.7 为主。
+
+### 1. 存储结构
+
+内部包含了一个 Entry 类型的数组 table。
+
+```java
+transient Entry[] table;
+```
+
+Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
+
+
+
+```java
+static class Entry implements Map.Entry {
+ final K key;
+ V value;
+ Entry next;
+ int hash;
+
+ Entry(int h, K k, V v, Entry n) {
+ value = v;
+ next = n;
+ key = k;
+ hash = h;
+ }
+
+ public final K getKey() {
+ return key;
+ }
+
+ public final V getValue() {
+ return value;
+ }
+
+ public final V setValue(V newValue) {
+ V oldValue = value;
+ value = newValue;
+ return oldValue;
+ }
+
+ public final boolean equals(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry e = (Map.Entry)o;
+ Object k1 = getKey();
+ Object k2 = e.getKey();
+ if (k1 == k2 || (k1 != null && k1.equals(k2))) {
+ Object v1 = getValue();
+ Object v2 = e.getValue();
+ if (v1 == v2 || (v1 != null && v1.equals(v2)))
+ return true;
+ }
+ return false;
+ }
+
+ public final int hashCode() {
+ return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
+ }
+
+ public final String toString() {
+ return getKey() + "=" + getValue();
+ }
+}
+```
+
+### 2. 拉链法的工作原理
+
+```java
+HashMap map = new HashMap<>();
+map.put("K1", "V1");
+map.put("K2", "V2");
+map.put("K3", "V3");
+```
+
+- 新建一个 HashMap,默认大小为 16;
+- 插入 <K1,V1> 键值对,先计算 K1 的 hashCode 为 115,使用除留余数法得到所在的桶下标 115%16=3。
+- 插入 <K2,V2> 键值对,先计算 K2 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6。
+- 插入 <K3,V3> 键值对,先计算 K3 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6,插在 <K2,V2> 前面。
+
+应该注意到链表的插入是以头插法方式进行的,例如上面的 <K3,V3> 不是插在 <K2,V2> 后面,而是插入在链表头部。
+
+查找需要分成两步进行:
+
+- 计算键值对所在的桶;
+- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
+
+
+
+### 3. put 操作
+
+```java
+public V put(K key, V value) {
+ if (table == EMPTY_TABLE) {
+ inflateTable(threshold);
+ }
+ // 键为 null 单独处理
+ if (key == null)
+ return putForNullKey(value);
+ int hash = hash(key);
+ // 确定桶下标
+ int i = indexFor(hash, table.length);
+ // 先找出是否已经存在键为 key 的键值对,如果存在的话就更新这个键值对的值为 value
+ for (Entry e = table[i]; e != null; e = e.next) {
+ Object k;
+ if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
+ V oldValue = e.value;
+ e.value = value;
+ e.recordAccess(this);
+ return oldValue;
+ }
+ }
+
+ modCount++;
+ // 插入新键值对
+ addEntry(hash, key, value, i);
+ return null;
+}
+```
+
+HashMap 允许插入键为 null 的键值对。但是因为无法调用 null 的 hashCode() 方法,也就无法确定该键值对的桶下标,只能通过强制指定一个桶下标来存放。HashMap 使用第 0 个桶存放键为 null 的键值对。
+
+```java
+private V putForNullKey(V value) {
+ for (Entry e = table[0]; e != null; e = e.next) {
+ if (e.key == null) {
+ V oldValue = e.value;
+ e.value = value;
+ e.recordAccess(this);
+ return oldValue;
+ }
+ }
+ modCount++;
+ addEntry(0, null, value, 0);
+ return null;
+}
+```
+
+使用链表的头插法,也就是新的键值对插在链表的头部,而不是链表的尾部。
+
+```java
+void addEntry(int hash, K key, V value, int bucketIndex) {
+ if ((size >= threshold) && (null != table[bucketIndex])) {
+ resize(2 * table.length);
+ hash = (null != key) ? hash(key) : 0;
+ bucketIndex = indexFor(hash, table.length);
+ }
+
+ createEntry(hash, key, value, bucketIndex);
+}
+
+void createEntry(int hash, K key, V value, int bucketIndex) {
+ Entry e = table[bucketIndex];
+ // 头插法,链表头部指向新的键值对
+ table[bucketIndex] = new Entry<>(hash, key, value, e);
+ size++;
+}
+```
+
+```java
+Entry(int h, K k, V v, Entry n) {
+ value = v;
+ next = n;
+ key = k;
+ hash = h;
+}
+```
+
+### 4. 确定桶下标
+
+很多操作都需要先确定一个键值对所在的桶下标。
+
+```java
+int hash = hash(key);
+int i = indexFor(hash, table.length);
+```
+
+**4.1 计算 hash 值**
+
+```java
+final int hash(Object k) {
+ int h = hashSeed;
+ if (0 != h && k instanceof String) {
+ return sun.misc.Hashing.stringHash32((String) k);
+ }
+
+ h ^= k.hashCode();
+
+ // This function ensures that hashCodes that differ only by
+ // constant multiples at each bit position have a bounded
+ // number of collisions (approximately 8 at default load factor).
+ h ^= (h >>> 20) ^ (h >>> 12);
+ return h ^ (h >>> 7) ^ (h >>> 4);
+}
+```
+
+```java
+public final int hashCode() {
+ return Objects.hashCode(key) ^ Objects.hashCode(value);
+}
+```
+
+**4.2 取模**
+
+令 x = 1<<4,即 x 为 2 的 4 次方,它具有以下性质:
+
+```
+x : 00010000
+x-1 : 00001111
+```
+
+令一个数 y 与 x-1 做与运算,可以去除 y 位级表示的第 4 位以上数:
+
+```
+y : 10110010
+x-1 : 00001111
+y&(x-1) : 00000010
+```
+
+这个性质和 y 对 x 取模效果是一样的:
+
+```
+y : 10110010
+x : 00010000
+y%x : 00000010
+```
+
+我们知道,位运算的代价比求模运算小的多,因此在进行这种计算时用位运算的话能带来更高的性能。
+
+确定桶下标的最后一步是将 key 的 hash 值对桶个数取模:hash%capacity,如果能保证 capacity 为 2 的 n 次方,那么就可以将这个操作转换为位运算。
+
+```java
+static int indexFor(int h, int length) {
+ return h & (length-1);
+}
+```
+
+### 5. 扩容-基本原理
+
+设 HashMap 的 table 长度为 M,需要存储的键值对数量为 N,如果哈希函数满足均匀性的要求,那么每条链表的长度大约为 N/M,因此平均查找次数的复杂度为 O(N/M)。
+
+为了让查找的成本降低,应该尽可能使得 N/M 尽可能小,因此需要保证 M 尽可能大,也就是说 table 要尽可能大。HashMap 采用动态扩容来根据当前的 N 值来调整 M 值,使得空间效率和时间效率都能得到保证。
+
+和扩容相关的参数主要有:capacity、size、threshold 和 load_factor。
+
+| 参数 | 含义 |
+| :--: | :-- |
+| capacity | table 的容量大小,默认为 16。需要注意的是 capacity 必须保证为 2 的 n 次方。|
+| size | 键值对数量。 |
+| threshold | size 的临界值,当 size 大于等于 threshold 就必须进行扩容操作。 |
+| loadFactor | 装载因子,table 能够使用的比例,threshold = capacity * loadFactor。|
+
+```java
+static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+static final int MAXIMUM_CAPACITY = 1 << 30;
+
+static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+transient Entry[] table;
+
+transient int size;
+
+int threshold;
+
+final float loadFactor;
+
+transient int modCount;
+```
+
+从下面的添加元素代码中可以看出,当需要扩容时,令 capacity 为原来的两倍。
+
+```java
+void addEntry(int hash, K key, V value, int bucketIndex) {
+ Entry e = table[bucketIndex];
+ table[bucketIndex] = new Entry<>(hash, key, value, e);
+ if (size++ >= threshold)
+ resize(2 * table.length);
+}
+```
+
+扩容使用 resize() 实现,需要注意的是,扩容操作同样需要把 oldTable 的所有键值对重新插入 newTable 中,因此这一步是很费时的。
+
+```java
+void resize(int newCapacity) {
+ Entry[] oldTable = table;
+ int oldCapacity = oldTable.length;
+ if (oldCapacity == MAXIMUM_CAPACITY) {
+ threshold = Integer.MAX_VALUE;
+ return;
+ }
+ Entry[] newTable = new Entry[newCapacity];
+ transfer(newTable);
+ table = newTable;
+ threshold = (int)(newCapacity * loadFactor);
+}
+
+void transfer(Entry[] newTable) {
+ Entry[] src = table;
+ int newCapacity = newTable.length;
+ for (int j = 0; j < src.length; j++) {
+ Entry e = src[j];
+ if (e != null) {
+ src[j] = null;
+ do {
+ Entry next = e.next;
+ int i = indexFor(e.hash, newCapacity);
+ e.next = newTable[i];
+ newTable[i] = e;
+ e = next;
+ } while (e != null);
+ }
+ }
+}
+```
+
+### 6. 扩容-重新计算桶下标
+
+在进行扩容时,需要把键值对重新放到对应的桶上。HashMap 使用了一个特殊的机制,可以降低重新计算桶下标的操作。
+
+假设原数组长度 capacity 为 16,扩容之后 new capacity 为 32:
+
+```html
+capacity : 00010000
+new capacity : 00100000
+```
+
+对于一个 Key,
+
+- 它的哈希值如果在第 5 位上为 0,那么取模得到的结果和之前一样;
+- 如果为 1,那么得到的结果为原来的结果 +16。
+
+### 7. 计算数组容量
+
+HashMap 构造函数允许用户传入的容量不是 2 的 n 次方,因为它可以自动地将传入的容量转换为 2 的 n 次方。
+
+先考虑如何求一个数的掩码,对于 10010000,它的掩码为 11111111,可以使用以下方法得到:
+
+```
+mask |= mask >> 1 11011000
+mask |= mask >> 2 11111110
+mask |= mask >> 4 11111111
+```
+
+mask+1 是大于原始数字的最小的 2 的 n 次方。
+
+```
+num 10010000
+mask+1 100000000
+```
+
+以下是 HashMap 中计算数组容量的代码:
+
+```java
+static final int tableSizeFor(int cap) {
+ int n = cap - 1;
+ n |= n >>> 1;
+ n |= n >>> 2;
+ n |= n >>> 4;
+ n |= n >>> 8;
+ n |= n >>> 16;
+ return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+}
+```
+
+### 8. 链表转红黑树
+
+从 JDK 1.8 开始,一个桶存储的链表长度大于 8 时会将链表转换为红黑树。
+
+### 9. 与 HashTable 的比较
+
+- HashTable 使用 synchronized 来进行同步。
+- HashMap 可以插入键为 null 的 Entry。
+- HashMap 的迭代器是 fail-fast 迭代器。
+- HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。
+
+## ConcurrentHashMap
+
+### 1. 存储结构
+
+```java
+static final class HashEntry {
+ final int hash;
+ final K key;
+ volatile V value;
+ volatile HashEntry next;
+}
+```
+
+ConcurrentHashMap 和 HashMap 实现上类似,最主要的差别是 ConcurrentHashMap 采用了分段锁(Segment),每个分段锁维护着几个桶(HashEntry),多个线程可以同时访问不同分段锁上的桶,从而使其并发度更高(并发度就是 Segment 的个数)。
+
+Segment 继承自 ReentrantLock。
+
+```java
+static final class Segment extends ReentrantLock implements Serializable {
+
+ private static final long serialVersionUID = 2249069246763182397L;
+
+ static final int MAX_SCAN_RETRIES =
+ Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
+
+ transient volatile HashEntry[] table;
+
+ transient int count;
+
+ transient int modCount;
+
+ transient int threshold;
+
+ final float loadFactor;
+}
+```
+
+```java
+final Segment[] segments;
+```
+
+默认的并发级别为 16,也就是说默认创建 16 个 Segment。
+
+```java
+static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+```
+
+
+
+### 2. size 操作
+
+每个 Segment 维护了一个 count 变量来统计该 Segment 中的键值对个数。
+
+```java
+/**
+ * The number of elements. Accessed only either within locks
+ * or among other volatile reads that maintain visibility.
+ */
+transient int count;
+```
+
+在执行 size 操作时,需要遍历所有 Segment 然后把 count 累计起来。
+
+ConcurrentHashMap 在执行 size 操作时先尝试不加锁,如果连续两次不加锁操作得到的结果一致,那么可以认为这个结果是正确的。
+
+尝试次数使用 RETRIES_BEFORE_LOCK 定义,该值为 2,retries 初始值为 -1,因此尝试次数为 3。
+
+如果尝试的次数超过 3 次,就需要对每个 Segment 加锁。
+
+```java
+
+/**
+ * Number of unsynchronized retries in size and containsValue
+ * methods before resorting to locking. This is used to avoid
+ * unbounded retries if tables undergo continuous modification
+ * which would make it impossible to obtain an accurate result.
+ */
+static final int RETRIES_BEFORE_LOCK = 2;
+
+public int size() {
+ // Try a few times to get accurate count. On failure due to
+ // continuous async changes in table, resort to locking.
+ final Segment[] segments = this.segments;
+ int size;
+ boolean overflow; // true if size overflows 32 bits
+ long sum; // sum of modCounts
+ long last = 0L; // previous sum
+ int retries = -1; // first iteration isn't retry
+ try {
+ for (;;) {
+ // 超过尝试次数,则对每个 Segment 加锁
+ if (retries++ == RETRIES_BEFORE_LOCK) {
+ for (int j = 0; j < segments.length; ++j)
+ ensureSegment(j).lock(); // force creation
+ }
+ sum = 0L;
+ size = 0;
+ overflow = false;
+ for (int j = 0; j < segments.length; ++j) {
+ Segment seg = segmentAt(segments, j);
+ if (seg != null) {
+ sum += seg.modCount;
+ int c = seg.count;
+ if (c < 0 || (size += c) < 0)
+ overflow = true;
+ }
+ }
+ // 连续两次得到的结果一致,则认为这个结果是正确的
+ if (sum == last)
+ break;
+ last = sum;
+ }
+ } finally {
+ if (retries > RETRIES_BEFORE_LOCK) {
+ for (int j = 0; j < segments.length; ++j)
+ segmentAt(segments, j).unlock();
+ }
+ }
+ return overflow ? Integer.MAX_VALUE : size;
+}
+```
+
+### 3. JDK 1.8 的改动
+
+JDK 1.7 使用分段锁机制来实现并发更新操作,核心类为 Segment,它继承自重入锁 ReentrantLock,并发度与 Segment 数量相等。
+
+JDK 1.8 使用了 CAS 操作来支持更高的并发度,在 CAS 操作失败时使用内置锁 synchronized。
+
+并且 JDK 1.8 的实现也在链表过长时会转换为红黑树。
+
+## LinkedHashMap
+
+### 存储结构
+
+继承自 HashMap,因此具有和 HashMap 一样的快速查找特性。
+
+```java
+public class LinkedHashMap extends HashMap implements Map
+```
+
+内部维护了一个双向链表,用来维护插入顺序或者 LRU 顺序。
+
+```java
+/**
+ * The head (eldest) of the doubly linked list.
+ */
+transient LinkedHashMap.Entry head;
+
+/**
+ * The tail (youngest) of the doubly linked list.
+ */
+transient LinkedHashMap.Entry tail;
+```
+
+accessOrder 决定了顺序,默认为 false,此时维护的是插入顺序。
+
+```java
+final boolean accessOrder;
+```
+
+LinkedHashMap 最重要的是以下用于维护顺序的函数,它们会在 put、get 等方法中调用。
+
+```java
+void afterNodeAccess(Node p) { }
+void afterNodeInsertion(boolean evict) { }
+```
+
+### afterNodeAccess()
+
+当一个节点被访问时,如果 accessOrder 为 true,则会将该节点移到链表尾部。也就是说指定为 LRU 顺序之后,在每次访问一个节点时,会将这个节点移到链表尾部,保证链表尾部是最近访问的节点,那么链表首部就是最近最久未使用的节点。
+
+```java
+void afterNodeAccess(Node e) { // move node to last
+ LinkedHashMap.Entry last;
+ if (accessOrder && (last = tail) != e) {
+ LinkedHashMap.Entry p =
+ (LinkedHashMap.Entry)e, b = p.before, a = p.after;
+ p.after = null;
+ if (b == null)
+ head = a;
+ else
+ b.after = a;
+ if (a != null)
+ a.before = b;
+ else
+ last = b;
+ if (last == null)
+ head = p;
+ else {
+ p.before = last;
+ last.after = p;
+ }
+ tail = p;
+ ++modCount;
+ }
+}
+```
+
+### afterNodeInsertion()
+
+在 put 等操作之后执行,当 removeEldestEntry() 方法返回 true 时会移除最晚的节点,也就是链表首部节点 first。
+
+evict 只有在构建 Map 的时候才为 false,在这里为 true。
+
+```java
+void afterNodeInsertion(boolean evict) { // possibly remove eldest
+ LinkedHashMap.Entry first;
+ if (evict && (first = head) != null && removeEldestEntry(first)) {
+ K key = first.key;
+ removeNode(hash(key), key, null, false, true);
+ }
+}
+```
+
+removeEldestEntry() 默认为 false,如果需要让它为 true,需要继承 LinkedHashMap 并且覆盖这个方法的实现,这在实现 LRU 的缓存中特别有用,通过移除最近最久未使用的节点,从而保证缓存空间足够,并且缓存的数据都是热点数据。
+
+```java
+protected boolean removeEldestEntry(Map.Entry eldest) {
+ return false;
+}
+```
+
+### LRU 缓存
+
+以下是使用 LinkedHashMap 实现的一个 LRU 缓存:
+
+- 设定最大缓存空间 MAX_ENTRIES 为 3;
+- 使用 LinkedHashMap 的构造函数将 accessOrder 设置为 true,开启 LRU 顺序;
+- 覆盖 removeEldestEntry() 方法实现,在节点多于 MAX_ENTRIES 就会将最近最久未使用的数据移除。
+
+```java
+class LRUCache extends LinkedHashMap {
+ private static final int MAX_ENTRIES = 3;
+
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > MAX_ENTRIES;
+ }
+
+ LRUCache() {
+ super(MAX_ENTRIES, 0.75f, true);
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ LRUCache cache = new LRUCache<>();
+ cache.put(1, "a");
+ cache.put(2, "b");
+ cache.put(3, "c");
+ cache.get(1);
+ cache.put(4, "d");
+ System.out.println(cache.keySet());
+}
+```
+
+```html
+[3, 1, 4]
+```
+
+## WeakHashMap
+
+### 存储结构
+
+WeakHashMap 的 Entry 继承自 WeakReference,被 WeakReference 关联的对象在下一次垃圾回收时会被回收。
+
+WeakHashMap 主要用来实现缓存,通过使用 WeakHashMap 来引用缓存对象,由 JVM 对这部分缓存进行回收。
+
+```java
+private static class Entry extends WeakReference implements Map.Entry
+```
+
+### ConcurrentCache
+
+Tomcat 中的 ConcurrentCache 使用了 WeakHashMap 来实现缓存功能。
+
+ConcurrentCache 采取的是分代缓存:
+
+- 经常使用的对象放入 eden 中,eden 使用 ConcurrentHashMap 实现,不用担心会被回收(伊甸园);
+- 不常用的对象放入 longterm,longterm 使用 WeakHashMap 实现,这些老对象会被垃圾收集器回收。
+- 当调用 get() 方法时,会先从 eden 区获取,如果没有找到的话再到 longterm 获取,当从 longterm 获取到就把对象放入 eden 中,从而保证经常被访问的节点不容易被回收。
+- 当调用 put() 方法时,如果 eden 的大小超过了 size,那么就将 eden 中的所有对象都放入 longterm 中,利用虚拟机回收掉一部分不经常使用的对象。
+
+```java
+public final class ConcurrentCache {
+
+ private final int size;
+
+ private final Map eden;
+
+ private final Map longterm;
+
+ public ConcurrentCache(int size) {
+ this.size = size;
+ this.eden = new ConcurrentHashMap<>(size);
+ this.longterm = new WeakHashMap<>(size);
+ }
+
+ public V get(K k) {
+ V v = this.eden.get(k);
+ if (v == null) {
+ v = this.longterm.get(k);
+ if (v != null)
+ this.eden.put(k, v);
+ }
+ return v;
+ }
+
+ public void put(K k, V v) {
+ if (this.eden.size() >= size) {
+ this.longterm.putAll(this.eden);
+ this.eden.clear();
+ }
+ this.eden.put(k, v);
+ }
+}
+```
+
+# 附录
+
+Collection 绘图源码:
+
+```
+@startuml
+
+interface Collection
+interface Set
+interface List
+interface Queue
+interface SortSet
+
+class HashSet
+class LinkedHashSet
+class TreeSet
+class ArrayList
+class Vector
+class LinkedList
+class PriorityQueue
+
+
+Collection <|-- Set
+Collection <|-- List
+Collection <|-- Queue
+Set <|-- SortSet
+
+Set <|.. HashSet
+Set <|.. LinkedHashSet
+SortSet <|.. TreeSet
+List <|.. ArrayList
+List <|.. Vector
+List <|.. LinkedList
+Queue <|.. LinkedList
+Queue <|.. PriorityQueue
+
+@enduml
+```
+
+Map 绘图源码
+
+```
+@startuml
+
+interface Map
+interface SortMap
+
+class HashTable
+class LinkedHashMap
+class HashMap
+class TreeMap
+
+Map <|.. HashTable
+Map <|.. LinkedHashMap
+Map <|.. HashMap
+Map <|-- SortMap
+SortMap <|.. TreeMap
+
+@enduml
+```
+
+迭代器类图
+
+```
+@startuml
+
+interface Iterable
+interface Collection
+interface List
+interface Set
+interface Queue
+interface Iterator
+interface ListIterator
+
+Iterable <|-- Collection
+Collection <|.. List
+Collection <|.. Set
+Collection <|-- Queue
+Iterator <-- Iterable
+Iterator <|.. ListIterator
+ListIterator <-- List
+
+@enduml
+```
+
+# 参考资料
+
+- Eckel B. Java 编程思想 [M]. 机械工业出版社, 2002.
+- [Java Collection Framework](https://www.w3resource.com/java-tutorial/java-collections.php)
+- [Iterator 模式](https://openhome.cc/Gossip/DesignPattern/IteratorPattern.htm)
+- [Java 8 系列之重新认识 HashMap](https://tech.meituan.com/java_hashmap.html)
+- [What is difference between HashMap and Hashtable in Java?](http://javarevisited.blogspot.hk/2010/10/difference-between-hashmap-and.html)
+- [Java 集合之 HashMap](http://www.zhangchangle.com/2018/02/07/Java%E9%9B%86%E5%90%88%E4%B9%8BHashMap/)
+- [The principle of ConcurrentHashMap analysis](http://www.programering.com/a/MDO3QDNwATM.html)
+- [探索 ConcurrentHashMap 高并发性的实现机制](https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/)
+- [HashMap 相关面试题及其解答](https://www.jianshu.com/p/75adf47958a7)
+- [Java 集合细节(二):asList 的缺陷](http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html)
+- [Java Collection Framework – The LinkedList Class](http://javaconceptoftheday.com/java-collection-framework-linkedlist-class/)
+
diff --git a/docs1/docs/notes/Java 并发.md b/docs1/docs/notes/Java 并发.md
new file mode 100644
index 00000000..024f6636
--- /dev/null
+++ b/docs1/docs/notes/Java 并发.md
@@ -0,0 +1,1638 @@
+
+* [一、线程状态转换](#一线程状态转换)
+ * [新建(New)](#新建new)
+ * [可运行(Runnable)](#可运行runnable)
+ * [阻塞(Blocking)](#阻塞blocking)
+ * [无限期等待(Waiting)](#无限期等待waiting)
+ * [限期等待(Timed Waiting)](#限期等待timed-waiting)
+ * [死亡(Terminated)](#死亡terminated)
+* [二、使用线程](#二使用线程)
+ * [实现 Runnable 接口](#实现-runnable-接口)
+ * [实现 Callable 接口](#实现-callable-接口)
+ * [继承 Thread 类](#继承-thread-类)
+ * [实现接口 VS 继承 Thread](#实现接口-vs-继承-thread)
+* [三、基础线程机制](#三基础线程机制)
+ * [Executor](#executor)
+ * [Daemon](#daemon)
+ * [sleep()](#sleep)
+ * [yield()](#yield)
+* [四、中断](#四中断)
+ * [InterruptedException](#interruptedexception)
+ * [interrupted()](#interrupted)
+ * [Executor 的中断操作](#executor-的中断操作)
+* [五、互斥同步](#五互斥同步)
+ * [synchronized](#synchronized)
+ * [ReentrantLock](#reentrantlock)
+ * [比较](#比较)
+ * [使用选择](#使用选择)
+* [六、线程之间的协作](#六线程之间的协作)
+ * [join()](#join)
+ * [wait() notify() notifyAll()](#wait-notify-notifyall)
+ * [await() signal() signalAll()](#await-signal-signalall)
+* [七、J.U.C - AQS](#七juc---aqs)
+ * [CountdownLatch](#countdownlatch)
+ * [CyclicBarrier](#cyclicbarrier)
+ * [Semaphore](#semaphore)
+* [八、J.U.C - 其它组件](#八juc---其它组件)
+ * [FutureTask](#futuretask)
+ * [BlockingQueue](#blockingqueue)
+ * [ForkJoin](#forkjoin)
+* [九、线程不安全示例](#九线程不安全示例)
+* [十、Java 内存模型](#十java-内存模型)
+ * [主内存与工作内存](#主内存与工作内存)
+ * [内存间交互操作](#内存间交互操作)
+ * [内存模型三大特性](#内存模型三大特性)
+ * [先行发生原则](#先行发生原则)
+* [十一、线程安全](#十一线程安全)
+ * [不可变](#不可变)
+ * [互斥同步](#互斥同步)
+ * [非阻塞同步](#非阻塞同步)
+ * [无同步方案](#无同步方案)
+* [十二、锁优化](#十二锁优化)
+ * [自旋锁](#自旋锁)
+ * [锁消除](#锁消除)
+ * [锁粗化](#锁粗化)
+ * [轻量级锁](#轻量级锁)
+ * [偏向锁](#偏向锁)
+* [十三、多线程开发良好的实践](#十三多线程开发良好的实践)
+* [参考资料](#参考资料)
+
+
+
+# 一、线程状态转换
+
+
+
+## 新建(New)
+
+创建后尚未启动。
+
+## 可运行(Runnable)
+
+可能正在运行,也可能正在等待 CPU 时间片。
+
+包含了操作系统线程状态中的 Running 和 Ready。
+
+## 阻塞(Blocking)
+
+等待获取一个排它锁,如果其线程释放了锁就会结束此状态。
+
+## 无限期等待(Waiting)
+
+等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。
+
+| 进入方法 | 退出方法 |
+| --- | --- |
+| 没有设置 Timeout 参数的 Object.wait() 方法 | Object.notify() / Object.notifyAll() |
+| 没有设置 Timeout 参数的 Thread.join() 方法 | 被调用的线程执行完毕 |
+| LockSupport.park() 方法 | - |
+
+## 限期等待(Timed Waiting)
+
+无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。
+
+调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用“使一个线程睡眠”进行描述。
+
+调用 Object.wait() 方法使线程进入限期等待或者无限期等待时,常常用“挂起一个线程”进行描述。
+
+睡眠和挂起是用来描述行为,而阻塞和等待用来描述状态。
+
+阻塞和等待的区别在于,阻塞是被动的,它是在等待获取一个排它锁。而等待是主动的,通过调用 Thread.sleep() 和 Object.wait() 等方法进入。
+
+| 进入方法 | 退出方法 |
+| --- | --- |
+| Thread.sleep() 方法 | 时间结束 |
+| 设置了 Timeout 参数的 Object.wait() 方法 | 时间结束 / Object.notify() / Object.notifyAll() |
+| 设置了 Timeout 参数的 Thread.join() 方法 | 时间结束 / 被调用的线程执行完毕 |
+| LockSupport.parkNanos() 方法 | - |
+| LockSupport.parkUntil() 方法 | - |
+
+## 死亡(Terminated)
+
+可以是线程结束任务之后自己结束,或者产生了异常而结束。
+
+# 二、使用线程
+
+有三种使用线程的方法:
+
+- 实现 Runnable 接口;
+- 实现 Callable 接口;
+- 继承 Thread 类。
+
+实现 Runnable 和 Callable 接口的类只能当做一个可以在线程中运行的任务,不是真正意义上的线程,因此最后还需要通过 Thread 来调用。可以说任务是通过线程驱动从而执行的。
+
+## 实现 Runnable 接口
+
+需要实现 run() 方法。
+
+通过 Thread 调用 start() 方法来启动线程。
+
+```java
+public class MyRunnable implements Runnable {
+ public void run() {
+ // ...
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ MyRunnable instance = new MyRunnable();
+ Thread thread = new Thread(instance);
+ thread.start();
+}
+```
+
+## 实现 Callable 接口
+
+与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。
+
+```java
+public class MyCallable implements Callable {
+ public Integer call() {
+ return 123;
+ }
+}
+```
+
+```java
+public static void main(String[] args) throws ExecutionException, InterruptedException {
+ MyCallable mc = new MyCallable();
+ FutureTask ft = new FutureTask<>(mc);
+ Thread thread = new Thread(ft);
+ thread.start();
+ System.out.println(ft.get());
+}
+```
+
+## 继承 Thread 类
+
+同样也是需要实现 run() 方法,因为 Thread 类也实现了 Runable 接口。
+
+当调用 start() 方法启动一个线程时,虚拟机会将该线程放入就绪队列中等待被调度,当一个线程被调度时会执行该线程的 run() 方法。
+
+```java
+public class MyThread extends Thread {
+ public void run() {
+ // ...
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ MyThread mt = new MyThread();
+ mt.start();
+}
+```
+
+## 实现接口 VS 继承 Thread
+
+实现接口会更好一些,因为:
+
+- Java 不支持多重继承,因此继承了 Thread 类就无法继承其它类,但是可以实现多个接口;
+- 类可能只要求可执行就行,继承整个 Thread 类开销过大。
+
+# 三、基础线程机制
+
+## Executor
+
+Executor 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。
+
+主要有三种 Executor:
+
+- CachedThreadPool:一个任务创建一个线程;
+- FixedThreadPool:所有任务只能使用固定大小的线程;
+- SingleThreadExecutor:相当于大小为 1 的 FixedThreadPool。
+
+```java
+public static void main(String[] args) {
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < 5; i++) {
+ executorService.execute(new MyRunnable());
+ }
+ executorService.shutdown();
+}
+```
+
+## Daemon
+
+守护线程是程序运行时在后台提供服务的线程,不属于程序中不可或缺的部分。
+
+当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程。
+
+main() 属于非守护线程。
+
+使用 setDaemon() 方法将一个线程设置为守护线程。
+
+```java
+public static void main(String[] args) {
+ Thread thread = new Thread(new MyRunnable());
+ thread.setDaemon(true);
+}
+```
+
+## sleep()
+
+Thread.sleep(millisec) 方法会休眠当前正在执行的线程,millisec 单位为毫秒。
+
+sleep() 可能会抛出 InterruptedException,因为异常不能跨线程传播回 main() 中,因此必须在本地进行处理。线程中抛出的其它异常也同样需要在本地进行处理。
+
+```java
+public void run() {
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+}
+```
+
+## yield()
+
+对静态方法 Thread.yield() 的调用声明了当前线程已经完成了生命周期中最重要的部分,可以切换给其它线程来执行。该方法只是对线程调度器的一个建议,而且也只是建议具有相同优先级的其它线程可以运行。
+
+```java
+public void run() {
+ Thread.yield();
+}
+```
+
+# 四、中断
+
+一个线程执行完毕之后会自动结束,如果在运行过程中发生异常也会提前结束。
+
+## InterruptedException
+
+通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。
+
+对于以下代码,在 main() 中启动一个线程之后再中断它,由于线程中调用了 Thread.sleep() 方法,因此会抛出一个 InterruptedException,从而提前结束线程,不执行之后的语句。
+
+```java
+public class InterruptExample {
+
+ private static class MyThread1 extends Thread {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(2000);
+ System.out.println("Thread run");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
+```
+
+```java
+public static void main(String[] args) throws InterruptedException {
+ Thread thread1 = new MyThread1();
+ thread1.start();
+ thread1.interrupt();
+ System.out.println("Main run");
+}
+```
+
+```html
+Main run
+java.lang.InterruptedException: sleep interrupted
+ at java.lang.Thread.sleep(Native Method)
+ at InterruptExample.lambda$main$0(InterruptExample.java:5)
+ at InterruptExample$$Lambda$1/713338599.run(Unknown Source)
+ at java.lang.Thread.run(Thread.java:745)
+```
+
+## interrupted()
+
+如果一个线程的 run() 方法执行一个无限循环,并且没有执行 sleep() 等会抛出 InterruptedException 的操作,那么调用线程的 interrupt() 方法就无法使线程提前结束。
+
+但是调用 interrupt() 方法会设置线程的中断标记,此时调用 interrupted() 方法会返回 true。因此可以在循环体中使用 interrupted() 方法来判断线程是否处于中断状态,从而提前结束线程。
+
+```java
+public class InterruptExample {
+
+ private static class MyThread2 extends Thread {
+ @Override
+ public void run() {
+ while (!interrupted()) {
+ // ..
+ }
+ System.out.println("Thread end");
+ }
+ }
+}
+```
+
+```java
+public static void main(String[] args) throws InterruptedException {
+ Thread thread2 = new MyThread2();
+ thread2.start();
+ thread2.interrupt();
+}
+```
+
+```html
+Thread end
+```
+
+## Executor 的中断操作
+
+调用 Executor 的 shutdown() 方法会等待线程都执行完毕之后再关闭,但是如果调用的是 shutdownNow() 方法,则相当于调用每个线程的 interrupt() 方法。
+
+以下使用 Lambda 创建线程,相当于创建了一个匿名内部线程。
+
+```java
+public static void main(String[] args) {
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ executorService.execute(() -> {
+ try {
+ Thread.sleep(2000);
+ System.out.println("Thread run");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ executorService.shutdownNow();
+ System.out.println("Main run");
+}
+```
+
+```html
+Main run
+java.lang.InterruptedException: sleep interrupted
+ at java.lang.Thread.sleep(Native Method)
+ at ExecutorInterruptExample.lambda$main$0(ExecutorInterruptExample.java:9)
+ at ExecutorInterruptExample$$Lambda$1/1160460865.run(Unknown Source)
+ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
+ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
+ at java.lang.Thread.run(Thread.java:745)
+```
+
+如果只想中断 Executor 中的一个线程,可以通过使用 submit() 方法来提交一个线程,它会返回一个 Future> 对象,通过调用该对象的 cancel(true) 方法就可以中断线程。
+
+```java
+Future> future = executorService.submit(() -> {
+ // ..
+});
+future.cancel(true);
+```
+
+# 五、互斥同步
+
+Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问,第一个是 JVM 实现的 synchronized,而另一个是 JDK 实现的 ReentrantLock。
+
+## synchronized
+
+**1. 同步一个代码块**
+
+```java
+public void func() {
+ synchronized (this) {
+ // ...
+ }
+}
+```
+
+它只作用于同一个对象,如果调用两个对象上的同步代码块,就不会进行同步。
+
+对于以下代码,使用 ExecutorService 执行了两个线程,由于调用的是同一个对象的同步代码块,因此这两个线程会进行同步,当一个线程进入同步语句块时,另一个线程就必须等待。
+
+```java
+public class SynchronizedExample {
+
+ public void func1() {
+ synchronized (this) {
+ for (int i = 0; i < 10; i++) {
+ System.out.print(i + " ");
+ }
+ }
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ SynchronizedExample e1 = new SynchronizedExample();
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ executorService.execute(() -> e1.func1());
+ executorService.execute(() -> e1.func1());
+}
+```
+
+```html
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+```
+
+对于以下代码,两个线程调用了不同对象的同步代码块,因此这两个线程就不需要同步。从输出结果可以看出,两个线程交叉执行。
+
+```java
+public static void main(String[] args) {
+ SynchronizedExample e1 = new SynchronizedExample();
+ SynchronizedExample e2 = new SynchronizedExample();
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ executorService.execute(() -> e1.func1());
+ executorService.execute(() -> e2.func1());
+}
+```
+
+```html
+0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
+```
+
+
+**2. 同步一个方法**
+
+```java
+public synchronized void func () {
+ // ...
+}
+```
+
+它和同步代码块一样,作用于同一个对象。
+
+**3. 同步一个类**
+
+```java
+public void func() {
+ synchronized (SynchronizedExample.class) {
+ // ...
+ }
+}
+```
+
+作用于整个类,也就是说两个线程调用同一个类的不同对象上的这种同步语句,也会进行同步。
+
+```java
+public class SynchronizedExample {
+
+ public void func2() {
+ synchronized (SynchronizedExample.class) {
+ for (int i = 0; i < 10; i++) {
+ System.out.print(i + " ");
+ }
+ }
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ SynchronizedExample e1 = new SynchronizedExample();
+ SynchronizedExample e2 = new SynchronizedExample();
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ executorService.execute(() -> e1.func2());
+ executorService.execute(() -> e2.func2());
+}
+```
+
+```html
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+```
+
+**4. 同步一个静态方法**
+
+```java
+public synchronized static void fun() {
+ // ...
+}
+```
+
+作用于整个类。
+
+## ReentrantLock
+
+ReentrantLock 是 java.util.concurrent(J.U.C)包中的锁。
+
+```java
+public class LockExample {
+
+ private Lock lock = new ReentrantLock();
+
+ public void func() {
+ lock.lock();
+ try {
+ for (int i = 0; i < 10; i++) {
+ System.out.print(i + " ");
+ }
+ } finally {
+ lock.unlock(); // 确保释放锁,从而避免发生死锁。
+ }
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ LockExample lockExample = new LockExample();
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ executorService.execute(() -> lockExample.func());
+ executorService.execute(() -> lockExample.func());
+}
+```
+
+```html
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+```
+
+
+## 比较
+
+**1. 锁的实现**
+
+synchronized 是 JVM 实现的,而 ReentrantLock 是 JDK 实现的。
+
+**2. 性能**
+
+新版本 Java 对 synchronized 进行了很多优化,例如自旋锁等,synchronized 与 ReentrantLock 大致相同。
+
+**3. 等待可中断**
+
+当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。
+
+ReentrantLock 可中断,而 synchronized 不行。
+
+**4. 公平锁**
+
+公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。
+
+synchronized 中的锁是非公平的,ReentrantLock 默认情况下也是非公平的,但是也可以是公平的。
+
+**5. 锁绑定多个条件**
+
+一个 ReentrantLock 可以同时绑定多个 Condition 对象。
+
+## 使用选择
+
+除非需要使用 ReentrantLock 的高级功能,否则优先使用 synchronized。这是因为 synchronized 是 JVM 实现的一种锁机制,JVM 原生地支持它,而 ReentrantLock 不是所有的 JDK 版本都支持。并且使用 synchronized 不用担心没有释放锁而导致死锁问题,因为 JVM 会确保锁的释放。
+
+# 六、线程之间的协作
+
+当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调。
+
+## join()
+
+在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。
+
+对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。
+
+```java
+public class JoinExample {
+
+ private class A extends Thread {
+ @Override
+ public void run() {
+ System.out.println("A");
+ }
+ }
+
+ private class B extends Thread {
+
+ private A a;
+
+ B(A a) {
+ this.a = a;
+ }
+
+ @Override
+ public void run() {
+ try {
+ a.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.println("B");
+ }
+ }
+
+ public void test() {
+ A a = new A();
+ B b = new B(a);
+ b.start();
+ a.start();
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ JoinExample example = new JoinExample();
+ example.test();
+}
+```
+
+```
+A
+B
+```
+
+## wait() notify() notifyAll()
+
+调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。
+
+它们都属于 Object 的一部分,而不属于 Thread。
+
+只能用在同步方法或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateException。
+
+使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。
+
+```java
+public class WaitNotifyExample {
+
+ public synchronized void before() {
+ System.out.println("before");
+ notifyAll();
+ }
+
+ public synchronized void after() {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.println("after");
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ WaitNotifyExample example = new WaitNotifyExample();
+ executorService.execute(() -> example.after());
+ executorService.execute(() -> example.before());
+}
+```
+
+```html
+before
+after
+```
+
+**wait() 和 sleep() 的区别**
+
+- wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法;
+- wait() 会释放锁,sleep() 不会。
+
+## await() signal() signalAll()
+
+java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。
+
+相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活。
+
+使用 Lock 来获取一个 Condition 对象。
+
+```java
+public class AwaitSignalExample {
+
+ private Lock lock = new ReentrantLock();
+ private Condition condition = lock.newCondition();
+
+ public void before() {
+ lock.lock();
+ try {
+ System.out.println("before");
+ condition.signalAll();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public void after() {
+ lock.lock();
+ try {
+ condition.await();
+ System.out.println("after");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ lock.unlock();
+ }
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ AwaitSignalExample example = new AwaitSignalExample();
+ executorService.execute(() -> example.after());
+ executorService.execute(() -> example.before());
+}
+```
+
+```html
+before
+after
+```
+
+# 七、J.U.C - AQS
+
+java.util.concurrent(J.U.C)大大提高了并发性能,AQS 被认为是 J.U.C 的核心。
+
+## CountdownLatch
+
+用来控制一个线程等待多个线程。
+
+维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
+
+
+
+```java
+public class CountdownLatchExample {
+
+ public static void main(String[] args) throws InterruptedException {
+ final int totalThread = 10;
+ CountDownLatch countDownLatch = new CountDownLatch(totalThread);
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < totalThread; i++) {
+ executorService.execute(() -> {
+ System.out.print("run..");
+ countDownLatch.countDown();
+ });
+ }
+ countDownLatch.await();
+ System.out.println("end");
+ executorService.shutdown();
+ }
+}
+```
+
+```html
+run..run..run..run..run..run..run..run..run..run..end
+```
+
+## CyclicBarrier
+
+用来控制多个线程互相等待,只有当多个线程都到达时,这些线程才会继续执行。
+
+和 CountdownLatch 相似,都是通过维护计数器来实现的。线程执行 await() 方法之后计数器会减 1,并进行等待,直到计数器为 0,所有调用 await() 方法而在等待的线程才能继续执行。
+
+CyclicBarrier 和 CountdownLatch 的一个区别是,CyclicBarrier 的计数器通过调用 reset() 方法可以循环使用,所以它才叫做循环屏障。
+
+CyclicBarrier 有两个构造函数,其中 parties 指示计数器的初始值,barrierAction 在所有线程都到达屏障的时候会执行一次。
+
+```java
+public CyclicBarrier(int parties, Runnable barrierAction) {
+ if (parties <= 0) throw new IllegalArgumentException();
+ this.parties = parties;
+ this.count = parties;
+ this.barrierCommand = barrierAction;
+}
+
+public CyclicBarrier(int parties) {
+ this(parties, null);
+}
+```
+
+
+
+```java
+public class CyclicBarrierExample {
+
+ public static void main(String[] args) {
+ final int totalThread = 10;
+ CyclicBarrier cyclicBarrier = new CyclicBarrier(totalThread);
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < totalThread; i++) {
+ executorService.execute(() -> {
+ System.out.print("before..");
+ try {
+ cyclicBarrier.await();
+ } catch (InterruptedException | BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+ System.out.print("after..");
+ });
+ }
+ executorService.shutdown();
+ }
+}
+```
+
+```html
+before..before..before..before..before..before..before..before..before..before..after..after..after..after..after..after..after..after..after..after..
+```
+
+## Semaphore
+
+Semaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。
+
+
+
+以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。
+
+```java
+public class SemaphoreExample {
+
+ public static void main(String[] args) {
+ final int clientCount = 3;
+ final int totalRequestCount = 10;
+ Semaphore semaphore = new Semaphore(clientCount);
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < totalRequestCount; i++) {
+ executorService.execute(()->{
+ try {
+ semaphore.acquire();
+ System.out.print(semaphore.availablePermits() + " ");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ semaphore.release();
+ }
+ });
+ }
+ executorService.shutdown();
+ }
+}
+```
+
+```html
+2 1 2 2 2 2 2 1 2 2
+```
+
+# 八、J.U.C - 其它组件
+
+## FutureTask
+
+在介绍 Callable 时我们知道它可以有返回值,返回值通过 Future 进行封装。FutureTask 实现了 RunnableFuture 接口,该接口继承自 Runnable 和 Future 接口,这使得 FutureTask 既可以当做一个任务执行,也可以有返回值。
+
+```java
+public class FutureTask implements RunnableFuture
+```
+
+```java
+public interface RunnableFuture extends Runnable, Future
+```
+
+FutureTask 可用于异步获取执行结果或取消执行任务的场景。当一个计算任务需要执行很长时间,那么就可以用 FutureTask 来封装这个任务,主线程在完成自己的任务之后再去获取结果。
+
+```java
+public class FutureTaskExample {
+
+ public static void main(String[] args) throws ExecutionException, InterruptedException {
+ FutureTask futureTask = new FutureTask(new Callable() {
+ @Override
+ public Integer call() throws Exception {
+ int result = 0;
+ for (int i = 0; i < 100; i++) {
+ Thread.sleep(10);
+ result += i;
+ }
+ return result;
+ }
+ });
+
+ Thread computeThread = new Thread(futureTask);
+ computeThread.start();
+
+ Thread otherThread = new Thread(() -> {
+ System.out.println("other task is running...");
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ otherThread.start();
+ System.out.println(futureTask.get());
+ }
+}
+```
+
+```html
+other task is running...
+4950
+```
+
+## BlockingQueue
+
+java.util.concurrent.BlockingQueue 接口有以下阻塞队列的实现:
+
+- **FIFO 队列** :LinkedBlockingQueue、ArrayBlockingQueue(固定长度)
+- **优先级队列** :PriorityBlockingQueue
+
+提供了阻塞的 take() 和 put() 方法:如果队列为空 take() 将阻塞,直到队列中有内容;如果队列为满 put() 将阻塞,直到队列有空闲位置。
+
+**使用 BlockingQueue 实现生产者消费者问题**
+
+```java
+public class ProducerConsumer {
+
+ private static BlockingQueue queue = new ArrayBlockingQueue<>(5);
+
+ private static class Producer extends Thread {
+ @Override
+ public void run() {
+ try {
+ queue.put("product");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.print("produce..");
+ }
+ }
+
+ private static class Consumer extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ String product = queue.take();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.print("consume..");
+ }
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ for (int i = 0; i < 2; i++) {
+ Producer producer = new Producer();
+ producer.start();
+ }
+ for (int i = 0; i < 5; i++) {
+ Consumer consumer = new Consumer();
+ consumer.start();
+ }
+ for (int i = 0; i < 3; i++) {
+ Producer producer = new Producer();
+ producer.start();
+ }
+}
+```
+
+```html
+produce..produce..consume..consume..produce..consume..produce..consume..produce..consume..
+```
+
+## ForkJoin
+
+主要用于并行计算中,和 MapReduce 原理类似,都是把大的计算任务拆分成多个小任务并行计算。
+
+```java
+public class ForkJoinExample extends RecursiveTask {
+
+ private final int threshold = 5;
+ private int first;
+ private int last;
+
+ public ForkJoinExample(int first, int last) {
+ this.first = first;
+ this.last = last;
+ }
+
+ @Override
+ protected Integer compute() {
+ int result = 0;
+ if (last - first <= threshold) {
+ // 任务足够小则直接计算
+ for (int i = first; i <= last; i++) {
+ result += i;
+ }
+ } else {
+ // 拆分成小任务
+ int middle = first + (last - first) / 2;
+ ForkJoinExample leftTask = new ForkJoinExample(first, middle);
+ ForkJoinExample rightTask = new ForkJoinExample(middle + 1, last);
+ leftTask.fork();
+ rightTask.fork();
+ result = leftTask.join() + rightTask.join();
+ }
+ return result;
+ }
+}
+```
+
+```java
+public static void main(String[] args) throws ExecutionException, InterruptedException {
+ ForkJoinExample example = new ForkJoinExample(1, 10000);
+ ForkJoinPool forkJoinPool = new ForkJoinPool();
+ Future result = forkJoinPool.submit(example);
+ System.out.println(result.get());
+}
+```
+
+ForkJoin 使用 ForkJoinPool 来启动,它是一个特殊的线程池,线程数量取决于 CPU 核数。
+
+```java
+public class ForkJoinPool extends AbstractExecutorService
+```
+
+ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列,用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务,避免和队列所属线程发生竞争。例如下图中,Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务,Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
+
+
+
+# 九、线程不安全示例
+
+如果多个线程对同一个共享数据进行访问而不采取同步操作的话,那么操作的结果是不一致的。
+
+以下代码演示了 1000 个线程同时对 cnt 执行自增操作,操作结束之后它的值有可能小于 1000。
+
+```java
+public class ThreadUnsafeExample {
+
+ private int cnt = 0;
+
+ public void add() {
+ cnt++;
+ }
+
+ public int get() {
+ return cnt;
+ }
+}
+```
+
+```java
+public static void main(String[] args) throws InterruptedException {
+ final int threadSize = 1000;
+ ThreadUnsafeExample example = new ThreadUnsafeExample();
+ final CountDownLatch countDownLatch = new CountDownLatch(threadSize);
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < threadSize; i++) {
+ executorService.execute(() -> {
+ example.add();
+ countDownLatch.countDown();
+ });
+ }
+ countDownLatch.await();
+ executorService.shutdown();
+ System.out.println(example.get());
+}
+```
+
+```html
+997
+```
+
+# 十、Java 内存模型
+
+Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。
+
+## 主内存与工作内存
+
+处理器上的寄存器的读写的速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存。
+
+加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
+
+
+
+所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
+
+线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
+
+
+
+## 内存间交互操作
+
+Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
+
+
+
+- read:把一个变量的值从主内存传输到工作内存中
+- load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
+- use:把工作内存中一个变量的值传递给执行引擎
+- assign:把一个从执行引擎接收到的值赋给工作内存的变量
+- store:把工作内存的一个变量的值传送到主内存中
+- write:在 store 之后执行,把 store 得到的值放入主内存的变量中
+- lock:作用于主内存的变量
+- unlock
+
+## 内存模型三大特性
+
+### 1. 原子性
+
+Java 内存模型保证了 read、load、use、assign、store、write、lock 和 unlock 操作具有原子性,例如对一个 int 类型的变量执行 assign 赋值操作,这个操作就是原子性的。但是 Java 内存模型允许虚拟机将没有被 volatile 修饰的 64 位数据(long,double)的读写操作划分为两次 32 位的操作来进行,即 load、store、read 和 write 操作可以不具备原子性。
+
+有一个错误认识就是,int 等原子性的类型在多线程环境中不会出现线程安全问题。前面的线程不安全示例代码中,cnt 属于 int 类型变量,1000 个线程对它进行自增操作之后,得到的值为 997 而不是 1000。
+
+为了方便讨论,将内存间的交互操作简化为 3 个:load、assign、store。
+
+下图演示了两个线程同时对 cnt 进行操作,load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存,T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
+
+
+
+AtomicInteger 能保证多个线程修改的原子性。
+
+
+
+使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
+
+```java
+public class AtomicExample {
+ private AtomicInteger cnt = new AtomicInteger();
+
+ public void add() {
+ cnt.incrementAndGet();
+ }
+
+ public int get() {
+ return cnt.get();
+ }
+}
+```
+
+```java
+public static void main(String[] args) throws InterruptedException {
+ final int threadSize = 1000;
+ AtomicExample example = new AtomicExample(); // 只修改这条语句
+ final CountDownLatch countDownLatch = new CountDownLatch(threadSize);
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < threadSize; i++) {
+ executorService.execute(() -> {
+ example.add();
+ countDownLatch.countDown();
+ });
+ }
+ countDownLatch.await();
+ executorService.shutdown();
+ System.out.println(example.get());
+}
+```
+
+```html
+1000
+```
+
+除了使用原子类之外,也可以使用 synchronized 互斥锁来保证操作的原子性。它对应的内存间交互操作为:lock 和 unlock,在虚拟机实现上对应的字节码指令为 monitorenter 和 monitorexit。
+
+```java
+public class AtomicSynchronizedExample {
+ private int cnt = 0;
+
+ public synchronized void add() {
+ cnt++;
+ }
+
+ public synchronized int get() {
+ return cnt;
+ }
+}
+```
+
+```java
+public static void main(String[] args) throws InterruptedException {
+ final int threadSize = 1000;
+ AtomicSynchronizedExample example = new AtomicSynchronizedExample();
+ final CountDownLatch countDownLatch = new CountDownLatch(threadSize);
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < threadSize; i++) {
+ executorService.execute(() -> {
+ example.add();
+ countDownLatch.countDown();
+ });
+ }
+ countDownLatch.await();
+ executorService.shutdown();
+ System.out.println(example.get());
+}
+```
+
+```html
+1000
+```
+
+### 2. 可见性
+
+可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。
+
+主要有有三种实现可见性的方式:
+
+- volatile
+- synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
+- final,被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。
+
+对前面的线程不安全示例中的 cnt 变量使用 volatile 修饰,不能解决线程不安全问题,因为 volatile 并不能保证操作的原子性。
+
+### 3. 有序性
+
+有序性是指:在本线程内观察,所有操作都是有序的。在一个线程观察另一个线程,所有操作都是无序的,无序是因为发生了指令重排序。在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
+
+volatile 关键字通过添加内存屏障的方式来禁止指令重排,即重排序时不能把后面的指令放到内存屏障之前。
+
+也可以通过 synchronized 来保证有序性,它保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码。
+
+## 先行发生原则
+
+上面提到了可以用 volatile 和 synchronized 来保证有序性。除此之外,JVM 还规定了先行发生原则,让一个操作无需控制就能先于另一个操作完成。
+
+### 1. 单一线程原则
+
+> Single Thread rule
+
+在一个线程内,在程序前面的操作先行发生于后面的操作。
+
+
+
+### 2. 管程锁定规则
+
+> Monitor Lock Rule
+
+一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
+
+
+
+### 3. volatile 变量规则
+
+> Volatile Variable Rule
+
+对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
+
+
+
+### 4. 线程启动规则
+
+> Thread Start Rule
+
+Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
+
+
+
+### 5. 线程加入规则
+
+> Thread Join Rule
+
+Thread 对象的结束先行发生于 join() 方法返回。
+
+
+
+### 6. 线程中断规则
+
+> Thread Interruption Rule
+
+对线程 interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 interrupted() 方法检测到是否有中断发生。
+
+### 7. 对象终结规则
+
+> Finalizer Rule
+
+一个对象的初始化完成(构造函数执行结束)先行发生于它的 finalize() 方法的开始。
+
+### 8. 传递性
+
+> Transitivity
+
+如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那么操作 A 先行发生于操作 C。
+
+# 十一、线程安全
+
+多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为。
+
+线程安全有以下几种实现方式:
+
+## 不可变
+
+不可变(Immutable)的对象一定是线程安全的,不需要再采取任何的线程安全保障措施。只要一个不可变的对象被正确地构建出来,永远也不会看到它在多个线程之中处于不一致的状态。多线程环境下,应当尽量使对象成为不可变,来满足线程安全。
+
+不可变的类型:
+
+- final 关键字修饰的基本数据类型
+- String
+- 枚举类型
+- Number 部分子类,如 Long 和 Double 等数值包装类型,BigInteger 和 BigDecimal 等大数据类型。但同为 Number 的原子类 AtomicInteger 和 AtomicLong 则是可变的。
+
+对于集合类型,可以使用 Collections.unmodifiableXXX() 方法来获取一个不可变的集合。
+
+```java
+public class ImmutableExample {
+ public static void main(String[] args) {
+ Map map = new HashMap<>();
+ Map unmodifiableMap = Collections.unmodifiableMap(map);
+ unmodifiableMap.put("a", 1);
+ }
+}
+```
+
+```html
+Exception in thread "main" java.lang.UnsupportedOperationException
+ at java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
+ at ImmutableExample.main(ImmutableExample.java:9)
+```
+
+Collections.unmodifiableXXX() 先对原始的集合进行拷贝,需要对集合进行修改的方法都直接抛出异常。
+
+```java
+public V put(K key, V value) {
+ throw new UnsupportedOperationException();
+}
+```
+
+## 互斥同步
+
+synchronized 和 ReentrantLock。
+
+## 非阻塞同步
+
+互斥同步最主要的问题就是线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步。
+
+互斥同步属于一种悲观的并发策略,总是认为只要不去做正确的同步措施,那就肯定会出现问题。无论共享数据是否真的会出现竞争,它都要进行加锁(这里讨论的是概念模型,实际上虚拟机会优化掉很大一部分不必要的加锁)、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。
+
+### 1. CAS
+
+随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略:先进行操作,如果没有其它线程争用共享数据,那操作就成功了,否则采取补偿措施(不断地重试,直到成功为止)。这种乐观的并发策略的许多实现都不需要将线程阻塞,因此这种同步操作称为非阻塞同步。
+
+乐观锁需要操作和冲突检测这两个步骤具备原子性,这里就不能再使用互斥同步来保证了,只能靠硬件来完成。硬件支持的原子性操作最典型的是:比较并交换(Compare-and-Swap,CAS)。CAS 指令需要有 3 个操作数,分别是内存地址 V、旧的预期值 A 和新值 B。当执行操作时,只有当 V 的值等于 A,才将 V 的值更新为 B。
+
+### 2. AtomicInteger
+
+J.U.C 包里面的整数原子类 AtomicInteger 的方法调用了 Unsafe 类的 CAS 操作。
+
+以下代码使用了 AtomicInteger 执行了自增的操作。
+
+```java
+private AtomicInteger cnt = new AtomicInteger();
+
+public void add() {
+ cnt.incrementAndGet();
+}
+```
+
+以下代码是 incrementAndGet() 的源码,它调用了 Unsafe 的 getAndAddInt() 。
+
+```java
+public final int incrementAndGet() {
+ return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
+}
+```
+
+以下代码是 getAndAddInt() 源码,var1 指示对象内存地址,var2 指示该字段相对对象内存地址的偏移,var4 指示操作需要加的数值,这里为 1。通过 getIntVolatile(var1, var2) 得到旧的预期值,通过调用 compareAndSwapInt() 来进行 CAS 比较,如果该字段内存地址中的值等于 var5,那么就更新内存地址为 var1+var2 的变量为 var5+var4。
+
+可以看到 getAndAddInt() 在一个循环中进行,发生冲突的做法是不断的进行重试。
+
+```java
+public final int getAndAddInt(Object var1, long var2, int var4) {
+ int var5;
+ do {
+ var5 = this.getIntVolatile(var1, var2);
+ } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
+
+ return var5;
+}
+```
+
+### 3. ABA
+
+如果一个变量初次读取的时候是 A 值,它的值被改成了 B,后来又被改回为 A,那 CAS 操作就会误认为它从来没有被改变过。
+
+J.U.C 包提供了一个带有标记的原子引用类 AtomicStampedReference 来解决这个问题,它可以通过控制变量值的版本来保证 CAS 的正确性。大部分情况下 ABA 问题不会影响程序并发的正确性,如果需要解决 ABA 问题,改用传统的互斥同步可能会比原子类更高效。
+
+## 无同步方案
+
+要保证线程安全,并不是一定就要进行同步。如果一个方法本来就不涉及共享数据,那它自然就无须任何同步措施去保证正确性。
+
+### 1. 栈封闭
+
+多个线程访问同一个方法的局部变量时,不会出现线程安全问题,因为局部变量存储在虚拟机栈中,属于线程私有的。
+
+```java
+public class StackClosedExample {
+ public void add100() {
+ int cnt = 0;
+ for (int i = 0; i < 100; i++) {
+ cnt++;
+ }
+ System.out.println(cnt);
+ }
+}
+```
+
+```java
+public static void main(String[] args) {
+ StackClosedExample example = new StackClosedExample();
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ executorService.execute(() -> example.add100());
+ executorService.execute(() -> example.add100());
+ executorService.shutdown();
+}
+```
+
+```html
+100
+100
+```
+
+### 2. 线程本地存储(Thread Local Storage)
+
+如果一段代码中所需要的数据必须与其他代码共享,那就看看这些共享数据的代码是否能保证在同一个线程中执行。如果能保证,我们就可以把共享数据的可见范围限制在同一个线程之内,这样,无须同步也能保证线程之间不出现数据争用的问题。
+
+符合这种特点的应用并不少见,大部分使用消费队列的架构模式(如“生产者-消费者”模式)都会将产品的消费过程尽量在一个线程中消费完。其中最重要的一个应用实例就是经典 Web 交互模型中的“一个请求对应一个服务器线程”(Thread-per-Request)的处理方式,这种处理方式的广泛应用使得很多 Web 服务端应用都可以使用线程本地存储来解决线程安全问题。
+
+可以使用 java.lang.ThreadLocal 类来实现线程本地存储功能。
+
+对于以下代码,thread1 中设置 threadLocal 为 1,而 thread2 设置 threadLocal 为 2。过了一段时间之后,thread1 读取 threadLocal 依然是 1,不受 thread2 的影响。
+
+```java
+public class ThreadLocalExample {
+ public static void main(String[] args) {
+ ThreadLocal threadLocal = new ThreadLocal();
+ Thread thread1 = new Thread(() -> {
+ threadLocal.set(1);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.println(threadLocal.get());
+ threadLocal.remove();
+ });
+ Thread thread2 = new Thread(() -> {
+ threadLocal.set(2);
+ threadLocal.remove();
+ });
+ thread1.start();
+ thread2.start();
+ }
+}
+```
+
+```html
+1
+```
+
+为了理解 ThreadLocal,先看以下代码:
+
+```java
+public class ThreadLocalExample1 {
+ public static void main(String[] args) {
+ ThreadLocal threadLocal1 = new ThreadLocal();
+ ThreadLocal threadLocal2 = new ThreadLocal();
+ Thread thread1 = new Thread(() -> {
+ threadLocal1.set(1);
+ threadLocal2.set(1);
+ });
+ Thread thread2 = new Thread(() -> {
+ threadLocal1.set(2);
+ threadLocal2.set(2);
+ });
+ thread1.start();
+ thread2.start();
+ }
+}
+```
+
+它所对应的底层结构图为:
+
+
+
+每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
+
+```java
+/* ThreadLocal values pertaining to this thread. This map is maintained
+ * by the ThreadLocal class. */
+ThreadLocal.ThreadLocalMap threadLocals = null;
+```
+
+当调用一个 ThreadLocal 的 set(T value) 方法时,先得到当前线程的 ThreadLocalMap 对象,然后将 ThreadLocal->value 键值对插入到该 Map 中。
+
+```java
+public void set(T value) {
+ Thread t = Thread.currentThread();
+ ThreadLocalMap map = getMap(t);
+ if (map != null)
+ map.set(this, value);
+ else
+ createMap(t, value);
+}
+```
+
+get() 方法类似。
+
+```java
+public T get() {
+ Thread t = Thread.currentThread();
+ ThreadLocalMap map = getMap(t);
+ if (map != null) {
+ ThreadLocalMap.Entry e = map.getEntry(this);
+ if (e != null) {
+ @SuppressWarnings("unchecked")
+ T result = (T)e.value;
+ return result;
+ }
+ }
+ return setInitialValue();
+}
+```
+
+ThreadLocal 从理论上讲并不是用来解决多线程并发问题的,因为根本不存在多线程竞争。
+
+在一些场景 (尤其是使用线程池) 下,由于 ThreadLocal.ThreadLocalMap 的底层数据结构导致 ThreadLocal 有内存泄漏的情况,应该尽可能在每次使用 ThreadLocal 后手动调用 remove(),以避免出现 ThreadLocal 经典的内存泄漏甚至是造成自身业务混乱的风险。
+
+### 3. 可重入代码(Reentrant Code)
+
+这种代码也叫做纯代码(Pure Code),可以在代码执行的任何时刻中断它,转而去执行另外一段代码(包括递归调用它本身),而在控制权返回后,原来的程序不会出现任何错误。
+
+可重入代码有一些共同的特征,例如不依赖存储在堆上的数据和公用的系统资源、用到的状态量都由参数中传入、不调用非可重入的方法等。
+
+# 十二、锁优化
+
+这里的锁优化主要是指 JVM 对 synchronized 的优化。
+
+## 自旋锁
+
+互斥同步进入阻塞状态的开销都很大,应该尽量避免。在许多应用中,共享数据的锁定状态只会持续很短的一段时间。自旋锁的思想是让一个线程在请求一个共享数据的锁时执行忙循环(自旋)一段时间,如果在这段时间内能获得锁,就可以避免进入阻塞状态。
+
+自旋锁虽然能避免进入阻塞状态从而减少开销,但是它需要进行忙循环操作占用 CPU 时间,它只适用于共享数据的锁定状态很短的场景。
+
+在 JDK 1.6 中引入了自适应的自旋锁。自适应意味着自旋的次数不再固定了,而是由前一次在同一个锁上的自旋次数及锁的拥有者的状态来决定。
+
+## 锁消除
+
+锁消除是指对于被检测出不可能存在竞争的共享数据的锁进行消除。
+
+锁消除主要是通过逃逸分析来支持,如果堆上的共享数据不可能逃逸出去被其它线程访问到,那么就可以把它们当成私有数据对待,也就可以将它们的锁进行消除。
+
+对于一些看起来没有加锁的代码,其实隐式的加了很多锁。例如下面的字符串拼接代码就隐式加了锁:
+
+```java
+public static String concatString(String s1, String s2, String s3) {
+ return s1 + s2 + s3;
+}
+```
+
+String 是一个不可变的类,编译器会对 String 的拼接自动优化。在 JDK 1.5 之前,会转化为 StringBuffer 对象的连续 append() 操作:
+
+```java
+public static String concatString(String s1, String s2, String s3) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(s1);
+ sb.append(s2);
+ sb.append(s3);
+ return sb.toString();
+}
+```
+
+每个 append() 方法中都有一个同步块。虚拟机观察变量 sb,很快就会发现它的动态作用域被限制在 concatString() 方法内部。也就是说,sb 的所有引用永远不会逃逸到 concatString() 方法之外,其他线程无法访问到它,因此可以进行消除。
+
+## 锁粗化
+
+如果一系列的连续操作都对同一个对象反复加锁和解锁,频繁的加锁操作就会导致性能损耗。
+
+上一节的示例代码中连续的 append() 方法就属于这类情况。如果虚拟机探测到由这样的一串零碎的操作都对同一个对象加锁,将会把加锁的范围扩展(粗化)到整个操作序列的外部。对于上一节的示例代码就是扩展到第一个 append() 操作之前直至最后一个 append() 操作之后,这样只需要加锁一次就可以了。
+
+## 轻量级锁
+
+JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:无锁状态(unlocked)、偏向锁状态(biasble)、轻量级锁状态(lightweight locked)和重量级锁状态(inflated)。
+
+以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
+
+
+
+下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象,包含了 Mark Word 和其它信息。
+
+
+
+轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
+
+当尝试获取一个锁对象时,如果锁对象标记为 0 01,说明锁对象的锁未锁定(unlocked)状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record,然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00,表示该对象处于轻量级锁状态。
+
+
+
+如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
+
+## 偏向锁
+
+偏向锁的思想是偏向于让第一个获取锁对象的线程,这个线程在之后获取该锁就不再需要进行同步操作,甚至连 CAS 操作也不再需要。
+
+当锁对象第一次被线程获得的时候,进入偏向状态,标记为 1 01。同时使用 CAS 操作将线程 ID 记录到 Mark Word 中,如果 CAS 操作成功,这个线程以后每次进入这个锁相关的同步块就不需要再进行任何同步操作。
+
+当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定状态或者轻量级锁状态。
+
+
+
+# 十三、多线程开发良好的实践
+
+- 给线程起个有意义的名字,这样可以方便找 Bug。
+
+- 缩小同步范围,从而减少锁争用。例如对于 synchronized,应该尽量使用同步块而不是同步方法。
+
+- 多用同步工具少用 wait() 和 notify()。首先,CountDownLatch, CyclicBarrier, Semaphore 和 Exchanger 这些同步类简化了编码操作,而用 wait() 和 notify() 很难实现复杂控制流;其次,这些同步类是由最好的企业编写和维护,在后续的 JDK 中还会不断优化和完善。
+
+- 使用 BlockingQueue 实现生产者消费者问题。
+
+- 多用并发集合少用同步集合,例如应该使用 ConcurrentHashMap 而不是 Hashtable。
+
+- 使用本地变量和不可变类来保证线程安全。
+
+- 使用线程池而不是直接创建线程,这是因为创建线程代价很高,线程池可以有效地利用有限的线程来启动任务。
+
+# 参考资料
+
+- BruceEckel. Java 编程思想: 第 4 版 [M]. 机械工业出版社, 2007.
+- 周志明. 深入理解 Java 虚拟机 [M]. 机械工业出版社, 2011.
+- [Threads and Locks](https://docs.oracle.com/javase/specs/jvms/se6/html/Threads.doc.html)
+- [线程通信](http://ifeve.com/thread-signaling/#missed_signal)
+- [Java 线程面试题 Top 50](http://www.importnew.com/12773.html)
+- [BlockingQueue](http://tutorials.jenkov.com/java-util-concurrent/blockingqueue.html)
+- [thread state java](https://stackoverflow.com/questions/11265289/thread-state-java)
+- [CSC 456 Spring 2012/ch7 MN](http://wiki.expertiza.ncsu.edu/index.php/CSC_456_Spring_2012/ch7_MN)
+- [Java - Understanding Happens-before relationship](https://www.logicbig.com/tutorials/core-java-tutorial/java-multi-threading/happens-before.html)
+- [6장 Thread Synchronization](https://www.slideshare.net/novathinker/6-thread-synchronization)
+- [How is Java's ThreadLocal implemented under the hood?](https://stackoverflow.com/questions/1202444/how-is-javas-threadlocal-implemented-under-the-hood/15653015)
+- [Concurrent](https://sites.google.com/site/webdevelopart/21-compile/06-java/javase/concurrent?tmpl=%2Fsystem%2Fapp%2Ftemplates%2Fprint%2F&showPrintDialog=1)
+- [JAVA FORK JOIN EXAMPLE](http://www.javacreed.com/java-fork-join-example/ "Java Fork Join Example")
+- [聊聊并发(八)——Fork/Join 框架介绍](http://ifeve.com/talk-concurrency-forkjoin/)
+- [Eliminating SynchronizationRelated Atomic Operations with Biased Locking and Bulk Rebiasing](http://www.oracle.com/technetwork/java/javase/tech/biasedlocking-oopsla2006-preso-150106.pdf)
diff --git a/docs1/docs/notes/Java 虚拟机.md b/docs1/docs/notes/Java 虚拟机.md
new file mode 100644
index 00000000..3138a170
--- /dev/null
+++ b/docs1/docs/notes/Java 虚拟机.md
@@ -0,0 +1,749 @@
+
+* [一、运行时数据区域](#一运行时数据区域)
+ * [程序计数器](#程序计数器)
+ * [Java 虚拟机栈](#java-虚拟机栈)
+ * [本地方法栈](#本地方法栈)
+ * [堆](#堆)
+ * [方法区](#方法区)
+ * [运行时常量池](#运行时常量池)
+ * [直接内存](#直接内存)
+* [二、垃圾收集](#二垃圾收集)
+ * [判断一个对象是否可被回收](#判断一个对象是否可被回收)
+ * [引用类型](#引用类型)
+ * [垃圾收集算法](#垃圾收集算法)
+ * [垃圾收集器](#垃圾收集器)
+* [三、内存分配与回收策略](#三内存分配与回收策略)
+ * [Minor GC 和 Full GC](#minor-gc-和-full-gc)
+ * [内存分配策略](#内存分配策略)
+ * [Full GC 的触发条件](#full-gc-的触发条件)
+* [四、类加载机制](#四类加载机制)
+ * [类的生命周期](#类的生命周期)
+ * [类加载过程](#类加载过程)
+ * [类初始化时机](#类初始化时机)
+ * [类与类加载器](#类与类加载器)
+ * [类加载器分类](#类加载器分类)
+ * [双亲委派模型](#双亲委派模型)
+ * [自定义类加载器实现](#自定义类加载器实现)
+* [参考资料](#参考资料)
+
+
+
+# 一、运行时数据区域
+
+
+
+## 程序计数器
+
+记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)。
+
+## Java 虚拟机栈
+
+每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
+
+
+
+可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
+
+```java
+java -Xss512M HackTheJava
+```
+
+该区域可能抛出以下异常:
+
+- 当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常;
+- 栈进行动态扩展时如果无法申请到足够内存,会抛出 OutOfMemoryError 异常。
+
+## 本地方法栈
+
+本地方法栈与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。
+
+本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
+
+
+
+## 堆
+
+所有对象都在这里分配内存,是垃圾收集的主要区域("GC 堆")。
+
+现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法,可以将堆分成两块:
+
+- 新生代(Young Generation)
+- 老年代(Old Generation)
+
+堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。
+
+可以通过 -Xms 和 -Xmx 两个虚拟机参数来指定一个程序的堆内存大小,第一个参数设置初始值,第二个参数设置最大值。
+
+```java
+java -Xms1M -Xmx2M HackTheJava
+```
+
+## 方法区
+
+用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
+
+和堆一样不需要连续的内存,并且可以动态扩展,动态扩展失败一样会抛出 OutOfMemoryError 异常。
+
+对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现。
+
+HotSpot 虚拟机把它当成永久代来进行垃圾回收。但是很难确定永久代的大小,因为它受到很多因素影响,并且每次 Full GC 之后永久代的大小都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更容易管理方法区,从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。
+
+## 运行时常量池
+
+运行时常量池是方法区的一部分。
+
+Class 文件中的常量池(编译器生成的各种字面量和符号引用)会在类加载后被放入这个区域。
+
+除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。
+
+## 直接内存
+
+在 JDK 1.4 中新加入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存(Native 堆),然后通过一个存储在 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。
+
+这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。
+
+# 二、垃圾收集
+
+垃圾收集主要是针对堆和方法区进行。
+
+程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收。
+
+## 判断一个对象是否可被回收
+
+### 1. 引用计数算法
+
+给对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。
+
+两个对象出现循环引用的情况下,此时引用计数器永远不为 0,导致无法对它们进行回收。
+
+正因为循环引用的存在,因此 Java 虚拟机不使用引用计数算法。
+
+```java
+public class ReferenceCountingGC {
+
+ public Object instance = null;
+
+ public static void main(String[] args) {
+ ReferenceCountingGC objectA = new ReferenceCountingGC();
+ ReferenceCountingGC objectB = new ReferenceCountingGC();
+ objectA.instance = objectB;
+ objectB.instance = objectA;
+ }
+}
+```
+
+### 2. 可达性分析算法
+
+通过 GC Roots 作为起始点进行搜索,能够到达到的对象都是存活的,不可达的对象可被回收。
+
+Java 虚拟机使用该算法来判断对象是否可被回收,在 Java 中 GC Roots 一般包含以下内容:
+
+- 虚拟机栈中局部变量表中引用的对象
+- 本地方法栈中 JNI 中引用的对象
+- 方法区中类静态属性引用的对象
+- 方法区中的常量引用的对象
+
+
+
+### 3. 方法区的回收
+
+因为方法区主要存放永久代对象,而永久代对象的回收率比新生代低很多,因此在方法区上进行回收性价比不高。
+
+主要是对常量池的回收和对类的卸载。
+
+在大量使用反射、动态代理、CGLib 等 ByteCode 框架、动态生成 JSP 以及 OSGi 这类频繁自定义 ClassLoader 的场景都需要虚拟机具备类卸载功能,以保证不会出现内存溢出。
+
+类的卸载条件很多,需要满足以下三个条件,并且满足了也不一定会被卸载:
+
+- 该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。
+- 加载该类的 ClassLoader 已经被回收。
+- 该类对应的 Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。
+
+可以通过 -Xnoclassgc 参数来控制是否对类进行卸载。
+
+### 4. finalize()
+
+finalize() 类似 C++ 的析构函数,用来做关闭外部资源等工作。但是 try-finally 等方式可以做的更好,并且该方法运行代价高昂,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。
+
+当一个对象可被回收时,如果需要执行该对象的 finalize() 方法,那么就有可能在该方法中让对象重新被引用,从而实现自救。自救只能进行一次,如果回收的对象之前调用了 finalize() 方法自救,后面回收时不会调用 finalize() 方法。
+
+## 引用类型
+
+无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象是否可达,判定对象是否可被回收都与引用有关。
+
+Java 提供了四种强度不同的引用类型。
+
+### 1. 强引用
+
+被强引用关联的对象不会被回收。
+
+使用 new 一个新对象的方式来创建强引用。
+
+```java
+Object obj = new Object();
+```
+
+### 2. 软引用
+
+被软引用关联的对象只有在内存不够的情况下才会被回收。
+
+使用 SoftReference 类来创建软引用。
+
+```java
+Object obj = new Object();
+SoftReference sf = new SoftReference(obj);
+obj = null; // 使对象只被软引用关联
+```
+
+### 3. 弱引用
+
+被弱引用关联的对象一定会被回收,也就是说它只能存活到下一次垃圾回收发生之前。
+
+使用 WeakReference 类来实现弱引用。
+
+```java
+Object obj = new Object();
+WeakReference wf = new WeakReference(obj);
+obj = null;
+```
+
+### 4. 虚引用
+
+又称为幽灵引用或者幻影引用。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象。
+
+为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。
+
+使用 PhantomReference 来实现虚引用。
+
+```java
+Object obj = new Object();
+PhantomReference pf = new PhantomReference(obj);
+obj = null;
+```
+
+## 垃圾收集算法
+
+### 1. 标记 - 清除
+
+
+
+标记要回收的对象,然后清除。
+
+不足:
+
+- 标记和清除过程效率都不高;
+- 会产生大量不连续的内存碎片,导致无法给大对象分配内存。
+
+### 2. 标记 - 整理
+
+
+
+让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
+
+### 3. 复制
+
+
+
+将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
+
+主要不足是只使用了内存的一半。
+
+现在的商业虚拟机都采用这种收集算法来回收新生代,但是并不是将新生代划分为大小相等的两块,而是分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 空间和其中一块 Survivor。在回收时,将 Eden 和 Survivor 中还存活着的对象一次性复制到另一块 Survivor 空间上,最后清理 Eden 和使用过的那一块 Survivor。
+
+HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1,保证了内存的利用率达到 90%。如果每次回收有多于 10% 的对象存活,那么一块 Survivor 空间就不够用了,此时需要依赖于老年代进行分配担保,也就是借用老年代的空间存储放不下的对象。
+
+### 4. 分代收集
+
+现在的商业虚拟机采用分代收集算法,它根据对象存活周期将内存划分为几块,不同块采用适当的收集算法。
+
+一般将堆分为新生代和老年代。
+
+- 新生代使用:复制算法
+- 老年代使用:标记 - 清除 或者 标记 - 整理 算法
+
+## 垃圾收集器
+
+
+
+以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
+
+- 单线程与多线程:单线程指的是垃圾收集器只使用一个线程进行收集,而多线程使用多个线程;
+- 串行与并行:串行指的是垃圾收集器与用户程序交替执行,这意味着在执行垃圾收集的时候需要停顿用户程序;并行指的是垃圾收集器和用户程序同时执行。除了 CMS 和 G1 之外,其它垃圾收集器都是以串行的方式执行。
+
+### 1. Serial 收集器
+
+
+
+Serial 翻译为串行,也就是说它以串行的方式执行。
+
+它是单线程的收集器,只会使用一个线程进行垃圾收集工作。
+
+它的优点是简单高效,对于单个 CPU 环境来说,由于没有线程交互的开销,因此拥有最高的单线程收集效率。
+
+它是 Client 模式下的默认新生代收集器,因为在该应用场景下,分配给虚拟机管理的内存一般来说不会很大。Serial 收集器收集几十兆甚至一两百兆的新生代停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿是可以接受的。
+
+### 2. ParNew 收集器
+
+
+
+它是 Serial 收集器的多线程版本。
+
+是 Server 模式下的虚拟机首选新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合工作。
+
+默认开启的线程数量与 CPU 数量相同,可以使用 -XX:ParallelGCThreads 参数来设置线程数。
+
+### 3. Parallel Scavenge 收集器
+
+与 ParNew 一样是多线程收集器。
+
+其它收集器关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,它被称为“吞吐量优先”收集器。这里的吞吐量指 CPU 用于运行用户代码的时间占总时间的比值。
+
+停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,适合在后台运算而不需要太多交互的任务。
+
+缩短停顿时间是以牺牲吞吐量和新生代空间来换取的:新生代空间变小,垃圾回收变得频繁,导致吞吐量下降。
+
+可以通过一个开关参数打开 GC 自适应的调节策略(GC Ergonomics),就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例、晋升老年代对象年龄等细节参数了。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。
+
+### 4. Serial Old 收集器
+
+
+
+是 Serial 收集器的老年代版本,也是给 Client 模式下的虚拟机使用。如果用在 Server 模式下,它有两大用途:
+
+- 在 JDK 1.5 以及之前版本(Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用。
+- 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。
+
+### 5. Parallel Old 收集器
+
+
+
+是 Parallel Scavenge 收集器的老年代版本。
+
+在注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器。
+
+### 6. CMS 收集器
+
+
+
+CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。
+
+分为以下四个流程:
+
+- 初始标记:仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿。
+- 并发标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿。
+- 重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿。
+- 并发清除:不需要停顿。
+
+在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,不需要进行停顿。
+
+具有以下缺点:
+
+- 吞吐量低:低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率不够高。
+- 无法处理浮动垃圾,可能出现 Concurrent Mode Failure。浮动垃圾是指并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS。
+- 标记 - 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC。
+
+### 7. G1 收集器
+
+G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。HotSpot 开发团队赋予它的使命是未来可以替换掉 CMS 收集器。
+
+堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
+
+
+
+G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。
+
+
+
+通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
+
+每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。
+
+
+
+如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:
+
+- 初始标记
+- 并发标记
+- 最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行。
+- 筛选回收:首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。
+
+具备如下特点:
+
+- 空间整合:整体来看是基于“标记 - 整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的,这意味着运行期间不会产生内存空间碎片。
+- 可预测的停顿:能让使用者明确指定在一个长度为 M 毫秒的时间片段内,消耗在 GC 上的时间不得超过 N 毫秒。
+
+# 三、内存分配与回收策略
+
+## Minor GC 和 Full GC
+
+- Minor GC:发生在新生代上,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。
+
+- Full GC:发生在老年代上,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。
+
+## 内存分配策略
+
+### 1. 对象优先在 Eden 分配
+
+大多数情况下,对象在新生代 Eden 区分配,当 Eden 区空间不够时,发起 Minor GC。
+
+### 2. 大对象直接进入老年代
+
+大对象是指需要连续内存空间的对象,最典型的大对象是那种很长的字符串以及数组。
+
+经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。
+
+-XX:PretenureSizeThreshold,大于此值的对象直接在老年代分配,避免在 Eden 区和 Survivor 区之间的大量内存复制。
+
+### 3. 长期存活的对象进入老年代
+
+为对象定义年龄计数器,对象在 Eden 出生并经过 Minor GC 依然存活,将移动到 Survivor 中,年龄就增加 1 岁,增加到一定年龄则移动到老年代中。
+
+-XX:MaxTenuringThreshold 用来定义年龄的阈值。
+
+### 4. 动态对象年龄判定
+
+虚拟机并不是永远地要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。
+
+### 5. 空间分配担保
+
+在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。
+
+如果不成立的话虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 设置不允许冒险,那么就要进行一次 Full GC。
+
+## Full GC 的触发条件
+
+对于 Minor GC,其触发条件非常简单,当 Eden 空间满时,就将触发一次 Minor GC。而 Full GC 则相对复杂,有以下条件:
+
+### 1. 调用 System.gc()
+
+只是建议虚拟机执行 Full GC,但是虚拟机不一定真正去执行。不建议使用这种方式,而是让虚拟机管理内存。
+
+### 2. 老年代空间不足
+
+老年代空间不足的常见场景为前文所讲的大对象直接进入老年代、长期存活的对象进入老年代等。
+
+为了避免以上原因引起的 Full GC,应当尽量不要创建过大的对象以及数组。除此之外,可以通过 -Xmn 虚拟机参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代。还可以通过 -XX:MaxTenuringThreshold 调大对象进入老年代的年龄,让对象在新生代多存活一段时间。
+
+### 3. 空间分配担保失败
+
+使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第五小节。
+
+### 4. JDK 1.7 及以前的永久代空间不足
+
+在 JDK 1.7 及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 Class 的信息、常量、静态变量等数据。
+
+当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么虚拟机会抛出 java.lang.OutOfMemoryError。
+
+为避免以上原因引起的 Full GC,可采用的方法为增大永久代空间或转为使用 CMS GC。
+
+### 5. Concurrent Mode Failure
+
+执行 CMS GC 的过程中同时有对象要放入老年代,而此时老年代空间不足(可能是 GC 过程中浮动垃圾过多导致暂时性的空间不足),便会报 Concurrent Mode Failure 错误,并触发 Full GC。
+
+# 四、类加载机制
+
+类是在运行期间第一次使用时动态加载的,而不是编译时期一次性加载。因为如果在编译时期一次性加载,那么会占用很多的内存。
+
+## 类的生命周期
+
+
+
+包括以下 7 个阶段:
+
+- **加载(Loading)**
+- **验证(Verification)**
+- **准备(Preparation)**
+- **解析(Resolution)**
+- **初始化(Initialization)**
+- 使用(Using)
+- 卸载(Unloading)
+
+## 类加载过程
+
+包含了加载、验证、准备、解析和初始化这 5 个阶段。
+
+### 1. 加载
+
+加载是类加载的一个阶段,注意不要混淆。
+
+加载过程完成以下三件事:
+
+- 通过一个类的全限定名来获取定义此类的二进制字节流。
+- 将这个字节流所代表的静态存储结构转化为方法区的运行时存储结构。
+- 在内存中生成一个代表这个类的 Class 对象,作为方法区这个类的各种数据的访问入口。
+
+其中二进制字节流可以从以下方式中获取:
+
+- 从 ZIP 包读取,成为 JAR、EAR、WAR 格式的基础。
+- 从网络中获取,最典型的应用是 Applet。
+- 运行时计算生成,例如动态代理技术,在 java.lang.reflect.Proxy 使用 ProxyGenerator.generateProxyClass 的代理类的二进制字节流。
+- 由其他文件生成,例如由 JSP 文件生成对应的 Class 类。
+
+### 2. 验证
+
+确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
+
+### 3. 准备
+
+类变量是被 static 修饰的变量,准备阶段为类变量分配内存并设置初始值,使用的是方法区的内存。
+
+实例变量不会在这阶段分配内存,它将会在对象实例化时随着对象一起分配在堆中。
+
+注意,实例化不是类加载的一个过程,类加载发生在所有实例化操作之前,并且类加载只进行一次,实例化可以进行多次。
+
+初始值一般为 0 值,例如下面的类变量 value 被初始化为 0 而不是 123。
+
+```java
+public static int value = 123;
+```
+
+如果类变量是常量,那么会按照表达式来进行初始化,而不是赋值为 0。
+
+```java
+public static final int value = 123;
+```
+
+### 4. 解析
+
+将常量池的符号引用替换为直接引用的过程。
+
+其中解析过程在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 的动态绑定。
+
+### 5. 初始化
+
+初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段即虚拟机执行类构造器 <clinit>() 方法的过程。
+
+在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
+
+<clinit>() 方法具有以下特点:
+
+- 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
+
+```java
+public class Test {
+ static {
+ i = 0; // 给变量赋值可以正常编译通过
+ System.out.print(i); // 这句编译器会提示“非法向前引用”
+ }
+ static int i = 1;
+}
+```
+
+- 与类的构造函数(或者说实例构造器 <init>())不同,不需要显式的调用父类的构造器。虚拟机会自动保证在子类的 <clinit>() 方法运行之前,父类的 <clinit>() 方法已经执行结束。因此虚拟机中第一个执行 <clinit>() 方法的类肯定为 java.lang.Object。
+
+- 由于父类的 <clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类。例如以下代码:
+
+```java
+static class Parent {
+ public static int A = 1;
+ static {
+ A = 2;
+ }
+}
+
+static class Sub extends Parent {
+ public static int B = A;
+}
+
+public static void main(String[] args) {
+ System.out.println(Sub.B); // 2
+}
+```
+
+- <clinit>() 方法对于类或接口不是必须的,如果一个类中不包含静态语句块,也没有对类变量的赋值操作,编译器可以不为该类生成 <clinit>() 方法。
+
+- 接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 <clinit>() 方法。但接口与类不同的是,执行接口的 <clinit>() 方法不需要先执行父接口的 <clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 <clinit>() 方法。
+
+- 虚拟机会保证一个类的 <clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 <clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 <clinit>() 方法完毕。如果在一个类的 <clinit>() 方法中有耗时的操作,就可能造成多个线程阻塞,在实际过程中此种阻塞很隐蔽。
+
+## 类初始化时机
+
+### 1. 主动引用
+
+虚拟机规范中并没有强制约束何时进行加载,但是规范严格规定了有且只有下列五种情况必须对类进行初始化(加载、验证、准备都会随之发生):
+
+- 遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时,如果类没有进行过初始化,则必须先触发其初始化。最常见的生成这 4 条指令的场景是:使用 new 关键字实例化对象的时候;读取或设置一个类的静态字段(被 final 修饰、已在编译期把结果放入常量池的静态字段除外)的时候;以及调用一个类的静态方法的时候。
+
+- 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。
+
+- 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
+
+- 当虚拟机启动时,用户需要指定一个要执行的主类(包含 main() 方法的那个类),虚拟机会先初始化这个主类;
+
+- 当使用 JDK 1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果为 REF_getStatic, REF_putStatic, REF_invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化;
+
+### 2. 被动引用
+
+以上 5 种场景中的行为称为对一个类进行主动引用。除此之外,所有引用类的方式都不会触发初始化,称为被动引用。被动引用的常见例子包括:
+
+- 通过子类引用父类的静态字段,不会导致子类初始化。
+
+```java
+System.out.println(SubClass.value); // value 字段在 SuperClass 中定义
+```
+
+- 通过数组定义来引用类,不会触发此类的初始化。该过程会对数组类进行初始化,数组类是一个由虚拟机自动生成的、直接继承自 Object 的子类,其中包含了数组的属性和方法。
+
+```java
+SuperClass[] sca = new SuperClass[10];
+```
+
+- 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
+
+```java
+System.out.println(ConstClass.HELLOWORLD);
+```
+
+## 类与类加载器
+
+两个类相等需要类本身相等,并且使用同一个类加载器进行加载。这是因为每一个类加载器都拥有一个独立的类名称空间。
+
+这里的相等,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果为 true,也包括使用 instanceof 关键字做对象所属关系判定结果为 true。
+
+## 类加载器分类
+
+从 Java 虚拟机的角度来讲,只存在以下两种不同的类加载器:
+
+- 启动类加载器(Bootstrap ClassLoader),这个类加载器用 C++ 实现,是虚拟机自身的一部分;
+
+- 所有其他类的加载器,这些类由 Java 实现,独立于虚拟机外部,并且全都继承自抽象类 java.lang.ClassLoader。
+
+从 Java 开发人员的角度看,类加载器可以划分得更细致一些:
+
+- 启动类加载器(Bootstrap ClassLoader)此类加载器负责将存放在 <JRE_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器,直接使用 null 代替即可。
+
+- 扩展类加载器(Extension ClassLoader)这个类加载器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将 <JAVA_HOME>/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中,开发者可以直接使用扩展类加载器。
+
+- 应用程序类加载器(Application ClassLoader)这个类加载器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此一般称为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
+
+## 双亲委派模型
+
+应用程序都是由三种类加载器相互配合进行加载的,如果有必要,还可以加入自己定义的类加载器。
+
+下图展示的类加载器之间的层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。这里类加载器之间的父子关系一般通过组合(Composition)关系来实现,而不是通过继承(Inheritance)的关系实现。
+
+
+
+### 1. 工作过程
+
+一个类加载器首先将类加载请求传送到父类加载器,只有当父类加载器无法完成类加载请求时才尝试加载。
+
+### 2. 好处
+
+使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。
+
+例如 java.lang.Object 存放在 rt.jar 中,如果编写另外一个 java.lang.Object 的类并放到 ClassPath 中,程序可以编译通过。由于双亲委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 优先级更高,这是因为 rt.jar 中的 Object 使用的是启动类加载器,而 ClassPath 中的 Object 使用的是应用程序类加载器。rt.jar 中的 Object 优先级更高,那么程序中所有的 Object 都是这个 Object。
+
+### 3. 实现
+
+以下是抽象类 java.lang.ClassLoader 的代码片段,其中的 loadClass() 方法运行过程如下:先检查类是否已经加载过,如果没有则让父类加载器去加载。当父类加载器加载失败时抛出 ClassNotFoundException,此时尝试自己去加载。
+
+```java
+public abstract class ClassLoader {
+ // The parent class loader for delegation
+ private final ClassLoader parent;
+
+ public Class> loadClass(String name) throws ClassNotFoundException {
+ return loadClass(name, false);
+ }
+
+ protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ synchronized (getClassLoadingLock(name)) {
+ // First, check if the class has already been loaded
+ Class> c = findLoadedClass(name);
+ if (c == null) {
+ try {
+ if (parent != null) {
+ c = parent.loadClass(name, false);
+ } else {
+ c = findBootstrapClassOrNull(name);
+ }
+ } catch (ClassNotFoundException e) {
+ // ClassNotFoundException thrown if class not found
+ // from the non-null parent class loader
+ }
+
+ if (c == null) {
+ // If still not found, then invoke findClass in order
+ // to find the class.
+ c = findClass(name);
+ }
+ }
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ }
+
+ protected Class> findClass(String name) throws ClassNotFoundException {
+ throw new ClassNotFoundException(name);
+ }
+}
+```
+
+## 自定义类加载器实现
+
+FileSystemClassLoader 是自定义类加载器,继承自 java.lang.ClassLoader,用于加载文件系统上的类。它首先根据类的全名在文件系统上查找类的字节代码文件(.class 文件),然后读取该文件内容,最后通过 defineClass() 方法来把这些字节代码转换成 java.lang.Class 类的实例。
+
+java.lang.ClassLoader 的 loadClass() 实现了双亲委派模型的逻辑,因此自定义类加载器一般不去重写它,但是需要重写 findClass() 方法。
+
+```java
+public class FileSystemClassLoader extends ClassLoader {
+
+ private String rootDir;
+
+ public FileSystemClassLoader(String rootDir) {
+ this.rootDir = rootDir;
+ }
+
+ protected Class> findClass(String name) throws ClassNotFoundException {
+ byte[] classData = getClassData(name);
+ if (classData == null) {
+ throw new ClassNotFoundException();
+ } else {
+ return defineClass(name, classData, 0, classData.length);
+ }
+ }
+
+ private byte[] getClassData(String className) {
+ String path = classNameToPath(className);
+ try {
+ InputStream ins = new FileInputStream(path);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int bufferSize = 4096;
+ byte[] buffer = new byte[bufferSize];
+ int bytesNumRead;
+ while ((bytesNumRead = ins.read(buffer)) != -1) {
+ baos.write(buffer, 0, bytesNumRead);
+ }
+ return baos.toByteArray();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private String classNameToPath(String className) {
+ return rootDir + File.separatorChar
+ + className.replace('.', File.separatorChar) + ".class";
+ }
+}
+```
+
+# 参考资料
+
+- 周志明. 深入理解 Java 虚拟机 [M]. 机械工业出版社, 2011.
+- [Chapter 2. The Structure of the Java Virtual Machine](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4)
+- [Jvm memory](https://www.slideshare.net/benewu/jvm-memory)
+[Getting Started with the G1 Garbage Collector](http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html)
+- [JNI Part1: Java Native Interface Introduction and “Hello World” application](http://electrofriends.com/articles/jni/jni-part1-java-native-interface/)
+- [Memory Architecture Of JVM(Runtime Data Areas)](https://hackthejava.wordpress.com/2015/01/09/memory-architecture-by-jvmruntime-data-areas/)
+- [JVM Run-Time Data Areas](https://www.programcreek.com/2013/04/jvm-run-time-data-areas/)
+- [Android on x86: Java Native Interface and the Android Native Development Kit](http://www.drdobbs.com/architecture-and-design/android-on-x86-java-native-interface-and/240166271)
+- [深入理解 JVM(2)——GC 算法与内存分配策略](https://crowhawk.github.io/2017/08/10/jvm_2/)
+- [深入理解 JVM(3)——7 种垃圾收集器](https://crowhawk.github.io/2017/08/15/jvm_3/)
+- [JVM Internals](http://blog.jamesdbloom.com/JVMInternals.html)
+- [深入探讨 Java 类加载器](https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#code6)
+- [Guide to WeakHashMap in Java](http://www.baeldung.com/java-weakhashmap)
+- [Tomcat example source code file (ConcurrentCache.java)](https://alvinalexander.com/java/jwarehouse/apache-tomcat-6.0.16/java/org/apache/el/util/ConcurrentCache.java.shtml)
diff --git a/docs1/docs/notes/Leetcode 题解.md b/docs1/docs/notes/Leetcode 题解.md
new file mode 100644
index 00000000..e68d7582
--- /dev/null
+++ b/docs1/docs/notes/Leetcode 题解.md
@@ -0,0 +1,7059 @@
+
+* [算法思想](#算法思想)
+ * [双指针](#双指针)
+ * [排序](#排序)
+ * [快速选择](#快速选择)
+ * [堆排序](#堆排序)
+ * [桶排序](#桶排序)
+ * [荷兰国旗问题](#荷兰国旗问题)
+ * [贪心思想](#贪心思想)
+ * [二分查找](#二分查找)
+ * [分治](#分治)
+ * [搜索](#搜索)
+ * [BFS](#bfs)
+ * [DFS](#dfs)
+ * [Backtracking](#backtracking)
+ * [动态规划](#动态规划)
+ * [斐波那契数列](#斐波那契数列)
+ * [矩阵路径](#矩阵路径)
+ * [数组区间](#数组区间)
+ * [分割整数](#分割整数)
+ * [最长递增子序列](#最长递增子序列)
+ * [最长公共子序列](#最长公共子序列)
+ * [0-1 背包](#0-1-背包)
+ * [股票交易](#股票交易)
+ * [字符串编辑](#字符串编辑)
+ * [数学](#数学)
+ * [素数](#素数)
+ * [最大公约数](#最大公约数)
+ * [进制转换](#进制转换)
+ * [阶乘](#阶乘)
+ * [字符串加法减法](#字符串加法减法)
+ * [相遇问题](#相遇问题)
+ * [多数投票问题](#多数投票问题)
+ * [其它](#其它)
+* [数据结构相关](#数据结构相关)
+ * [链表](#链表)
+ * [树](#树)
+ * [递归](#递归)
+ * [层次遍历](#层次遍历)
+ * [前中后序遍历](#前中后序遍历)
+ * [BST](#bst)
+ * [Trie](#trie)
+ * [栈和队列](#栈和队列)
+ * [哈希表](#哈希表)
+ * [字符串](#字符串)
+ * [数组与矩阵](#数组与矩阵)
+ * [图](#图)
+ * [二分图](#二分图)
+ * [拓扑排序](#拓扑排序)
+ * [并查集](#并查集)
+ * [位运算](#位运算)
+* [参考资料](#参考资料)
+
+
+
+# 算法思想
+
+## 双指针
+
+双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。
+
+**有序数组的 Two Sum**
+
+[Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/)
+
+```html
+Input: numbers={2, 7, 11, 15}, target=9
+Output: index1=1, index2=2
+```
+
+题目描述:在有序数组中找出两个数,使它们的和为 target。
+
+使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
+
+- 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
+- 如果 sum > target,移动较大的元素,使 sum 变小一些;
+- 如果 sum < target,移动较小的元素,使 sum 变大一些。
+
+```java
+public int[] twoSum(int[] numbers, int target) {
+ int i = 0, j = numbers.length - 1;
+ while (i < j) {
+ int sum = numbers[i] + numbers[j];
+ if (sum == target) {
+ return new int[]{i + 1, j + 1};
+ } else if (sum < target) {
+ i++;
+ } else {
+ j--;
+ }
+ }
+ return null;
+}
+```
+
+**两数平方和**
+
+[633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/)
+
+```html
+Input: 5
+Output: True
+Explanation: 1 * 1 + 2 * 2 = 5
+```
+
+题目描述:判断一个数是否为两个数的平方和。
+
+```java
+public boolean judgeSquareSum(int c) {
+ int i = 0, j = (int) Math.sqrt(c);
+ while (i <= j) {
+ int powSum = i * i + j * j;
+ if (powSum == c) {
+ return true;
+ } else if (powSum > c) {
+ j--;
+ } else {
+ i++;
+ }
+ }
+ return false;
+}
+```
+
+**反转字符串中的元音字符**
+
+[345. Reverse Vowels of a String (Easy)](https://leetcode.com/problems/reverse-vowels-of-a-string/description/)
+
+```html
+Given s = "leetcode", return "leotcede".
+```
+
+使用双指针指向待反转的两个元音字符,一个指针从头向尾遍历,一个指针从尾到头遍历。
+
+```java
+private final static HashSet vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
+
+public String reverseVowels(String s) {
+ int i = 0, j = s.length() - 1;
+ char[] result = new char[s.length()];
+ while (i <= j) {
+ char ci = s.charAt(i);
+ char cj = s.charAt(j);
+ if (!vowels.contains(ci)) {
+ result[i++] = ci;
+ } else if (!vowels.contains(cj)) {
+ result[j--] = cj;
+ } else {
+ result[i++] = cj;
+ result[j--] = ci;
+ }
+ }
+ return new String(result);
+}
+```
+
+**回文字符串**
+
+[680. Valid Palindrome II (Easy)](https://leetcode.com/problems/valid-palindrome-ii/description/)
+
+```html
+Input: "abca"
+Output: True
+Explanation: You could delete the character 'c'.
+```
+
+题目描述:可以删除一个字符,判断是否能构成回文字符串。
+
+```java
+public boolean validPalindrome(String s) {
+ int i = -1, j = s.length();
+ while (++i < --j) {
+ if (s.charAt(i) != s.charAt(j)) {
+ return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);
+ }
+ }
+ return true;
+}
+
+private boolean isPalindrome(String s, int i, int j) {
+ while (i < j) {
+ if (s.charAt(i++) != s.charAt(j--)) {
+ return false;
+ }
+ }
+ return true;
+}
+```
+
+**归并两个有序数组**
+
+[88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/)
+
+```html
+Input:
+nums1 = [1,2,3,0,0,0], m = 3
+nums2 = [2,5,6], n = 3
+
+Output: [1,2,2,3,5,6]
+```
+
+题目描述:把归并结果存到第一个数组上。
+
+需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值。
+
+```java
+public void merge(int[] nums1, int m, int[] nums2, int n) {
+ int index1 = m - 1, index2 = n - 1;
+ int indexMerge = m + n - 1;
+ while (index1 >= 0 || index2 >= 0) {
+ if (index1 < 0) {
+ nums1[indexMerge--] = nums2[index2--];
+ } else if (index2 < 0) {
+ nums1[indexMerge--] = nums1[index1--];
+ } else if (nums1[index1] > nums2[index2]) {
+ nums1[indexMerge--] = nums1[index1--];
+ } else {
+ nums1[indexMerge--] = nums2[index2--];
+ }
+ }
+}
+```
+
+**判断链表是否存在环**
+
+[141. Linked List Cycle (Easy)](https://leetcode.com/problems/linked-list-cycle/description/)
+
+使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。
+
+```java
+public boolean hasCycle(ListNode head) {
+ if (head == null) {
+ return false;
+ }
+ ListNode l1 = head, l2 = head.next;
+ while (l1 != null && l2 != null && l2.next != null) {
+ if (l1 == l2) {
+ return true;
+ }
+ l1 = l1.next;
+ l2 = l2.next.next;
+ }
+ return false;
+}
+```
+
+**最长子序列**
+
+[524. Longest Word in Dictionary through Deleting (Medium)](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/description/)
+
+```
+Input:
+s = "abpcplea", d = ["ale","apple","monkey","plea"]
+
+Output:
+"apple"
+```
+
+题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最大字符串。
+
+```java
+public String findLongestWord(String s, List d) {
+ String longestWord = "";
+ for (String target : d) {
+ int l1 = longestWord.length(), l2 = target.length();
+ if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) {
+ continue;
+ }
+ if (isValid(s, target)) {
+ longestWord = target;
+ }
+ }
+ return longestWord;
+}
+
+private boolean isValid(String s, String target) {
+ int i = 0, j = 0;
+ while (i < s.length() && j < target.length()) {
+ if (s.charAt(i) == target.charAt(j)) {
+ j++;
+ }
+ i++;
+ }
+ return j == target.length();
+}
+```
+
+## 排序
+
+### 快速选择
+
+用于求解 **Kth Element** 问题,使用快速排序的 partition() 进行实现。
+
+需要先打乱数组,否则最坏情况下时间复杂度为 O(N2 )。
+
+### 堆排序
+
+用于求解 **TopK Elements** 问题,通过维护一个大小为 K 的堆,堆中的元素就是 TopK Elements。
+
+堆排序也可以用于求解 Kth Element 问题,堆顶元素就是 Kth Element。
+
+快速选择也可以求解 TopK Elements 问题,因为找到 Kth Element 之后,再遍历一次数组,所有小于等于 Kth Element 的元素都是 TopK Elements。
+
+可以看到,快速选择和堆排序都可以求解 Kth Element 和 TopK Elements 问题。
+
+**Kth Element**
+
+[215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/)
+
+题目描述:找到第 k 大的元素。
+
+**排序** :时间复杂度 O(NlogN),空间复杂度 O(1)
+
+```java
+public int findKthLargest(int[] nums, int k) {
+ Arrays.sort(nums);
+ return nums[nums.length - k];
+}
+```
+
+**堆排序** :时间复杂度 O(NlogK),空间复杂度 O(K)。
+
+```java
+public int findKthLargest(int[] nums, int k) {
+ PriorityQueue pq = new PriorityQueue<>(); // 小顶堆
+ for (int val : nums) {
+ pq.add(val);
+ if (pq.size() > k) // 维护堆的大小为 K
+ pq.poll();
+ }
+ return pq.peek();
+}
+```
+
+**快速选择** :时间复杂度 O(N),空间复杂度 O(1)
+
+```java
+public int findKthLargest(int[] nums, int k) {
+ k = nums.length - k;
+ int l = 0, h = nums.length - 1;
+ while (l < h) {
+ int j = partition(nums, l, h);
+ if (j == k) {
+ break;
+ } else if (j < k) {
+ l = j + 1;
+ } else {
+ h = j - 1;
+ }
+ }
+ return nums[k];
+}
+
+private int partition(int[] a, int l, int h) {
+ int i = l, j = h + 1;
+ while (true) {
+ while (a[++i] < a[l] && i < h) ;
+ while (a[--j] > a[l] && j > l) ;
+ if (i >= j) {
+ break;
+ }
+ swap(a, i, j);
+ }
+ swap(a, l, j);
+ return j;
+}
+
+private void swap(int[] a, int i, int j) {
+ int t = a[i];
+ a[i] = a[j];
+ a[j] = t;
+}
+```
+
+### 桶排序
+
+**出现频率最多的 k 个数**
+
+[347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/)
+
+```html
+Given [1,1,1,2,2,3] and k = 2, return [1,2].
+```
+
+设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率,即第 i 个桶中存储的数出现的频率为 i。
+
+把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。
+
+```java
+public List topKFrequent(int[] nums, int k) {
+ Map frequencyForNum = new HashMap<>();
+ for (int num : nums) {
+ frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1);
+ }
+ List[] buckets = new ArrayList[nums.length + 1];
+ for (int key : frequencyForNum.keySet()) {
+ int frequency = frequencyForNum.get(key);
+ if (buckets[frequency] == null) {
+ buckets[frequency] = new ArrayList<>();
+ }
+ buckets[frequency].add(key);
+ }
+ List topK = new ArrayList<>();
+ for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) {
+ if (buckets[i] != null) {
+ topK.addAll(buckets[i]);
+ }
+ }
+ return topK;
+}
+```
+
+**按照字符出现次数对字符串排序**
+
+[451. Sort Characters By Frequency (Medium)](https://leetcode.com/problems/sort-characters-by-frequency/description/)
+
+```html
+Input:
+"tree"
+
+Output:
+"eert"
+
+Explanation:
+'e' appears twice while 'r' and 't' both appear once.
+So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
+```
+
+```java
+public String frequencySort(String s) {
+ Map frequencyForNum = new HashMap<>();
+ for (char c : s.toCharArray())
+ frequencyForNum.put(c, frequencyForNum.getOrDefault(c, 0) + 1);
+
+ List[] frequencyBucket = new ArrayList[s.length() + 1];
+ for (char c : frequencyForNum.keySet()) {
+ int f = frequencyForNum.get(c);
+ if (frequencyBucket[f] == null) {
+ frequencyBucket[f] = new ArrayList<>();
+ }
+ frequencyBucket[f].add(c);
+ }
+ StringBuilder str = new StringBuilder();
+ for (int i = frequencyBucket.length - 1; i >= 0; i--) {
+ if (frequencyBucket[i] == null) {
+ continue;
+ }
+ for (char c : frequencyBucket[i]) {
+ for (int j = 0; j < i; j++) {
+ str.append(c);
+ }
+ }
+ }
+ return str.toString();
+}
+```
+
+### 荷兰国旗问题
+
+荷兰国旗包含三种颜色:红、白、蓝。
+
+有三种颜色的球,算法的目标是将这三种球按颜色顺序正确地排列。
+
+它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。
+
+
+
+**按颜色进行排序**
+
+[75. Sort Colors (Medium)](https://leetcode.com/problems/sort-colors/description/)
+
+```html
+Input: [2,0,2,1,1,0]
+Output: [0,0,1,1,2,2]
+```
+
+题目描述:只有 0/1/2 三种颜色。
+
+```java
+public void sortColors(int[] nums) {
+ int zero = -1, one = 0, two = nums.length;
+ while (one < two) {
+ if (nums[one] == 0) {
+ swap(nums, ++zero, one++);
+ } else if (nums[one] == 2) {
+ swap(nums, --two, one);
+ } else {
+ ++one;
+ }
+ }
+}
+
+private void swap(int[] nums, int i, int j) {
+ int t = nums[i];
+ nums[i] = nums[j];
+ nums[j] = t;
+}
+```
+
+## 贪心思想
+
+保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。
+
+**分配饼干**
+
+[455. Assign Cookies (Easy)](https://leetcode.com/problems/assign-cookies/description/)
+
+```html
+Input: [1,2], [1,2,3]
+Output: 2
+
+Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2.
+You have 3 cookies and their sizes are big enough to gratify all of the children,
+You need to output 2.
+```
+
+题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。
+
+给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因为最小的孩子最容易得到满足,所以先满足最小的孩子。
+
+证明:假设在某次选择中,贪心策略选择给当前满足度最小的孩子分配第 m 个饼干,第 m 个饼干为可以满足该孩子的最小饼干。假设存在一种最优策略,给该孩子分配第 n 个饼干,并且 m < n。我们可以发现,经过这一轮分配,贪心策略分配后剩下的饼干一定有一个比最优策略来得大。因此在后续的分配中,贪心策略一定能满足更多的孩子。也就是说不存在比贪心策略更优的策略,即贪心策略就是最优策略。
+
+```java
+public int findContentChildren(int[] g, int[] s) {
+ Arrays.sort(g);
+ Arrays.sort(s);
+ int gi = 0, si = 0;
+ while (gi < g.length && si < s.length) {
+ if (g[gi] <= s[si]) {
+ gi++;
+ }
+ si++;
+ }
+ return gi;
+}
+```
+
+**不重叠的区间个数**
+
+[435. Non-overlapping Intervals (Medium)](https://leetcode.com/problems/non-overlapping-intervals/description/)
+
+```html
+Input: [ [1,2], [1,2], [1,2] ]
+
+Output: 2
+
+Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping.
+```
+
+```html
+Input: [ [1,2], [2,3] ]
+
+Output: 0
+
+Explanation: You don't need to remove any of the intervals since they're already non-overlapping.
+```
+
+题目描述:计算让一组区间不重叠所需要移除的区间个数。
+
+先计算最多能组成的不重叠区间个数,然后用区间总个数减去不重叠区间的个数。
+
+在每次选择中,区间的结尾最为重要,选择的区间结尾越小,留给后面的区间的空间越大,那么后面能够选择的区间个数也就越大。
+
+按区间的结尾进行排序,每次选择结尾最小,并且和前一个区间不重叠的区间。
+
+```java
+public int eraseOverlapIntervals(Interval[] intervals) {
+ if (intervals.length == 0) {
+ return 0;
+ }
+ Arrays.sort(intervals, Comparator.comparingInt(o -> o.end));
+ int cnt = 1;
+ int end = intervals[0].end;
+ for (int i = 1; i < intervals.length; i++) {
+ if (intervals[i].start < end) {
+ continue;
+ }
+ end = intervals[i].end;
+ cnt++;
+ }
+ return intervals.length - cnt;
+}
+```
+
+使用 lambda 表示式创建 Comparator 会导致算法运行时间过长,如果注重运行时间,可以修改为普通创建 Comparator 语句:
+
+```java
+Arrays.sort(intervals, new Comparator() {
+ @Override
+ public int compare(Interval o1, Interval o2) {
+ return o1.end - o2.end;
+ }
+});
+```
+
+**投飞镖刺破气球**
+
+[452. Minimum Number of Arrows to Burst Balloons (Medium)](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/description/)
+
+```
+Input:
+[[10,16], [2,8], [1,6], [7,12]]
+
+Output:
+2
+```
+
+题目描述:气球在一个水平数轴上摆放,可以重叠,飞镖垂直投向坐标轴,使得路径上的气球都会刺破。求解最小的投飞镖次数使所有气球都被刺破。
+
+也是计算不重叠的区间个数,不过和 Non-overlapping Intervals 的区别在于,[1, 2] 和 [2, 3] 在本题中算是重叠区间。
+
+```java
+public int findMinArrowShots(int[][] points) {
+ if (points.length == 0) {
+ return 0;
+ }
+ Arrays.sort(points, Comparator.comparingInt(o -> o[1]));
+ int cnt = 1, end = points[0][1];
+ for (int i = 1; i < points.length; i++) {
+ if (points[i][0] <= end) {
+ continue;
+ }
+ cnt++;
+ end = points[i][1];
+ }
+ return cnt;
+}
+```
+
+**根据身高和序号重组队列**
+
+[406. Queue Reconstruction by Height(Medium)](https://leetcode.com/problems/queue-reconstruction-by-height/description/)
+
+```html
+Input:
+[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
+
+Output:
+[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
+```
+
+题目描述:一个学生用两个分量 (h, k) 描述,h 表示身高,k 表示排在前面的有 k 个学生的身高比他高或者和他一样高。
+
+为了使插入操作不影响后续的操作,身高较高的学生应该先做插入操作,否则身高较小的学生原先正确插入的第 k 个位置可能会变成第 k+1 个位置。
+
+身高降序、k 值升序,然后按排好序的顺序插入队列的第 k 个位置中。
+
+```java
+public int[][] reconstructQueue(int[][] people) {
+ if (people == null || people.length == 0 || people[0].length == 0) {
+ return new int[0][0];
+ }
+ Arrays.sort(people, (a, b) -> (a[0] == b[0] ? a[1] - b[1] : b[0] - a[0]));
+ List queue = new ArrayList<>();
+ for (int[] p : people) {
+ queue.add(p[1], p);
+ }
+ return queue.toArray(new int[queue.size()][]);
+}
+```
+
+**分隔字符串使同种字符出现在一起**
+
+[763. Partition Labels (Medium)](https://leetcode.com/problems/partition-labels/description/)
+
+```html
+Input: S = "ababcbacadefegdehijhklij"
+Output: [9,7,8]
+Explanation:
+The partition is "ababcbaca", "defegde", "hijhklij".
+This is a partition so that each letter appears in at most one part.
+A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.
+```
+
+```java
+public List partitionLabels(String S) {
+ int[] lastIndexsOfChar = new int[26];
+ for (int i = 0; i < S.length(); i++) {
+ lastIndexsOfChar[char2Index(S.charAt(i))] = i;
+ }
+ List partitions = new ArrayList<>();
+ int firstIndex = 0;
+ while (firstIndex < S.length()) {
+ int lastIndex = firstIndex;
+ for (int i = firstIndex; i < S.length() && i <= lastIndex; i++) {
+ int index = lastIndexsOfChar[char2Index(S.charAt(i))];
+ if (index > lastIndex) {
+ lastIndex = index;
+ }
+ }
+ partitions.add(lastIndex - firstIndex + 1);
+ firstIndex = lastIndex + 1;
+ }
+ return partitions;
+}
+
+private int char2Index(char c) {
+ return c - 'a';
+}
+```
+
+
+**种植花朵**
+
+[605. Can Place Flowers (Easy)](https://leetcode.com/problems/can-place-flowers/description/)
+
+```html
+Input: flowerbed = [1,0,0,0,1], n = 1
+Output: True
+```
+
+题目描述:花朵之间至少需要一个单位的间隔,求解是否能种下 n 朵花。
+
+```java
+public boolean canPlaceFlowers(int[] flowerbed, int n) {
+ int len = flowerbed.length;
+ int cnt = 0;
+ for (int i = 0; i < len && cnt < n; i++) {
+ if (flowerbed[i] == 1) {
+ continue;
+ }
+ int pre = i == 0 ? 0 : flowerbed[i - 1];
+ int next = i == len - 1 ? 0 : flowerbed[i + 1];
+ if (pre == 0 && next == 0) {
+ cnt++;
+ flowerbed[i] = 1;
+ }
+ }
+ return cnt >= n;
+}
+```
+
+**判断是否为子序列**
+
+[392. Is Subsequence (Medium)](https://leetcode.com/problems/is-subsequence/description/)
+
+```html
+s = "abc", t = "ahbgdc"
+Return true.
+```
+
+```java
+public boolean isSubsequence(String s, String t) {
+ int index = -1;
+ for (char c : s.toCharArray()) {
+ index = t.indexOf(c, index + 1);
+ if (index == -1) {
+ return false;
+ }
+ }
+ return true;
+}
+```
+
+**修改一个数成为非递减数组**
+
+[665. Non-decreasing Array (Easy)](https://leetcode.com/problems/non-decreasing-array/description/)
+
+```html
+Input: [4,2,3]
+Output: True
+Explanation: You could modify the first 4 to 1 to get a non-decreasing array.
+```
+
+题目描述:判断一个数组能不能只修改一个数就成为非递减数组。
+
+在出现 nums[i] < nums[i - 1] 时,需要考虑的是应该修改数组的哪个数,使得本次修改能使 i 之前的数组成为非递减数组,并且 **不影响后续的操作** 。优先考虑令 nums[i - 1] = nums[i],因为如果修改 nums[i] = nums[i - 1] 的话,那么 nums[i] 这个数会变大,就有可能比 nums[i + 1] 大,从而影响了后续操作。还有一个比较特别的情况就是 nums[i] < nums[i - 2],只修改 nums[i - 1] = nums[i] 不能使数组成为非递减数组,只能修改 nums[i] = nums[i - 1]。
+
+```java
+public boolean checkPossibility(int[] nums) {
+ int cnt = 0;
+ for (int i = 1; i < nums.length && cnt < 2; i++) {
+ if (nums[i] >= nums[i - 1]) {
+ continue;
+ }
+ cnt++;
+ if (i - 2 >= 0 && nums[i - 2] > nums[i]) {
+ nums[i] = nums[i - 1];
+ } else {
+ nums[i - 1] = nums[i];
+ }
+ }
+ return cnt <= 1;
+}
+```
+
+**股票的最大收益**
+
+[122. Best Time to Buy and Sell Stock II (Easy)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/)
+
+题目描述:一次股票交易包含买入和卖出,多个交易之间不能交叉进行。
+
+对于 [a, b, c, d],如果有 a <= b <= c <= d ,那么最大收益为 d - a。而 d - a = (d - c) + (c - b) + (b - a) ,因此当访问到一个 prices[i] 且 prices[i] - prices[i-1] > 0,那么就把 prices[i] - prices[i-1] 添加到收益中,从而在局部最优的情况下也保证全局最优。
+
+```java
+public int maxProfit(int[] prices) {
+ int profit = 0;
+ for (int i = 1; i < prices.length; i++) {
+ if (prices[i] > prices[i - 1]) {
+ profit += (prices[i] - prices[i - 1]);
+ }
+ }
+ return profit;
+}
+```
+
+**子数组最大的和**
+
+[53. Maximum Subarray (Easy)](https://leetcode.com/problems/maximum-subarray/description/)
+
+```html
+For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
+the contiguous subarray [4,-1,2,1] has the largest sum = 6.
+```
+
+```java
+public int maxSubArray(int[] nums) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int preSum = nums[0];
+ int maxSum = preSum;
+ for (int i = 1; i < nums.length; i++) {
+ preSum = preSum > 0 ? preSum + nums[i] : nums[i];
+ maxSum = Math.max(maxSum, preSum);
+ }
+ return maxSum;
+}
+```
+
+**买入和售出股票最大的收益**
+
+[121. Best Time to Buy and Sell Stock (Easy)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/)
+
+题目描述:只进行一次交易。
+
+只要记录前面的最小价格,将这个最小价格作为买入价格,然后将当前的价格作为售出价格,查看当前收益是不是最大收益。
+
+```java
+public int maxProfit(int[] prices) {
+ int n = prices.length;
+ if (n == 0) return 0;
+ int soFarMin = prices[0];
+ int max = 0;
+ for (int i = 1; i < n; i++) {
+ if (soFarMin > prices[i]) soFarMin = prices[i];
+ else max = Math.max(max, prices[i] - soFarMin);
+ }
+ return max;
+}
+```
+
+## 二分查找
+
+**正常实现**
+
+```java
+public int binarySearch(int[] nums, int key) {
+ int l = 0, h = nums.length - 1;
+ while (l <= h) {
+ int m = l + (h - l) / 2;
+ if (nums[m] == key) {
+ return m;
+ } else if (nums[m] > key) {
+ h = m - 1;
+ } else {
+ l = m + 1;
+ }
+ }
+ return -1;
+}
+```
+
+**时间复杂度**
+
+二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)。
+
+**m 计算**
+
+有两种计算中值 m 的方式:
+
+- m = (l + h) / 2
+- m = l + (h - l) / 2
+
+l + h 可能出现加法溢出,最好使用第二种方式。
+
+**返回值**
+
+循环退出时如果仍然没有查找到 key,那么表示查找失败。可以有两种返回值:
+
+- -1:以一个错误码表示没有查找到 key
+- l:将 key 插入到 nums 中的正确位置
+
+**变种**
+
+二分查找可以有很多变种,变种实现要注意边界值的判断。例如在一个有重复元素的数组中查找 key 的最左位置的实现如下:
+
+```java
+public int binarySearch(int[] nums, int key) {
+ int l = 0, h = nums.length - 1;
+ while (l < h) {
+ int m = l + (h - l) / 2;
+ if (nums[m] >= key) {
+ h = m;
+ } else {
+ l = m + 1;
+ }
+ }
+ return l;
+}
+```
+
+该实现和正常实现有以下不同:
+
+- 循环条件为 l < h
+- h 的赋值表达式为 h = m
+- 最后返回 l 而不是 -1
+
+在 nums[m] >= key 的情况下,可以推导出最左 key 位于 [l, m] 区间中,这是一个闭区间。h 的赋值表达式为 h = m,因为 m 位置也可能是解。
+
+在 h 的赋值表达式为 h = mid 的情况下,如果循环条件为 l <= h,那么会出现循环无法退出的情况,因此循环条件只能是 l < h。以下演示了循环条件为 l <= h 时循环无法退出的情况:
+
+```text
+nums = {0, 1, 2}, key = 1
+l m h
+0 1 2 nums[m] >= key
+0 0 1 nums[m] < key
+1 1 1 nums[m] >= key
+1 1 1 nums[m] >= key
+...
+```
+
+当循环体退出时,不表示没有查找到 key,因此最后返回的结果不应该为 -1。为了验证有没有查找到,需要在调用端判断一下返回位置上的值和 key 是否相等。
+
+**求开方**
+
+[69. Sqrt(x) (Easy)](https://leetcode.com/problems/sqrtx/description/)
+
+```html
+Input: 4
+Output: 2
+
+Input: 8
+Output: 2
+Explanation: The square root of 8 is 2.82842..., and since we want to return an integer, the decimal part will be truncated.
+```
+
+一个数 x 的开方 sqrt 一定在 0 \~ x 之间,并且满足 sqrt == x / sqrt。可以利用二分查找在 0 \~ x 之间查找 sqrt。
+
+对于 x = 8,它的开方是 2.82842...,最后应该返回 2 而不是 3。在循环条件为 l <= h 并且循环退出时,h 总是比 l 小 1,也就是说 h = 2,l = 3,因此最后的返回值应该为 h 而不是 l。
+
+```java
+public int mySqrt(int x) {
+ if (x <= 1) {
+ return x;
+ }
+ int l = 1, h = x;
+ while (l <= h) {
+ int mid = l + (h - l) / 2;
+ int sqrt = x / mid;
+ if (sqrt == mid) {
+ return mid;
+ } else if (mid > sqrt) {
+ h = mid - 1;
+ } else {
+ l = mid + 1;
+ }
+ }
+ return h;
+}
+```
+
+**大于给定元素的最小元素**
+
+[744. Find Smallest Letter Greater Than Target (Easy)](https://leetcode.com/problems/find-smallest-letter-greater-than-target/description/)
+
+```html
+Input:
+letters = ["c", "f", "j"]
+target = "d"
+Output: "f"
+
+Input:
+letters = ["c", "f", "j"]
+target = "k"
+Output: "c"
+```
+
+题目描述:给定一个有序的字符数组 letters 和一个字符 target,要求找出 letters 中大于 target 的最小字符,如果找不到就返回第 1 个字符。
+
+```java
+public char nextGreatestLetter(char[] letters, char target) {
+ int n = letters.length;
+ int l = 0, h = n - 1;
+ while (l <= h) {
+ int m = l + (h - l) / 2;
+ if (letters[m] <= target) {
+ l = m + 1;
+ } else {
+ h = m - 1;
+ }
+ }
+ return l < n ? letters[l] : letters[0];
+}
+```
+
+**有序数组的 Single Element**
+
+[540. Single Element in a Sorted Array (Medium)](https://leetcode.com/problems/single-element-in-a-sorted-array/description/)
+
+```html
+Input: [1, 1, 2, 3, 3, 4, 4, 8, 8]
+Output: 2
+```
+
+题目描述:一个有序数组只有一个数不出现两次,找出这个数。要求以 O(logN) 时间复杂度进行求解。
+
+令 index 为 Single Element 在数组中的位置。如果 m 为偶数,并且 m + 1 < index,那么 nums[m] == nums[m + 1];m + 1 >= index,那么 nums[m] != nums[m + 1]。
+
+从上面的规律可以知道,如果 nums[m] == nums[m + 1],那么 index 所在的数组位置为 [m + 2, h],此时令 l = m + 2;如果 nums[m] != nums[m + 1],那么 index 所在的数组位置为 [l, m],此时令 h = m。
+
+因为 h 的赋值表达式为 h = m,那么循环条件也就只能使用 l < h 这种形式。
+
+```java
+public int singleNonDuplicate(int[] nums) {
+ int l = 0, h = nums.length - 1;
+ while (l < h) {
+ int m = l + (h - l) / 2;
+ if (m % 2 == 1) {
+ m--; // 保证 l/h/m 都在偶数位,使得查找区间大小一直都是奇数
+ }
+ if (nums[m] == nums[m + 1]) {
+ l = m + 2;
+ } else {
+ h = m;
+ }
+ }
+ return nums[l];
+}
+```
+
+**第一个错误的版本**
+
+[278. First Bad Version (Easy)](https://leetcode.com/problems/first-bad-version/description/)
+
+题目描述:给定一个元素 n 代表有 [1, 2, ..., n] 版本,可以调用 isBadVersion(int x) 知道某个版本是否错误,要求找到第一个错误的版本。
+
+如果第 m 个版本出错,则表示第一个错误的版本在 [l, m] 之间,令 h = m;否则第一个错误的版本在 [m + 1, h] 之间,令 l = m + 1。
+
+因为 h 的赋值表达式为 h = m,因此循环条件为 l < h。
+
+```java
+public int firstBadVersion(int n) {
+ int l = 1, h = n;
+ while (l < h) {
+ int mid = l + (h - l) / 2;
+ if (isBadVersion(mid)) {
+ h = mid;
+ } else {
+ l = mid + 1;
+ }
+ }
+ return l;
+}
+```
+
+**旋转数组的最小数字**
+
+[153. Find Minimum in Rotated Sorted Array (Medium)](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/)
+
+```html
+Input: [3,4,5,1,2],
+Output: 1
+```
+
+```java
+public int findMin(int[] nums) {
+ int l = 0, h = nums.length - 1;
+ while (l < h) {
+ int m = l + (h - l) / 2;
+ if (nums[m] <= nums[h]) {
+ h = m;
+ } else {
+ l = m + 1;
+ }
+ }
+ return nums[l];
+}
+```
+
+**查找区间**
+
+[34. Search for a Range (Medium)](https://leetcode.com/problems/search-for-a-range/description/)
+
+```html
+Input: nums = [5,7,7,8,8,10], target = 8
+Output: [3,4]
+
+Input: nums = [5,7,7,8,8,10], target = 6
+Output: [-1,-1]
+```
+
+```java
+public int[] searchRange(int[] nums, int target) {
+ int first = binarySearch(nums, target);
+ int last = binarySearch(nums, target + 1) - 1;
+ if (first == nums.length || nums[first] != target) {
+ return new int[]{-1, -1};
+ } else {
+ return new int[]{first, Math.max(first, last)};
+ }
+}
+
+private int binarySearch(int[] nums, int target) {
+ int l = 0, h = nums.length; // 注意 h 的初始值
+ while (l < h) {
+ int m = l + (h - l) / 2;
+ if (nums[m] >= target) {
+ h = m;
+ } else {
+ l = m + 1;
+ }
+ }
+ return l;
+}
+```
+
+## 分治
+
+**给表达式加括号**
+
+[241. Different Ways to Add Parentheses (Medium)](https://leetcode.com/problems/different-ways-to-add-parentheses/description/)
+
+```html
+Input: "2-1-1".
+
+((2-1)-1) = 0
+(2-(1-1)) = 2
+
+Output : [0, 2]
+```
+
+```java
+public List diffWaysToCompute(String input) {
+ List ways = new ArrayList<>();
+ for (int i = 0; i < input.length(); i++) {
+ char c = input.charAt(i);
+ if (c == '+' || c == '-' || c == '*') {
+ List left = diffWaysToCompute(input.substring(0, i));
+ List right = diffWaysToCompute(input.substring(i + 1));
+ for (int l : left) {
+ for (int r : right) {
+ switch (c) {
+ case '+':
+ ways.add(l + r);
+ break;
+ case '-':
+ ways.add(l - r);
+ break;
+ case '*':
+ ways.add(l * r);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (ways.size() == 0) {
+ ways.add(Integer.valueOf(input));
+ }
+ return ways;
+}
+```
+
+## 搜索
+
+深度优先搜索和广度优先搜索广泛运用于树和图中,但是它们的应用远远不止如此。
+
+### BFS
+
+
+
+广度优先搜索一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。
+
+第一层:
+
+- 0 -> {6,2,1,5}
+
+第二层:
+
+- 6 -> {4}
+- 2 -> {}
+- 1 -> {}
+- 5 -> {3}
+
+第三层:
+
+- 4 -> {}
+- 3 -> {}
+
+每一层遍历的节点都与根节点距离相同。设 di 表示第 i 个节点与根节点的距离,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di <= dj 。利用这个结论,可以求解最短路径等 **最优解** 问题:第一次遍历到目的节点,其所经过的路径为最短路径。应该注意的是,使用 BFS 只能求解无权图的最短路径。
+
+在程序实现 BFS 时需要考虑以下问题:
+
+- 队列:用来存储每一轮遍历得到的节点;
+- 标记:对于遍历过的节点,应该将它标记,防止重复遍历。
+
+**计算在网格中从原点到特定点的最短路径长度**
+
+```html
+[[1,1,0,1],
+ [1,0,1,0],
+ [1,1,1,1],
+ [1,0,1,1]]
+```
+
+1 表示可以经过某个位置,求解从 (0, 0) 位置到 (tr, tc) 位置的最短路径长度。
+
+```java
+public int minPathLength(int[][] grids, int tr, int tc) {
+ final int[][] direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
+ final int m = grids.length, n = grids[0].length;
+ Queue> queue = new LinkedList<>();
+ queue.add(new Pair<>(0, 0));
+ int pathLength = 0;
+ while (!queue.isEmpty()) {
+ int size = queue.size();
+ pathLength++;
+ while (size-- > 0) {
+ Pair cur = queue.poll();
+ int cr = cur.getKey(), cc = cur.getValue();
+ grids[cr][cc] = 0; // 标记
+ for (int[] d : direction) {
+ int nr = cr + d[0], nc = cc + d[1];
+ if (nr < 0 || nr >= m || nc < 0 || nc >= n || grids[nr][nc] == 0) {
+ continue;
+ }
+ if (nr == tr && nc == tc) {
+ return pathLength;
+ }
+ queue.add(new Pair<>(nr, nc));
+ }
+ }
+ }
+ return -1;
+}
+```
+
+**组成整数的最小平方数数量**
+
+[279. Perfect Squares (Medium)](https://leetcode.com/problems/perfect-squares/description/)
+
+```html
+For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
+```
+
+可以将每个整数看成图中的一个节点,如果两个整数之差为一个平方数,那么这两个整数所在的节点就有一条边。
+
+要求解最小的平方数数量,就是求解从节点 n 到节点 0 的最短路径。
+
+本题也可以用动态规划求解,在之后动态规划部分中会再次出现。
+
+```java
+public int numSquares(int n) {
+ List squares = generateSquares(n);
+ Queue queue = new LinkedList<>();
+ boolean[] marked = new boolean[n + 1];
+ queue.add(n);
+ marked[n] = true;
+ int level = 0;
+ while (!queue.isEmpty()) {
+ int size = queue.size();
+ level++;
+ while (size-- > 0) {
+ int cur = queue.poll();
+ for (int s : squares) {
+ int next = cur - s;
+ if (next < 0) {
+ break;
+ }
+ if (next == 0) {
+ return level;
+ }
+ if (marked[next]) {
+ continue;
+ }
+ marked[next] = true;
+ queue.add(next);
+ }
+ }
+ }
+ return n;
+}
+
+/**
+ * 生成小于 n 的平方数序列
+ * @return 1,4,9,...
+ */
+private List generateSquares(int n) {
+ List squares = new ArrayList<>();
+ int square = 1;
+ int diff = 3;
+ while (square <= n) {
+ squares.add(square);
+ square += diff;
+ diff += 2;
+ }
+ return squares;
+}
+```
+
+**最短单词路径**
+
+[127. Word Ladder (Medium)](https://leetcode.com/problems/word-ladder/description/)
+
+```html
+Input:
+beginWord = "hit",
+endWord = "cog",
+wordList = ["hot","dot","dog","lot","log","cog"]
+
+Output: 5
+
+Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
+return its length 5.
+```
+
+```html
+Input:
+beginWord = "hit"
+endWord = "cog"
+wordList = ["hot","dot","dog","lot","log"]
+
+Output: 0
+
+Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
+```
+
+题目描述:找出一条从 beginWord 到 endWord 的最短路径,每次移动规定为改变一个字符,并且改变之后的字符串必须在 wordList 中。
+
+```java
+public int ladderLength(String beginWord, String endWord, List wordList) {
+ wordList.add(beginWord);
+ int N = wordList.size();
+ int start = N - 1;
+ int end = 0;
+ while (end < N && !wordList.get(end).equals(endWord)) {
+ end++;
+ }
+ if (end == N) {
+ return 0;
+ }
+ List[] graphic = buildGraphic(wordList);
+ return getShortestPath(graphic, start, end);
+}
+
+private List[] buildGraphic(List wordList) {
+ int N = wordList.size();
+ List[] graphic = new List[N];
+ for (int i = 0; i < N; i++) {
+ graphic[i] = new ArrayList<>();
+ for (int j = 0; j < N; j++) {
+ if (isConnect(wordList.get(i), wordList.get(j))) {
+ graphic[i].add(j);
+ }
+ }
+ }
+ return graphic;
+}
+
+private boolean isConnect(String s1, String s2) {
+ int diffCnt = 0;
+ for (int i = 0; i < s1.length() && diffCnt <= 1; i++) {
+ if (s1.charAt(i) != s2.charAt(i)) {
+ diffCnt++;
+ }
+ }
+ return diffCnt == 1;
+}
+
+private int getShortestPath(List[] graphic, int start, int end) {
+ Queue queue = new LinkedList<>();
+ boolean[] marked = new boolean[graphic.length];
+ queue.add(start);
+ marked[start] = true;
+ int path = 1;
+ while (!queue.isEmpty()) {
+ int size = queue.size();
+ path++;
+ while (size-- > 0) {
+ int cur = queue.poll();
+ for (int next : graphic[cur]) {
+ if (next == end) {
+ return path;
+ }
+ if (marked[next]) {
+ continue;
+ }
+ marked[next] = true;
+ queue.add(next);
+ }
+ }
+ }
+ return 0;
+}
+```
+
+### DFS
+
+
+
+广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历。
+
+而深度优先搜索在得到一个新节点时立即对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4;如此反复以这种方式遍历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2,然后继续以上步骤。
+
+从一个节点出发,使用 DFS 对一个图进行遍历时,能够遍历到的节点都是从初始节点可达的,DFS 常用来求解这种 **可达性** 问题。
+
+在程序实现 DFS 时需要考虑以下问题:
+
+- 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。可以使用递归栈。
+- 标记:和 BFS 一样同样需要对已经遍历过的节点进行标记。
+
+**查找最大的连通面积**
+
+[695. Max Area of Island (Easy)](https://leetcode.com/problems/max-area-of-island/description/)
+
+```html
+[[0,0,1,0,0,0,0,1,0,0,0,0,0],
+ [0,0,0,0,0,0,0,1,1,1,0,0,0],
+ [0,1,1,0,1,0,0,0,0,0,0,0,0],
+ [0,1,0,0,1,1,0,0,1,0,1,0,0],
+ [0,1,0,0,1,1,0,0,1,1,1,0,0],
+ [0,0,0,0,0,0,0,0,0,0,1,0,0],
+ [0,0,0,0,0,0,0,1,1,1,0,0,0],
+ [0,0,0,0,0,0,0,1,1,0,0,0,0]]
+```
+
+```java
+private int m, n;
+private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+public int maxAreaOfIsland(int[][] grid) {
+ if (grid == null || grid.length == 0) {
+ return 0;
+ }
+ m = grid.length;
+ n = grid[0].length;
+ int maxArea = 0;
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < n; j++) {
+ maxArea = Math.max(maxArea, dfs(grid, i, j));
+ }
+ }
+ return maxArea;
+}
+
+private int dfs(int[][] grid, int r, int c) {
+ if (r < 0 || r >= m || c < 0 || c >= n || grid[r][c] == 0) {
+ return 0;
+ }
+ grid[r][c] = 0;
+ int area = 1;
+ for (int[] d : direction) {
+ area += dfs(grid, r + d[0], c + d[1]);
+ }
+ return area;
+}
+```
+
+**矩阵中的连通分量数目**
+
+[200. Number of Islands (Medium)](https://leetcode.com/problems/number-of-islands/description/)
+
+```html
+Input:
+11000
+11000
+00100
+00011
+
+Output: 3
+```
+
+可以将矩阵表示看成一张有向图。
+
+```java
+private int m, n;
+private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+public int numIslands(char[][] grid) {
+ if (grid == null || grid.length == 0) {
+ return 0;
+ }
+ m = grid.length;
+ n = grid[0].length;
+ int islandsNum = 0;
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < n; j++) {
+ if (grid[i][j] != '0') {
+ dfs(grid, i, j);
+ islandsNum++;
+ }
+ }
+ }
+ return islandsNum;
+}
+
+private void dfs(char[][] grid, int i, int j) {
+ if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == '0') {
+ return;
+ }
+ grid[i][j] = '0';
+ for (int[] d : direction) {
+ dfs(grid, i + d[0], j + d[1]);
+ }
+}
+```
+
+**好友关系的连通分量数目**
+
+[547. Friend Circles (Medium)](https://leetcode.com/problems/friend-circles/description/)
+
+```html
+Input:
+[[1,1,0],
+ [1,1,0],
+ [0,0,1]]
+
+Output: 2
+
+Explanation:The 0th and 1st students are direct friends, so they are in a friend circle.
+The 2nd student himself is in a friend circle. So return 2.
+```
+
+题目描述:好友关系可以看成是一个无向图,例如第 0 个人与第 1 个人是好友,那么 M[0][1] 和 M[1][0] 的值都为 1。
+
+```java
+private int n;
+
+public int findCircleNum(int[][] M) {
+ n = M.length;
+ int circleNum = 0;
+ boolean[] hasVisited = new boolean[n];
+ for (int i = 0; i < n; i++) {
+ if (!hasVisited[i]) {
+ dfs(M, i, hasVisited);
+ circleNum++;
+ }
+ }
+ return circleNum;
+}
+
+private void dfs(int[][] M, int i, boolean[] hasVisited) {
+ hasVisited[i] = true;
+ for (int k = 0; k < n; k++) {
+ if (M[i][k] == 1 && !hasVisited[k]) {
+ dfs(M, k, hasVisited);
+ }
+ }
+}
+```
+
+**填充封闭区域**
+
+[130. Surrounded Regions (Medium)](https://leetcode.com/problems/surrounded-regions/description/)
+
+```html
+For example,
+X X X X
+X O O X
+X X O X
+X O X X
+
+After running your function, the board should be:
+X X X X
+X X X X
+X X X X
+X O X X
+```
+
+题目描述:使被 'X' 包围的 'O' 转换为 'X'。
+
+先填充最外侧,剩下的就是里侧了。
+
+```java
+private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+private int m, n;
+
+public void solve(char[][] board) {
+ if (board == null || board.length == 0) {
+ return;
+ }
+
+ m = board.length;
+ n = board[0].length;
+
+ for (int i = 0; i < m; i++) {
+ dfs(board, i, 0);
+ dfs(board, i, n - 1);
+ }
+ for (int i = 0; i < n; i++) {
+ dfs(board, 0, i);
+ dfs(board, m - 1, i);
+ }
+
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < n; j++) {
+ if (board[i][j] == 'T') {
+ board[i][j] = 'O';
+ } else if (board[i][j] == 'O') {
+ board[i][j] = 'X';
+ }
+ }
+ }
+}
+
+private void dfs(char[][] board, int r, int c) {
+ if (r < 0 || r >= m || c < 0 || c >= n || board[r][c] != 'O') {
+ return;
+ }
+ board[r][c] = 'T';
+ for (int[] d : direction) {
+ dfs(board, r + d[0], c + d[1]);
+ }
+}
+```
+
+**能到达的太平洋和大西洋的区域**
+
+[417. Pacific Atlantic Water Flow (Medium)](https://leetcode.com/problems/pacific-atlantic-water-flow/description/)
+
+```html
+Given the following 5x5 matrix:
+
+ Pacific ~ ~ ~ ~ ~
+ ~ 1 2 2 3 (5) *
+ ~ 3 2 3 (4) (4) *
+ ~ 2 4 (5) 3 1 *
+ ~ (6) (7) 1 4 5 *
+ ~ (5) 1 1 2 4 *
+ * * * * * Atlantic
+
+Return:
+[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix).
+```
+
+左边和上边是太平洋,右边和下边是大西洋,内部的数字代表海拔,海拔高的地方的水能够流到低的地方,求解水能够流到太平洋和大西洋的所有位置。
+
+```java
+
+private int m, n;
+private int[][] matrix;
+private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
+
+public List pacificAtlantic(int[][] matrix) {
+ List ret = new ArrayList<>();
+ if (matrix == null || matrix.length == 0) {
+ return ret;
+ }
+
+ m = matrix.length;
+ n = matrix[0].length;
+ this.matrix = matrix;
+ boolean[][] canReachP = new boolean[m][n];
+ boolean[][] canReachA = new boolean[m][n];
+
+ for (int i = 0; i < m; i++) {
+ dfs(i, 0, canReachP);
+ dfs(i, n - 1, canReachA);
+ }
+ for (int i = 0; i < n; i++) {
+ dfs(0, i, canReachP);
+ dfs(m - 1, i, canReachA);
+ }
+
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < n; j++) {
+ if (canReachP[i][j] && canReachA[i][j]) {
+ ret.add(new int[]{i, j});
+ }
+ }
+ }
+
+ return ret;
+}
+
+private void dfs(int r, int c, boolean[][] canReach) {
+ if (canReach[r][c]) {
+ return;
+ }
+ canReach[r][c] = true;
+ for (int[] d : direction) {
+ int nextR = d[0] + r;
+ int nextC = d[1] + c;
+ if (nextR < 0 || nextR >= m || nextC < 0 || nextC >= n
+ || matrix[r][c] > matrix[nextR][nextC]) {
+
+ continue;
+ }
+ dfs(nextR, nextC, canReach);
+ }
+}
+```
+
+### Backtracking
+
+Backtracking(回溯)属于 DFS。
+
+- 普通 DFS 主要用在 **可达性问题** ,这种问题只需要执行到特点的位置然后返回即可。
+- 而 Backtracking 主要用于求解 **排列组合** 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串,这种问题在执行到特定的位置返回之后还会继续执行求解过程。
+
+因为 Backtracking 不是立即就返回,而要继续求解,因此在程序实现时,需要注意对元素的标记问题:
+
+- 在访问一个新元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;
+- 但是在递归返回时,需要将元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。
+
+**数字键盘组合**
+
+[17. Letter Combinations of a Phone Number (Medium)](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/)
+
+
+
+```html
+Input:Digit string "23"
+Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
+```
+
+```java
+private static final String[] KEYS = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
+
+public List letterCombinations(String digits) {
+ List combinations = new ArrayList<>();
+ if (digits == null || digits.length() == 0) {
+ return combinations;
+ }
+ doCombination(new StringBuilder(), combinations, digits);
+ return combinations;
+}
+
+private void doCombination(StringBuilder prefix, List combinations, final String digits) {
+ if (prefix.length() == digits.length()) {
+ combinations.add(prefix.toString());
+ return;
+ }
+ int curDigits = digits.charAt(prefix.length()) - '0';
+ String letters = KEYS[curDigits];
+ for (char c : letters.toCharArray()) {
+ prefix.append(c); // 添加
+ doCombination(prefix, combinations, digits);
+ prefix.deleteCharAt(prefix.length() - 1); // 删除
+ }
+}
+```
+
+**IP 地址划分**
+
+[93. Restore IP Addresses(Medium)](https://leetcode.com/problems/restore-ip-addresses/description/)
+
+```html
+Given "25525511135",
+return ["255.255.11.135", "255.255.111.35"].
+```
+
+```java
+public List restoreIpAddresses(String s) {
+ List addresses = new ArrayList<>();
+ StringBuilder tempAddress = new StringBuilder();
+ doRestore(0, tempAddress, addresses, s);
+ return addresses;
+}
+
+private void doRestore(int k, StringBuilder tempAddress, List addresses, String s) {
+ if (k == 4 || s.length() == 0) {
+ if (k == 4 && s.length() == 0) {
+ addresses.add(tempAddress.toString());
+ }
+ return;
+ }
+ for (int i = 0; i < s.length() && i <= 2; i++) {
+ if (i != 0 && s.charAt(0) == '0') {
+ break;
+ }
+ String part = s.substring(0, i + 1);
+ if (Integer.valueOf(part) <= 255) {
+ if (tempAddress.length() != 0) {
+ part = "." + part;
+ }
+ tempAddress.append(part);
+ doRestore(k + 1, tempAddress, addresses, s.substring(i + 1));
+ tempAddress.delete(tempAddress.length() - part.length(), tempAddress.length());
+ }
+ }
+}
+```
+
+**在矩阵中寻找字符串**
+
+[79. Word Search (Medium)](https://leetcode.com/problems/word-search/description/)
+
+```html
+For example,
+Given board =
+[
+ ['A','B','C','E'],
+ ['S','F','C','S'],
+ ['A','D','E','E']
+]
+word = "ABCCED", -> returns true,
+word = "SEE", -> returns true,
+word = "ABCB", -> returns false.
+```
+
+```java
+private final static int[][] direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
+private int m;
+private int n;
+
+public boolean exist(char[][] board, String word) {
+ if (word == null || word.length() == 0) {
+ return true;
+ }
+ if (board == null || board.length == 0 || board[0].length == 0) {
+ return false;
+ }
+
+ m = board.length;
+ n = board[0].length;
+ boolean[][] hasVisited = new boolean[m][n];
+
+ for (int r = 0; r < m; r++) {
+ for (int c = 0; c < n; c++) {
+ if (backtracking(0, r, c, hasVisited, board, word)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+private boolean backtracking(int curLen, int r, int c, boolean[][] visited, final char[][] board, final String word) {
+ if (curLen == word.length()) {
+ return true;
+ }
+ if (r < 0 || r >= m || c < 0 || c >= n
+ || board[r][c] != word.charAt(curLen) || visited[r][c]) {
+
+ return false;
+ }
+
+ visited[r][c] = true;
+
+ for (int[] d : direction) {
+ if (backtracking(curLen + 1, r + d[0], c + d[1], visited, board, word)) {
+ return true;
+ }
+ }
+
+ visited[r][c] = false;
+
+ return false;
+}
+```
+
+**输出二叉树中所有从根到叶子的路径**
+
+[257. Binary Tree Paths (Easy)](https://leetcode.com/problems/binary-tree-paths/description/)
+
+```html
+ 1
+ / \
+2 3
+ \
+ 5
+```
+
+```html
+["1->2->5", "1->3"]
+```
+
+```java
+
+public List binaryTreePaths(TreeNode root) {
+ List paths = new ArrayList<>();
+ if (root == null) {
+ return paths;
+ }
+ List values = new ArrayList<>();
+ backtracking(root, values, paths);
+ return paths;
+}
+
+private void backtracking(TreeNode node, List values, List paths) {
+ if (node == null) {
+ return;
+ }
+ values.add(node.val);
+ if (isLeaf(node)) {
+ paths.add(buildPath(values));
+ } else {
+ backtracking(node.left, values, paths);
+ backtracking(node.right, values, paths);
+ }
+ values.remove(values.size() - 1);
+}
+
+private boolean isLeaf(TreeNode node) {
+ return node.left == null && node.right == null;
+}
+
+private String buildPath(List values) {
+ StringBuilder str = new StringBuilder();
+ for (int i = 0; i < values.size(); i++) {
+ str.append(values.get(i));
+ if (i != values.size() - 1) {
+ str.append("->");
+ }
+ }
+ return str.toString();
+}
+```
+
+**排列**
+
+[46. Permutations (Medium)](https://leetcode.com/problems/permutations/description/)
+
+```html
+[1,2,3] have the following permutations:
+[
+ [1,2,3],
+ [1,3,2],
+ [2,1,3],
+ [2,3,1],
+ [3,1,2],
+ [3,2,1]
+]
+```
+
+```java
+public List> permute(int[] nums) {
+ List> permutes = new ArrayList<>();
+ List permuteList = new ArrayList<>();
+ boolean[] hasVisited = new boolean[nums.length];
+ backtracking(permuteList, permutes, hasVisited, nums);
+ return permutes;
+}
+
+private void backtracking(List permuteList, List> permutes, boolean[] visited, final int[] nums) {
+ if (permuteList.size() == nums.length) {
+ permutes.add(new ArrayList<>(permuteList)); // 重新构造一个 List
+ return;
+ }
+ for (int i = 0; i < visited.length; i++) {
+ if (visited[i]) {
+ continue;
+ }
+ visited[i] = true;
+ permuteList.add(nums[i]);
+ backtracking(permuteList, permutes, visited, nums);
+ permuteList.remove(permuteList.size() - 1);
+ visited[i] = false;
+ }
+}
+```
+
+**含有相同元素求排列**
+
+[47. Permutations II (Medium)](https://leetcode.com/problems/permutations-ii/description/)
+
+```html
+[1,1,2] have the following unique permutations:
+[[1,1,2], [1,2,1], [2,1,1]]
+```
+
+数组元素可能含有相同的元素,进行排列时就有可能出现重复的排列,要求重复的排列只返回一个。
+
+在实现上,和 Permutations 不同的是要先排序,然后在添加一个元素时,判断这个元素是否等于前一个元素,如果等于,并且前一个元素还未访问,那么就跳过这个元素。
+
+```java
+public List> permuteUnique(int[] nums) {
+ List> permutes = new ArrayList<>();
+ List permuteList = new ArrayList<>();
+ Arrays.sort(nums); // 排序
+ boolean[] hasVisited = new boolean[nums.length];
+ backtracking(permuteList, permutes, hasVisited, nums);
+ return permutes;
+}
+
+private void backtracking(List permuteList, List> permutes, boolean[] visited, final int[] nums) {
+ if (permuteList.size() == nums.length) {
+ permutes.add(new ArrayList<>(permuteList));
+ return;
+ }
+
+ for (int i = 0; i < visited.length; i++) {
+ if (i != 0 && nums[i] == nums[i - 1] && !visited[i - 1]) {
+ continue; // 防止重复
+ }
+ if (visited[i]){
+ continue;
+ }
+ visited[i] = true;
+ permuteList.add(nums[i]);
+ backtracking(permuteList, permutes, visited, nums);
+ permuteList.remove(permuteList.size() - 1);
+ visited[i] = false;
+ }
+}
+```
+
+**组合**
+
+[77. Combinations (Medium)](https://leetcode.com/problems/combinations/description/)
+
+```html
+If n = 4 and k = 2, a solution is:
+[
+ [2,4],
+ [3,4],
+ [2,3],
+ [1,2],
+ [1,3],
+ [1,4],
+]
+```
+
+```java
+public List> combine(int n, int k) {
+ List> combinations = new ArrayList<>();
+ List combineList = new ArrayList<>();
+ backtracking(combineList, combinations, 1, k, n);
+ return combinations;
+}
+
+private void backtracking(List combineList, List> combinations, int start, int k, final int n) {
+ if (k == 0) {
+ combinations.add(new ArrayList<>(combineList));
+ return;
+ }
+ for (int i = start; i <= n - k + 1; i++) { // 剪枝
+ combineList.add(i);
+ backtracking(combineList, combinations, i + 1, k - 1, n);
+ combineList.remove(combineList.size() - 1);
+ }
+}
+```
+
+**组合求和**
+
+[39. Combination Sum (Medium)](https://leetcode.com/problems/combination-sum/description/)
+
+```html
+given candidate set [2, 3, 6, 7] and target 7,
+A solution set is:
+[[7],[2, 2, 3]]
+```
+
+```java
+public List> combinationSum(int[] candidates, int target) {
+ List> combinations = new ArrayList<>();
+ backtracking(new ArrayList<>(), combinations, 0, target, candidates);
+ return combinations;
+}
+
+private void backtracking(List tempCombination, List> combinations,
+ int start, int target, final int[] candidates) {
+
+ if (target == 0) {
+ combinations.add(new ArrayList<>(tempCombination));
+ return;
+ }
+ for (int i = start; i < candidates.length; i++) {
+ if (candidates[i] <= target) {
+ tempCombination.add(candidates[i]);
+ backtracking(tempCombination, combinations, i, target - candidates[i], candidates);
+ tempCombination.remove(tempCombination.size() - 1);
+ }
+ }
+}
+```
+
+**含有相同元素的求组合求和**
+
+[40. Combination Sum II (Medium)](https://leetcode.com/problems/combination-sum-ii/description/)
+
+```html
+For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8,
+A solution set is:
+[
+ [1, 7],
+ [1, 2, 5],
+ [2, 6],
+ [1, 1, 6]
+]
+```
+
+```java
+public List> combinationSum2(int[] candidates, int target) {
+ List> combinations = new ArrayList<>();
+ Arrays.sort(candidates);
+ backtracking(new ArrayList<>(), combinations, new boolean[candidates.length], 0, target, candidates);
+ return combinations;
+}
+
+private void backtracking(List tempCombination, List> combinations,
+ boolean[] hasVisited, int start, int target, final int[] candidates) {
+
+ if (target == 0) {
+ combinations.add(new ArrayList<>(tempCombination));
+ return;
+ }
+ for (int i = start; i < candidates.length; i++) {
+ if (i != 0 && candidates[i] == candidates[i - 1] && !hasVisited[i - 1]) {
+ continue;
+ }
+ if (candidates[i] <= target) {
+ tempCombination.add(candidates[i]);
+ hasVisited[i] = true;
+ backtracking(tempCombination, combinations, hasVisited, i + 1, target - candidates[i], candidates);
+ hasVisited[i] = false;
+ tempCombination.remove(tempCombination.size() - 1);
+ }
+ }
+}
+```
+
+**1-9 数字的组合求和**
+
+[216. Combination Sum III (Medium)](https://leetcode.com/problems/combination-sum-iii/description/)
+
+```html
+Input: k = 3, n = 9
+
+Output:
+
+[[1,2,6], [1,3,5], [2,3,4]]
+```
+
+从 1-9 数字中选出 k 个数不重复的数,使得它们的和为 n。
+
+```java
+public List> combinationSum3(int k, int n) {
+ List> combinations = new ArrayList<>();
+ List path = new ArrayList<>();
+ backtracking(k, n, 1, path, combinations);
+ return combinations;
+}
+
+private void backtracking(int k, int n, int start,
+ List tempCombination, List> combinations) {
+
+ if (k == 0 && n == 0) {
+ combinations.add(new ArrayList<>(tempCombination));
+ return;
+ }
+ if (k == 0 || n == 0) {
+ return;
+ }
+ for (int i = start; i <= 9; i++) {
+ tempCombination.add(i);
+ backtracking(k - 1, n - i, i + 1, tempCombination, combinations);
+ tempCombination.remove(tempCombination.size() - 1);
+ }
+}
+```
+
+**子集**
+
+[78. Subsets (Medium)](https://leetcode.com/problems/subsets/description/)
+
+找出集合的所有子集,子集不能重复,[1, 2] 和 [2, 1] 这种子集算重复
+
+```java
+public List> subsets(int[] nums) {
+ List> subsets = new ArrayList<>();
+ List tempSubset = new ArrayList<>();
+ for (int size = 0; size <= nums.length; size++) {
+ backtracking(0, tempSubset, subsets, size, nums); // 不同的子集大小
+ }
+ return subsets;
+}
+
+private void backtracking(int start, List tempSubset, List> subsets,
+ final int size, final int[] nums) {
+
+ if (tempSubset.size() == size) {
+ subsets.add(new ArrayList<>(tempSubset));
+ return;
+ }
+ for (int i = start; i < nums.length; i++) {
+ tempSubset.add(nums[i]);
+ backtracking(i + 1, tempSubset, subsets, size, nums);
+ tempSubset.remove(tempSubset.size() - 1);
+ }
+}
+```
+
+**含有相同元素求子集**
+
+[90. Subsets II (Medium)](https://leetcode.com/problems/subsets-ii/description/)
+
+```html
+For example,
+If nums = [1,2,2], a solution is:
+
+[
+ [2],
+ [1],
+ [1,2,2],
+ [2,2],
+ [1,2],
+ []
+]
+```
+
+```java
+public List> subsetsWithDup(int[] nums) {
+ Arrays.sort(nums);
+ List> subsets = new ArrayList<>();
+ List tempSubset = new ArrayList<>();
+ boolean[] hasVisited = new boolean[nums.length];
+ for (int size = 0; size <= nums.length; size++) {
+ backtracking(0, tempSubset, subsets, hasVisited, size, nums); // 不同的子集大小
+ }
+ return subsets;
+}
+
+private void backtracking(int start, List tempSubset, List> subsets, boolean[] hasVisited,
+ final int size, final int[] nums) {
+
+ if (tempSubset.size() == size) {
+ subsets.add(new ArrayList<>(tempSubset));
+ return;
+ }
+ for (int i = start; i < nums.length; i++) {
+ if (i != 0 && nums[i] == nums[i - 1] && !hasVisited[i - 1]) {
+ continue;
+ }
+ tempSubset.add(nums[i]);
+ hasVisited[i] = true;
+ backtracking(i + 1, tempSubset, subsets, hasVisited, size, nums);
+ hasVisited[i] = false;
+ tempSubset.remove(tempSubset.size() - 1);
+ }
+}
+```
+
+**分割字符串使得每个部分都是回文数**
+
+[131. Palindrome Partitioning (Medium)](https://leetcode.com/problems/palindrome-partitioning/description/)
+
+```html
+For example, given s = "aab",
+Return
+
+[
+ ["aa","b"],
+ ["a","a","b"]
+]
+```
+
+```java
+public List> partition(String s) {
+ List> partitions = new ArrayList<>();
+ List tempPartition = new ArrayList<>();
+ doPartition(s, partitions, tempPartition);
+ return partitions;
+}
+
+private void doPartition(String s, List> partitions, List tempPartition) {
+ if (s.length() == 0) {
+ partitions.add(new ArrayList<>(tempPartition));
+ return;
+ }
+ for (int i = 0; i < s.length(); i++) {
+ if (isPalindrome(s, 0, i)) {
+ tempPartition.add(s.substring(0, i + 1));
+ doPartition(s.substring(i + 1), partitions, tempPartition);
+ tempPartition.remove(tempPartition.size() - 1);
+ }
+ }
+}
+
+private boolean isPalindrome(String s, int begin, int end) {
+ while (begin < end) {
+ if (s.charAt(begin++) != s.charAt(end--)) {
+ return false;
+ }
+ }
+ return true;
+}
+```
+
+**数独**
+
+[37. Sudoku Solver (Hard)](https://leetcode.com/problems/sudoku-solver/description/)
+
+
+
+```java
+private boolean[][] rowsUsed = new boolean[9][10];
+private boolean[][] colsUsed = new boolean[9][10];
+private boolean[][] cubesUsed = new boolean[9][10];
+private char[][] board;
+
+public void solveSudoku(char[][] board) {
+ this.board = board;
+ for (int i = 0; i < 9; i++)
+ for (int j = 0; j < 9; j++) {
+ if (board[i][j] == '.') {
+ continue;
+ }
+ int num = board[i][j] - '0';
+ rowsUsed[i][num] = true;
+ colsUsed[j][num] = true;
+ cubesUsed[cubeNum(i, j)][num] = true;
+ }
+
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ backtracking(i, j);
+ }
+ }
+}
+
+private boolean backtracking(int row, int col) {
+ while (row < 9 && board[row][col] != '.') {
+ row = col == 8 ? row + 1 : row;
+ col = col == 8 ? 0 : col + 1;
+ }
+ if (row == 9) {
+ return true;
+ }
+ for (int num = 1; num <= 9; num++) {
+ if (rowsUsed[row][num] || colsUsed[col][num] || cubesUsed[cubeNum(row, col)][num]) {
+ continue;
+ }
+ rowsUsed[row][num] = colsUsed[col][num] = cubesUsed[cubeNum(row, col)][num] = true;
+ board[row][col] = (char) (num + '0');
+ if (backtracking(row, col)) {
+ return true;
+ }
+ board[row][col] = '.';
+ rowsUsed[row][num] = colsUsed[col][num] = cubesUsed[cubeNum(row, col)][num] = false;
+ }
+ return false;
+}
+
+private int cubeNum(int i, int j) {
+ int r = i / 3;
+ int c = j / 3;
+ return r * 3 + c;
+}
+```
+
+**N 皇后**
+
+[51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/)
+
+
+
+在 n\*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,求所有的 n 皇后的解。
+
+一行一行地摆放,在确定一行中的那个皇后应该摆在哪一列时,需要用三个标记数组来确定某一列是否合法,这三个标记数组分别为:列标记数组、45 度对角线标记数组和 135 度对角线标记数组。
+
+45 度对角线标记数组的长度为 2 \* n - 1,通过下图可以明确 (r, c) 的位置所在的数组下标为 r + c。
+
+
+
+135 度对角线标记数组的长度也是 2 \* n - 1,(r, c) 的位置所在的数组下标为 n - 1 - (r - c)。
+
+
+
+```java
+private List> solutions;
+private char[][] nQueens;
+private boolean[] colUsed;
+private boolean[] diagonals45Used;
+private boolean[] diagonals135Used;
+private int n;
+
+public List> solveNQueens(int n) {
+ solutions = new ArrayList<>();
+ nQueens = new char[n][n];
+ for (int i = 0; i < n; i++) {
+ Arrays.fill(nQueens[i], '.');
+ }
+ colUsed = new boolean[n];
+ diagonals45Used = new boolean[2 * n - 1];
+ diagonals135Used = new boolean[2 * n - 1];
+ this.n = n;
+ backtracking(0);
+ return solutions;
+}
+
+private void backtracking(int row) {
+ if (row == n) {
+ List list = new ArrayList<>();
+ for (char[] chars : nQueens) {
+ list.add(new String(chars));
+ }
+ solutions.add(list);
+ return;
+ }
+
+ for (int col = 0; col < n; col++) {
+ int diagonals45Idx = row + col;
+ int diagonals135Idx = n - 1 - (row - col);
+ if (colUsed[col] || diagonals45Used[diagonals45Idx] || diagonals135Used[diagonals135Idx]) {
+ continue;
+ }
+ nQueens[row][col] = 'Q';
+ colUsed[col] = diagonals45Used[diagonals45Idx] = diagonals135Used[diagonals135Idx] = true;
+ backtracking(row + 1);
+ colUsed[col] = diagonals45Used[diagonals45Idx] = diagonals135Used[diagonals135Idx] = false;
+ nQueens[row][col] = '.';
+ }
+}
+```
+
+## 动态规划
+
+递归和动态规划都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划保存了子问题的解,避免重复计算。
+
+### 斐波那契数列
+
+**爬楼梯**
+
+[70. Climbing Stairs (Easy)](https://leetcode.com/problems/climbing-stairs/description/)
+
+题目描述:有 N 阶楼梯,每次可以上一阶或者两阶,求有多少种上楼梯的方法。
+
+定义一个数组 dp 存储上楼梯的方法数(为了方便讨论,数组下标从 1 开始),dp[i] 表示走到第 i 个楼梯的方法数目。
+
+第 i 个楼梯可以从第 i-1 和 i-2 个楼梯再走一步到达,走到第 i 个楼梯的方法数为走到第 i-1 和第 i-2 个楼梯的方法数之和。
+
+
+
+考虑到 dp[i] 只与 dp[i - 1] 和 dp[i - 2] 有关,因此可以只用两个变量来存储 dp[i - 1] 和 dp[i - 2],使得原来的 O(N) 空间复杂度优化为 O(1) 复杂度。
+
+```java
+public int climbStairs(int n) {
+ if (n <= 2) {
+ return n;
+ }
+ int pre2 = 1, pre1 = 2;
+ for (int i = 2; i < n; i++) {
+ int cur = pre1 + pre2;
+ pre2 = pre1;
+ pre1 = cur;
+ }
+ return pre1;
+}
+```
+
+**强盗抢劫**
+
+[198. House Robber (Easy)](https://leetcode.com/problems/house-robber/description/)
+
+题目描述:抢劫一排住户,但是不能抢邻近的住户,求最大抢劫量。
+
+定义 dp 数组用来存储最大的抢劫量,其中 dp[i] 表示抢到第 i 个住户时的最大抢劫量。
+
+由于不能抢劫邻近住户,如果抢劫了第 i -1 个住户,那么就不能再抢劫第 i 个住户,所以
+
+
+
+```java
+public int rob(int[] nums) {
+ int pre2 = 0, pre1 = 0;
+ for (int i = 0; i < nums.length; i++) {
+ int cur = Math.max(pre2 + nums[i], pre1);
+ pre2 = pre1;
+ pre1 = cur;
+ }
+ return pre1;
+}
+```
+
+**强盗在环形街区抢劫**
+
+[213. House Robber II (Medium)](https://leetcode.com/problems/house-robber-ii/description/)
+
+```java
+public int rob(int[] nums) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int n = nums.length;
+ if (n == 1) {
+ return nums[0];
+ }
+ return Math.max(rob(nums, 0, n - 2), rob(nums, 1, n - 1));
+}
+
+private int rob(int[] nums, int first, int last) {
+ int pre2 = 0, pre1 = 0;
+ for (int i = first; i <= last; i++) {
+ int cur = Math.max(pre1, pre2 + nums[i]);
+ pre2 = pre1;
+ pre1 = cur;
+ }
+ return pre1;
+}
+```
+
+**信件错排**
+
+题目描述:有 N 个 信 和 信封,它们被打乱,求错误装信方式的数量。
+
+定义一个数组 dp 存储错误方式数量,dp[i] 表示前 i 个信和信封的错误方式数量。假设第 i 个信装到第 j 个信封里面,而第 j 个信装到第 k 个信封里面。根据 i 和 k 是否相等,有两种情况:
+
+- i==k,交换 i 和 k 的信后,它们的信和信封在正确的位置,但是其余 i-2 封信有 dp[i-2] 种错误装信的方式。由于 j 有 i-1 种取值,因此共有 (i-1)\*dp[i-2] 种错误装信方式。
+- i != k,交换 i 和 j 的信后,第 i 个信和信封在正确的位置,其余 i-1 封信有 dp[i-1] 种错误装信方式。由于 j 有 i-1 种取值,因此共有 (i-1)\*dp[i-1] 种错误装信方式。
+
+综上所述,错误装信数量方式数量为:
+
+
+
+**母牛生产**
+
+[程序员代码面试指南-P181](#)
+
+题目描述:假设农场中成熟的母牛每年都会生 1 头小母牛,并且永远不会死。第一年有 1 只小母牛,从第二年开始,母牛开始生小母牛。每只小母牛 3 年之后成熟又可以生小母牛。给定整数 N,求 N 年后牛的数量。
+
+第 i 年成熟的牛的数量为:
+
+
+
+### 矩阵路径
+
+**矩阵的最小路径和**
+
+[64. Minimum Path Sum (Medium)](https://leetcode.com/problems/minimum-path-sum/description/)
+
+```html
+[[1,3,1],
+ [1,5,1],
+ [4,2,1]]
+Given the above grid map, return 7. Because the path 1→3→1→1→1 minimizes the sum.
+```
+
+题目描述:求从矩阵的左上角到右下角的最小路径和,每次只能向右和向下移动。
+
+```java
+public int minPathSum(int[][] grid) {
+ if (grid.length == 0 || grid[0].length == 0) {
+ return 0;
+ }
+ int m = grid.length, n = grid[0].length;
+ int[] dp = new int[n];
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < n; j++) {
+ if (j == 0) {
+ dp[j] = dp[j]; // 只能从上侧走到该位置
+ } else if (i == 0) {
+ dp[j] = dp[j - 1]; // 只能从左侧走到该位置
+ } else {
+ dp[j] = Math.min(dp[j - 1], dp[j]);
+ }
+ dp[j] += grid[i][j];
+ }
+ }
+ return dp[n - 1];
+}
+```
+
+**矩阵的总路径数**
+
+[62. Unique Paths (Medium)](https://leetcode.com/problems/unique-paths/description/)
+
+题目描述:统计从矩阵左上角到右下角的路径总数,每次只能向右或者向下移动。
+
+
+
+```java
+public int uniquePaths(int m, int n) {
+ int[] dp = new int[n];
+ Arrays.fill(dp, 1);
+ for (int i = 1; i < m; i++) {
+ for (int j = 1; j < n; j++) {
+ dp[j] = dp[j] + dp[j - 1];
+ }
+ }
+ return dp[n - 1];
+}
+```
+
+也可以直接用数学公式求解,这是一个组合问题。机器人总共移动的次数 S=m+n-2,向下移动的次数 D=m-1,那么问题可以看成从 S 中取出 D 个位置的组合数量,这个问题的解为 C(S, D)。
+
+```java
+public int uniquePaths(int m, int n) {
+ int S = m + n - 2; // 总共的移动次数
+ int D = m - 1; // 向下的移动次数
+ long ret = 1;
+ for (int i = 1; i <= D; i++) {
+ ret = ret * (S - D + i) / i;
+ }
+ return (int) ret;
+}
+```
+
+### 数组区间
+
+**数组区间和**
+
+[303. Range Sum Query - Immutable (Easy)](https://leetcode.com/problems/range-sum-query-immutable/description/)
+
+```html
+Given nums = [-2, 0, 3, -5, 2, -1]
+
+sumRange(0, 2) -> 1
+sumRange(2, 5) -> -1
+sumRange(0, 5) -> -3
+```
+
+求区间 i \~ j 的和,可以转换为 sum[j + 1] - sum[i],其中 sum[i] 为 0 \~ i - 1 的和。
+
+```java
+class NumArray {
+
+ private int[] sums;
+
+ public NumArray(int[] nums) {
+ sums = new int[nums.length + 1];
+ for (int i = 1; i <= nums.length; i++) {
+ sums[i] = sums[i - 1] + nums[i - 1];
+ }
+ }
+
+ public int sumRange(int i, int j) {
+ return sums[j + 1] - sums[i];
+ }
+}
+```
+
+**数组中等差递增子区间的个数**
+
+[413. Arithmetic Slices (Medium)](https://leetcode.com/problems/arithmetic-slices/description/)
+
+```html
+A = [1, 2, 3, 4]
+return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself.
+```
+
+dp[i] 表示以 A[i] 为结尾的等差递增子区间的个数。
+
+在 A[i] - A[i - 1] == A[i - 1] - A[i - 2] 的条件下,{A[i - 2], A[i - 1], A[i]} 是一个等差递增子区间。如果 {A[i - 3], A[i - 2], A[i - 1]} 是一个等差递增子区间,那么 {A[i - 3], A[i - 2], A[i - 1], A[i]} 也是等差递增子区间,dp[i] = dp[i-1] + 1。
+
+```java
+public int numberOfArithmeticSlices(int[] A) {
+ if (A == null || A.length == 0) {
+ return 0;
+ }
+ int n = A.length;
+ int[] dp = new int[n];
+ for (int i = 2; i < n; i++) {
+ if (A[i] - A[i - 1] == A[i - 1] - A[i - 2]) {
+ dp[i] = dp[i - 1] + 1;
+ }
+ }
+ int total = 0;
+ for (int cnt : dp) {
+ total += cnt;
+ }
+ return total;
+}
+```
+
+### 分割整数
+
+**分割整数的最大乘积**
+
+[343. Integer Break (Medim)](https://leetcode.com/problems/integer-break/description/)
+
+题目描述:For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4).
+
+```java
+public int integerBreak(int n) {
+ int[] dp = new int[n + 1];
+ dp[1] = 1;
+ for (int i = 2; i <= n; i++) {
+ for (int j = 1; j <= i - 1; j++) {
+ dp[i] = Math.max(dp[i], Math.max(j * dp[i - j], j * (i - j)));
+ }
+ }
+ return dp[n];
+}
+```
+
+**按平方数来分割整数**
+
+[279. Perfect Squares(Medium)](https://leetcode.com/problems/perfect-squares/description/)
+
+题目描述:For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
+
+```java
+public int numSquares(int n) {
+ List squareList = generateSquareList(n);
+ int[] dp = new int[n + 1];
+ for (int i = 1; i <= n; i++) {
+ int min = Integer.MAX_VALUE;
+ for (int square : squareList) {
+ if (square > i) {
+ break;
+ }
+ min = Math.min(min, dp[i - square] + 1);
+ }
+ dp[i] = min;
+ }
+ return dp[n];
+}
+
+private List generateSquareList(int n) {
+ List squareList = new ArrayList<>();
+ int diff = 3;
+ int square = 1;
+ while (square <= n) {
+ squareList.add(square);
+ square += diff;
+ diff += 2;
+ }
+ return squareList;
+}
+```
+
+**分割整数构成字母字符串**
+
+[91. Decode Ways (Medium)](https://leetcode.com/problems/decode-ways/description/)
+
+题目描述:Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12).
+
+```java
+public int numDecodings(String s) {
+ if (s == null || s.length() == 0) {
+ return 0;
+ }
+ int n = s.length();
+ int[] dp = new int[n + 1];
+ dp[0] = 1;
+ dp[1] = s.charAt(0) == '0' ? 0 : 1;
+ for (int i = 2; i <= n; i++) {
+ int one = Integer.valueOf(s.substring(i - 1, i));
+ if (one != 0) {
+ dp[i] += dp[i - 1];
+ }
+ if (s.charAt(i - 2) == '0') {
+ continue;
+ }
+ int two = Integer.valueOf(s.substring(i - 2, i));
+ if (two <= 26) {
+ dp[i] += dp[i - 2];
+ }
+ }
+ return dp[n];
+}
+```
+
+### 最长递增子序列
+
+已知一个序列 {S1 , S2 ,...,Sn },取出若干数组成新的序列 {Si1 , Si2 ,..., Sim },其中 i1、i2 ... im 保持递增,即新序列中各个数仍然保持原数列中的先后顺序,称新序列为原序列的一个 **子序列** 。
+
+如果在子序列中,当下标 ix > iy 时,Six > Siy ,称子序列为原序列的一个 **递增子序列** 。
+
+定义一个数组 dp 存储最长递增子序列的长度,dp[n] 表示以 Sn 结尾的序列的最长递增子序列长度。对于一个递增子序列 {Si1 , Si2 ,...,Sim },如果 im < n 并且 Sim < Sn ,此时 {Si1 , Si2 ,..., Sim , Sn } 为一个递增子序列,递增子序列的长度增加 1。满足上述条件的递增子序列中,长度最长的那个递增子序列就是要找的,在长度最长的递增子序列上加上 Sn 就构成了以 Sn 为结尾的最长递增子序列。因此 dp[n] = max{ dp[i]+1 | Si < Sn && i < n} 。
+
+因为在求 dp[n] 时可能无法找到一个满足条件的递增子序列,此时 {Sn } 就构成了递增子序列,需要对前面的求解方程做修改,令 dp[n] 最小为 1,即:
+
+
+
+对于一个长度为 N 的序列,最长递增子序列并不一定会以 SN 为结尾,因此 dp[N] 不是序列的最长递增子序列的长度,需要遍历 dp 数组找出最大值才是所要的结果,max{ dp[i] | 1 <= i <= N} 即为所求。
+
+**最长递增子序列**
+
+[300. Longest Increasing Subsequence (Medium)](https://leetcode.com/problems/longest-increasing-subsequence/description/)
+
+```java
+public int lengthOfLIS(int[] nums) {
+ int n = nums.length;
+ int[] dp = new int[n];
+ for (int i = 0; i < n; i++) {
+ int max = 1;
+ for (int j = 0; j < i; j++) {
+ if (nums[i] > nums[j]) {
+ max = Math.max(max, dp[j] + 1);
+ }
+ }
+ dp[i] = max;
+ }
+ return Arrays.stream(dp).max().orElse(0);
+}
+```
+
+使用 Stream 求最大值会导致运行时间过长,可以改成以下形式:
+
+```java
+int ret = 0;
+for (int i = 0; i < n; i++) {
+ ret = Math.max(ret, dp[i]);
+}
+return ret;
+```
+
+以上解法的时间复杂度为 O(N2 ),可以使用二分查找将时间复杂度降低为 O(NlogN)。
+
+定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素。对于一个元素 x,
+
+- 如果它大于 tails 数组所有的值,那么把它添加到 tails 后面,表示最长递增子序列长度加 1;
+- 如果 tails[i-1] < x <= tails[i],那么更新 tails[i] = x。
+
+例如对于数组 [4,3,6,5],有:
+
+```html
+tails len num
+[] 0 4
+[4] 1 3
+[3] 1 6
+[3,6] 2 5
+[3,5] 2 null
+```
+
+可以看出 tails 数组保持有序,因此在查找 Si 位于 tails 数组的位置时就可以使用二分查找。
+
+```java
+public int lengthOfLIS(int[] nums) {
+ int n = nums.length;
+ int[] tails = new int[n];
+ int len = 0;
+ for (int num : nums) {
+ int index = binarySearch(tails, len, num);
+ tails[index] = num;
+ if (index == len) {
+ len++;
+ }
+ }
+ return len;
+}
+
+private int binarySearch(int[] tails, int len, int key) {
+ int l = 0, h = len;
+ while (l < h) {
+ int mid = l + (h - l) / 2;
+ if (tails[mid] == key) {
+ return mid;
+ } else if (tails[mid] > key) {
+ h = mid;
+ } else {
+ l = mid + 1;
+ }
+ }
+ return l;
+}
+```
+
+**一组整数对能够构成的最长链**
+
+[646. Maximum Length of Pair Chain (Medium)](https://leetcode.com/problems/maximum-length-of-pair-chain/description/)
+
+```html
+Input: [[1,2], [2,3], [3,4]]
+Output: 2
+Explanation: The longest chain is [1,2] -> [3,4]
+```
+
+题目描述:对于 (a, b) 和 (c, d) ,如果 b < c,则它们可以构成一条链。
+
+```java
+public int findLongestChain(int[][] pairs) {
+ if (pairs == null || pairs.length == 0) {
+ return 0;
+ }
+ Arrays.sort(pairs, (a, b) -> (a[0] - b[0]));
+ int n = pairs.length;
+ int[] dp = new int[n];
+ Arrays.fill(dp, 1);
+ for (int i = 1; i < n; i++) {
+ for (int j = 0; j < i; j++) {
+ if (pairs[j][1] < pairs[i][0]) {
+ dp[i] = Math.max(dp[i], dp[j] + 1);
+ }
+ }
+ }
+ return Arrays.stream(dp).max().orElse(0);
+}
+```
+
+**最长摆动子序列**
+
+[376. Wiggle Subsequence (Medium)](https://leetcode.com/problems/wiggle-subsequence/description/)
+
+```html
+Input: [1,7,4,9,2,5]
+Output: 6
+The entire sequence is a wiggle sequence.
+
+Input: [1,17,5,10,13,15,10,5,16,8]
+Output: 7
+There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8].
+
+Input: [1,2,3,4,5,6,7,8,9]
+Output: 2
+```
+
+要求:使用 O(N) 时间复杂度求解。
+
+```java
+public int wiggleMaxLength(int[] nums) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int up = 1, down = 1;
+ for (int i = 1; i < nums.length; i++) {
+ if (nums[i] > nums[i - 1]) {
+ up = down + 1;
+ } else if (nums[i] < nums[i - 1]) {
+ down = up + 1;
+ }
+ }
+ return Math.max(up, down);
+}
+```
+
+### 最长公共子序列
+
+对于两个子序列 S1 和 S2,找出它们最长的公共子序列。
+
+定义一个二维数组 dp 用来存储最长公共子序列的长度,其中 dp[i][j] 表示 S1 的前 i 个字符与 S2 的前 j 个字符最长公共子序列的长度。考虑 S1i 与 S2j 值是否相等,分为两种情况:
+
+- 当 S1i ==S2j 时,那么就能在 S1 的前 i-1 个字符与 S2 的前 j-1 个字符最长公共子序列的基础上再加上 S1i 这个值,最长公共子序列长度加 1,即 dp[i][j] = dp[i-1][j-1] + 1。
+- 当 S1i != S2j 时,此时最长公共子序列为 S1 的前 i-1 个字符和 S2 的前 j 个字符最长公共子序列,或者 S1 的前 i 个字符和 S2 的前 j-1 个字符最长公共子序列,取它们的最大者,即 dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }。
+
+综上,最长公共子序列的状态转移方程为:
+
+
+
+对于长度为 N 的序列 S1 和长度为 M 的序列 S2 ,dp[N][M] 就是序列 S1 和序列 S2 的最长公共子序列长度。
+
+与最长递增子序列相比,最长公共子序列有以下不同点:
+
+- 针对的是两个序列,求它们的最长公共子序列。
+- 在最长递增子序列中,dp[i] 表示以 Si 为结尾的最长递增子序列长度,子序列必须包含 Si ;在最长公共子序列中,dp[i][j] 表示 S1 中前 i 个字符与 S2 中前 j 个字符的最长公共子序列长度,不一定包含 S1i 和 S2j 。
+- 在求最终解时,最长公共子序列中 dp[N][M] 就是最终解,而最长递增子序列中 dp[N] 不是最终解,因为以 SN 为结尾的最长递增子序列不一定是整个序列最长递增子序列,需要遍历一遍 dp 数组找到最大者。
+
+```java
+public int lengthOfLCS(int[] nums1, int[] nums2) {
+ int n1 = nums1.length, n2 = nums2.length;
+ int[][] dp = new int[n1 + 1][n2 + 1];
+ for (int i = 1; i <= n1; i++) {
+ for (int j = 1; j <= n2; j++) {
+ if (nums1[i - 1] == nums2[j - 1]) {
+ dp[i][j] = dp[i - 1][j - 1] + 1;
+ } else {
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
+ }
+ }
+ }
+ return dp[n1][n2];
+}
+```
+
+### 0-1 背包
+
+有一个容量为 N 的背包,要用这个背包装下物品的价值最大,这些物品有两个属性:体积 w 和价值 v。
+
+定义一个二维数组 dp 存储最大价值,其中 dp[i][j] 表示前 i 件物品体积不超过 j 的情况下能达到的最大价值。设第 i 件物品体积为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论:
+
+- 第 i 件物品没添加到背包,总体积不超过 j 的前 i 件物品的最大价值就是总体积不超过 j 的前 i-1 件物品的最大价值,dp[i][j] = dp[i-1][j]。
+- 第 i 件物品添加到背包中,dp[i][j] = dp[i-1][j-w] + v。
+
+第 i 件物品可添加也可以不添加,取决于哪种情况下最大价值更大。因此,0-1 背包的状态转移方程为:
+
+
+
+```java
+public int knapsack(int W, int N, int[] weights, int[] values) {
+ int[][] dp = new int[N + 1][W + 1];
+ for (int i = 1; i <= N; i++) {
+ int w = weights[i - 1], v = values[i - 1];
+ for (int j = 1; j <= W; j++) {
+ if (j >= w) {
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - w] + v);
+ } else {
+ dp[i][j] = dp[i - 1][j];
+ }
+ }
+ }
+ return dp[N][W];
+}
+```
+
+**空间优化**
+
+在程序实现时可以对 0-1 背包做优化。观察状态转移方程可以知道,前 i 件物品的状态仅与前 i-1 件物品的状态有关,因此可以将 dp 定义为一维数组,其中 dp[j] 既可以表示 dp[i-1][j] 也可以表示 dp[i][j]。此时,
+
+
+
+因为 dp[j-w] 表示 dp[i-1][j-w],因此不能先求 dp[i][j-w],以防将 dp[i-1][j-w] 覆盖。也就是说要先计算 dp[i][j] 再计算 dp[i][j-w],在程序实现时需要按倒序来循环求解。
+
+```java
+public int knapsack(int W, int N, int[] weights, int[] values) {
+ int[] dp = new int[W + 1];
+ for (int i = 1; i <= N; i++) {
+ int w = weights[i - 1], v = values[i - 1];
+ for (int j = W; j >= 1; j--) {
+ if (j >= w) {
+ dp[j] = Math.max(dp[j], dp[j - w] + v);
+ }
+ }
+ }
+ return dp[W];
+}
+```
+
+**无法使用贪心算法的解释**
+
+0-1 背包问题无法使用贪心算法来求解,也就是说不能按照先添加性价比最高的物品来达到最优,这是因为这种方式可能造成背包空间的浪费,从而无法达到最优。考虑下面的物品和一个容量为 5 的背包,如果先添加物品 0 再添加物品 1,那么只能存放的价值为 16,浪费了大小为 2 的空间。最优的方式是存放物品 1 和物品 2,价值为 22.
+
+| id | w | v | v/w |
+| --- | --- | --- | --- |
+| 0 | 1 | 6 | 6 |
+| 1 | 2 | 10 | 5 |
+| 2 | 3 | 12 | 4 |
+
+**变种**
+
+- 完全背包:物品数量为无限个
+
+- 多重背包:物品数量有限制
+
+- 多维费用背包:物品不仅有重量,还有体积,同时考虑这两种限制
+
+- 其它:物品之间相互约束或者依赖
+
+**划分数组为和相等的两部分**
+
+[416. Partition Equal Subset Sum (Medium)](https://leetcode.com/problems/partition-equal-subset-sum/description/)
+
+```html
+Input: [1, 5, 11, 5]
+
+Output: true
+
+Explanation: The array can be partitioned as [1, 5, 5] and [11].
+```
+
+可以看成一个背包大小为 sum/2 的 0-1 背包问题。
+
+```java
+public boolean canPartition(int[] nums) {
+ int sum = computeArraySum(nums);
+ if (sum % 2 != 0) {
+ return false;
+ }
+ int W = sum / 2;
+ boolean[] dp = new boolean[W + 1];
+ dp[0] = true;
+ Arrays.sort(nums);
+ for (int num : nums) { // 0-1 背包一个物品只能用一次
+ for (int i = W; i >= num; i--) { // 从后往前,先计算 dp[i] 再计算 dp[i-num]
+ dp[i] = dp[i] || dp[i - num];
+ }
+ }
+ return dp[W];
+}
+
+private int computeArraySum(int[] nums) {
+ int sum = 0;
+ for (int num : nums) {
+ sum += num;
+ }
+ return sum;
+}
+```
+
+**改变一组数的正负号使得它们的和为一给定数**
+
+[494. Target Sum (Medium)](https://leetcode.com/problems/target-sum/description/)
+
+```html
+Input: nums is [1, 1, 1, 1, 1], S is 3.
+Output: 5
+Explanation:
+
+-1+1+1+1+1 = 3
++1-1+1+1+1 = 3
++1+1-1+1+1 = 3
++1+1+1-1+1 = 3
++1+1+1+1-1 = 3
+
+There are 5 ways to assign symbols to make the sum of nums be target 3.
+```
+
+该问题可以转换为 Subset Sum 问题,从而使用 0-1 背包的方法来求解。
+
+可以将这组数看成两部分,P 和 N,其中 P 使用正号,N 使用负号,有以下推导:
+
+```html
+ sum(P) - sum(N) = target
+sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
+ 2 * sum(P) = target + sum(nums)
+```
+
+因此只要找到一个子集,令它们都取正号,并且和等于 (target + sum(nums))/2,就证明存在解。
+
+```java
+public int findTargetSumWays(int[] nums, int S) {
+ int sum = computeArraySum(nums);
+ if (sum < S || (sum + S) % 2 == 1) {
+ return 0;
+ }
+ int W = (sum + S) / 2;
+ int[] dp = new int[W + 1];
+ dp[0] = 1;
+ for (int num : nums) {
+ for (int i = W; i >= num; i--) {
+ dp[i] = dp[i] + dp[i - num];
+ }
+ }
+ return dp[W];
+}
+
+private int computeArraySum(int[] nums) {
+ int sum = 0;
+ for (int num : nums) {
+ sum += num;
+ }
+ return sum;
+}
+```
+
+DFS 解法:
+
+```java
+public int findTargetSumWays(int[] nums, int S) {
+ return findTargetSumWays(nums, 0, S);
+}
+
+private int findTargetSumWays(int[] nums, int start, int S) {
+ if (start == nums.length) {
+ return S == 0 ? 1 : 0;
+ }
+ return findTargetSumWays(nums, start + 1, S + nums[start])
+ + findTargetSumWays(nums, start + 1, S - nums[start]);
+}
+```
+
+**字符串按单词列表分割**
+
+[139. Word Break (Medium)](https://leetcode.com/problems/word-break/description/)
+
+```html
+s = "leetcode",
+dict = ["leet", "code"].
+Return true because "leetcode" can be segmented as "leet code".
+```
+
+dict 中的单词没有使用次数的限制,因此这是一个完全背包问题。
+
+0-1 背包和完全背包在实现上的不同之处是,0-1 背包对物品的迭代是在最外层,而完全背包对物品的迭代是在最里层。
+
+```java
+public boolean wordBreak(String s, List wordDict) {
+ int n = s.length();
+ boolean[] dp = new boolean[n + 1];
+ dp[0] = true;
+ for (int i = 1; i <= n; i++) {
+ for (String word : wordDict) { // 完全一个物品可以使用多次
+ int len = word.length();
+ if (len <= i && word.equals(s.substring(i - len, i))) {
+ dp[i] = dp[i] || dp[i - len];
+ }
+ }
+ }
+ return dp[n];
+}
+```
+
+**01 字符构成最多的字符串**
+
+[474. Ones and Zeroes (Medium)](https://leetcode.com/problems/ones-and-zeroes/description/)
+
+```html
+Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3
+Output: 4
+
+Explanation: There are totally 4 strings can be formed by the using of 5 0s and 3 1s, which are "10","0001","1","0"
+```
+
+这是一个多维费用的 0-1 背包问题,有两个背包大小,0 的数量和 1 的数量。
+
+```java
+public int findMaxForm(String[] strs, int m, int n) {
+ if (strs == null || strs.length == 0) {
+ return 0;
+ }
+ int[][] dp = new int[m + 1][n + 1];
+ for (String s : strs) { // 每个字符串只能用一次
+ int ones = 0, zeros = 0;
+ for (char c : s.toCharArray()) {
+ if (c == '0') {
+ zeros++;
+ } else {
+ ones++;
+ }
+ }
+ for (int i = m; i >= zeros; i--) {
+ for (int j = n; j >= ones; j--) {
+ dp[i][j] = Math.max(dp[i][j], dp[i - zeros][j - ones] + 1);
+ }
+ }
+ }
+ return dp[m][n];
+}
+```
+
+**找零钱的最少硬币数**
+
+[322. Coin Change (Medium)](https://leetcode.com/problems/coin-change/description/)
+
+```html
+Example 1:
+coins = [1, 2, 5], amount = 11
+return 3 (11 = 5 + 5 + 1)
+
+Example 2:
+coins = [2], amount = 3
+return -1.
+```
+
+题目描述:给一些面额的硬币,要求用这些硬币来组成给定面额的钱数,并且使得硬币数量最少。硬币可以重复使用。
+
+- 物品:硬币
+- 物品大小:面额
+- 物品价值:数量
+
+因为硬币可以重复使用,因此这是一个完全背包问题。
+
+```java
+public int coinChange(int[] coins, int amount) {
+ if (coins == null || coins.length == 0) {
+ return 0;
+ }
+ int[] minimum = new int[amount + 1];
+ Arrays.fill(minimum, amount + 1);
+ minimum[0] = 0;
+ Arrays.sort(coins);
+ for (int i = 1; i <= amount; i++) {
+ for (int j = 0; j < coins.length && coins[j] <= i; j++) {
+ minimum[i] = Math.min(minimum[i], minimum[i - coins[j]] + 1);
+ }
+ }
+ return minimum[amount] > amount ? -1 : minimum[amount];
+}
+```
+
+**组合总和**
+
+[377. Combination Sum IV (Medium)](https://leetcode.com/problems/combination-sum-iv/description/)
+
+```html
+nums = [1, 2, 3]
+target = 4
+
+The possible combination ways are:
+(1, 1, 1, 1)
+(1, 1, 2)
+(1, 2, 1)
+(1, 3)
+(2, 1, 1)
+(2, 2)
+(3, 1)
+
+Note that different sequences are counted as different combinations.
+
+Therefore the output is 7.
+```
+
+完全背包。
+
+```java
+public int combinationSum4(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int[] maximum = new int[target + 1];
+ maximum[0] = 1;
+ Arrays.sort(nums);
+ for (int i = 1; i <= target; i++) {
+ for (int j = 0; j < nums.length && nums[j] <= i; j++) {
+ maximum[i] += maximum[i - nums[j]];
+ }
+ }
+ return maximum[target];
+}
+```
+
+### 股票交易
+
+**需要冷却期的股票交易**
+
+[309. Best Time to Buy and Sell Stock with Cooldown(Medium)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/)
+
+题目描述:交易之后需要有一天的冷却时间。
+
+
+
+```java
+public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int N = prices.length;
+ int[] buy = new int[N];
+ int[] s1 = new int[N];
+ int[] sell = new int[N];
+ int[] s2 = new int[N];
+ s1[0] = buy[0] = -prices[0];
+ sell[0] = s2[0] = 0;
+ for (int i = 1; i < N; i++) {
+ buy[i] = s2[i - 1] - prices[i];
+ s1[i] = Math.max(buy[i - 1], s1[i - 1]);
+ sell[i] = Math.max(buy[i - 1], s1[i - 1]) + prices[i];
+ s2[i] = Math.max(s2[i - 1], sell[i - 1]);
+ }
+ return Math.max(sell[N - 1], s2[N - 1]);
+}
+```
+
+**需要交易费用的股票交易**
+
+[714. Best Time to Buy and Sell Stock with Transaction Fee (Medium)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/description/)
+
+```html
+Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
+Output: 8
+Explanation: The maximum profit can be achieved by:
+Buying at prices[0] = 1
+Selling at prices[3] = 8
+Buying at prices[4] = 4
+Selling at prices[5] = 9
+The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
+```
+
+题目描述:每交易一次,都要支付一定的费用。
+
+
+
+```java
+public int maxProfit(int[] prices, int fee) {
+ int N = prices.length;
+ int[] buy = new int[N];
+ int[] s1 = new int[N];
+ int[] sell = new int[N];
+ int[] s2 = new int[N];
+ s1[0] = buy[0] = -prices[0];
+ sell[0] = s2[0] = 0;
+ for (int i = 1; i < N; i++) {
+ buy[i] = Math.max(sell[i - 1], s2[i - 1]) - prices[i];
+ s1[i] = Math.max(buy[i - 1], s1[i - 1]);
+ sell[i] = Math.max(buy[i - 1], s1[i - 1]) - fee + prices[i];
+ s2[i] = Math.max(s2[i - 1], sell[i - 1]);
+ }
+ return Math.max(sell[N - 1], s2[N - 1]);
+}
+```
+
+
+**只能进行两次的股票交易**
+
+[123. Best Time to Buy and Sell Stock III (Hard)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/description/)
+
+```java
+public int maxProfit(int[] prices) {
+ int firstBuy = Integer.MIN_VALUE, firstSell = 0;
+ int secondBuy = Integer.MIN_VALUE, secondSell = 0;
+ for (int curPrice : prices) {
+ if (firstBuy < -curPrice) {
+ firstBuy = -curPrice;
+ }
+ if (firstSell < firstBuy + curPrice) {
+ firstSell = firstBuy + curPrice;
+ }
+ if (secondBuy < firstSell - curPrice) {
+ secondBuy = firstSell - curPrice;
+ }
+ if (secondSell < secondBuy + curPrice) {
+ secondSell = secondBuy + curPrice;
+ }
+ }
+ return secondSell;
+}
+```
+
+**只能进行 k 次的股票交易**
+
+[188. Best Time to Buy and Sell Stock IV (Hard)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/description/)
+
+```java
+public int maxProfit(int k, int[] prices) {
+ int n = prices.length;
+ if (k >= n / 2) { // 这种情况下该问题退化为普通的股票交易问题
+ int maxProfit = 0;
+ for (int i = 1; i < n; i++) {
+ if (prices[i] > prices[i - 1]) {
+ maxProfit += prices[i] - prices[i - 1];
+ }
+ }
+ return maxProfit;
+ }
+ int[][] maxProfit = new int[k + 1][n];
+ for (int i = 1; i <= k; i++) {
+ int localMax = maxProfit[i - 1][0] - prices[0];
+ for (int j = 1; j < n; j++) {
+ maxProfit[i][j] = Math.max(maxProfit[i][j - 1], prices[j] + localMax);
+ localMax = Math.max(localMax, maxProfit[i - 1][j] - prices[j]);
+ }
+ }
+ return maxProfit[k][n - 1];
+}
+```
+
+### 字符串编辑
+
+**删除两个字符串的字符使它们相等**
+
+[583. Delete Operation for Two Strings (Medium)](https://leetcode.com/problems/delete-operation-for-two-strings/description/)
+
+```html
+Input: "sea", "eat"
+Output: 2
+Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea".
+```
+
+可以转换为求两个字符串的最长公共子序列问题。
+
+```java
+public int minDistance(String word1, String word2) {
+ int m = word1.length(), n = word2.length();
+ int[][] dp = new int[m + 1][n + 1];
+ for (int i = 1; i <= m; i++) {
+ for (int j = 1; j <= n; j++) {
+ if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
+ dp[i][j] = dp[i - 1][j - 1] + 1;
+ } else {
+ dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
+ }
+ }
+ }
+ return m + n - 2 * dp[m][n];
+}
+```
+
+**编辑距离**
+
+[72. Edit Distance (Hard)](https://leetcode.com/problems/edit-distance/description/)
+
+```html
+Example 1:
+
+Input: word1 = "horse", word2 = "ros"
+Output: 3
+Explanation:
+horse -> rorse (replace 'h' with 'r')
+rorse -> rose (remove 'r')
+rose -> ros (remove 'e')
+Example 2:
+
+Input: word1 = "intention", word2 = "execution"
+Output: 5
+Explanation:
+intention -> inention (remove 't')
+inention -> enention (replace 'i' with 'e')
+enention -> exention (replace 'n' with 'x')
+exention -> exection (replace 'n' with 'c')
+exection -> execution (insert 'u')
+```
+
+题目描述:修改一个字符串成为另一个字符串,使得修改次数最少。一次修改操作包括:插入一个字符、删除一个字符、替换一个字符。
+
+```java
+public int minDistance(String word1, String word2) {
+ if (word1 == null || word2 == null) {
+ return 0;
+ }
+ int m = word1.length(), n = word2.length();
+ int[][] dp = new int[m + 1][n + 1];
+ for (int i = 1; i <= m; i++) {
+ dp[i][0] = i;
+ }
+ for (int i = 1; i <= n; i++) {
+ dp[0][i] = i;
+ }
+ for (int i = 1; i <= m; i++) {
+ for (int j = 1; j <= n; j++) {
+ if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
+ dp[i][j] = dp[i - 1][j - 1];
+ } else {
+ dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1;
+ }
+ }
+ }
+ return dp[m][n];
+}
+```
+
+**复制粘贴字符**
+
+[650. 2 Keys Keyboard (Medium)](https://leetcode.com/problems/2-keys-keyboard/description/)
+
+题目描述:最开始只有一个字符 A,问需要多少次操作能够得到 n 个字符 A,每次操作可以复制当前所有的字符,或者粘贴。
+
+```
+Input: 3
+Output: 3
+Explanation:
+Intitally, we have one character 'A'.
+In step 1, we use Copy All operation.
+In step 2, we use Paste operation to get 'AA'.
+In step 3, we use Paste operation to get 'AAA'.
+```
+
+```java
+public int minSteps(int n) {
+ if (n == 1) return 0;
+ for (int i = 2; i <= Math.sqrt(n); i++) {
+ if (n % i == 0) return i + minSteps(n / i);
+ }
+ return n;
+}
+```
+
+```java
+public int minSteps(int n) {
+ int[] dp = new int[n + 1];
+ int h = (int) Math.sqrt(n);
+ for (int i = 2; i <= n; i++) {
+ dp[i] = i;
+ for (int j = 2; j <= h; j++) {
+ if (i % j == 0) {
+ dp[i] = dp[j] + dp[i / j];
+ break;
+ }
+ }
+ }
+ return dp[n];
+}
+```
+
+## 数学
+
+### 素数
+
+**素数分解**
+
+每一个数都可以分解成素数的乘积,例如 84 = 22 \* 31 \* 50 \* 71 \* 110 \* 130 \* 170 \* …
+
+**整除**
+
+令 x = 2m0 \* 3m1 \* 5m2 \* 7m3 \* 11m4 \* …
+
+令 y = 2n0 \* 3n1 \* 5n2 \* 7n3 \* 11n4 \* …
+
+如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。
+
+**最大公约数最小公倍数**
+
+x 和 y 的最大公约数为:gcd(x,y) = 2min(m0,n0) \* 3min(m1,n1) \* 5min(m2,n2) \* ...
+
+x 和 y 的最小公倍数为:lcm(x,y) = 2max(m0,n0) \* 3max(m1,n1) \* 5max(m2,n2) \* ...
+
+**生成素数序列**
+
+[204. Count Primes (Easy)](https://leetcode.com/problems/count-primes/description/)
+
+埃拉托斯特尼筛法在每次找到一个素数时,将能被素数整除的数排除掉。
+
+```java
+public int countPrimes(int n) {
+ boolean[] notPrimes = new boolean[n + 1];
+ int count = 0;
+ for (int i = 2; i < n; i++) {
+ if (notPrimes[i]) {
+ continue;
+ }
+ count++;
+ // 从 i * i 开始,因为如果 k < i,那么 k * i 在之前就已经被去除过了
+ for (long j = (long) (i) * i; j < n; j += i) {
+ notPrimes[(int) j] = true;
+ }
+ }
+ return count;
+}
+```
+
+### 最大公约数
+
+```java
+int gcd(int a, int b) {
+ return b == 0 ? a : gcd(b, a % b);
+}
+```
+
+最小公倍数为两数的乘积除以最大公约数。
+
+```java
+int lcm(int a, int b) {
+ return a * b / gcd(a, b);
+}
+```
+
+**使用位操作和减法求解最大公约数**
+
+[编程之美:2.7](#)
+
+对于 a 和 b 的最大公约数 f(a, b),有:
+
+- 如果 a 和 b 均为偶数,f(a, b) = 2\*f(a/2, b/2);
+- 如果 a 是偶数 b 是奇数,f(a, b) = f(a/2, b);
+- 如果 b 是偶数 a 是奇数,f(a, b) = f(a, b/2);
+- 如果 a 和 b 均为奇数,f(a, b) = f(b, a-b);
+
+乘 2 和除 2 都可以转换为移位操作。
+
+```java
+public int gcd(int a, int b) {
+ if (a < b) {
+ return gcd(b, a);
+ }
+ if (b == 0) {
+ return a;
+ }
+ boolean isAEven = isEven(a), isBEven = isEven(b);
+ if (isAEven && isBEven) {
+ return 2 * gcd(a >> 1, b >> 1);
+ } else if (isAEven && !isBEven) {
+ return gcd(a >> 1, b);
+ } else if (!isAEven && isBEven) {
+ return gcd(a, b >> 1);
+ } else {
+ return gcd(b, a - b);
+ }
+}
+```
+
+### 进制转换
+
+**7 进制**
+
+[504. Base 7 (Easy)](https://leetcode.com/problems/base-7/description/)
+
+```java
+public String convertToBase7(int num) {
+ if (num == 0) {
+ return "0";
+ }
+ StringBuilder sb = new StringBuilder();
+ boolean isNegative = num < 0;
+ if (isNegative) {
+ num = -num;
+ }
+ while (num > 0) {
+ sb.append(num % 7);
+ num /= 7;
+ }
+ String ret = sb.reverse().toString();
+ return isNegative ? "-" + ret : ret;
+}
+```
+
+Java 中 static String toString(int num, int radix) 可以将一个整数转换为 radix 进制表示的字符串。
+
+```java
+public String convertToBase7(int num) {
+ return Integer.toString(num, 7);
+}
+```
+
+**16 进制**
+
+[405. Convert a Number to Hexadecimal (Easy)](https://leetcode.com/problems/convert-a-number-to-hexadecimal/description/)
+
+```html
+Input:
+26
+
+Output:
+"1a"
+
+Input:
+-1
+
+Output:
+"ffffffff"
+```
+
+负数要用它的补码形式。
+
+```java
+public String toHex(int num) {
+ char[] map = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ if (num == 0) return "0";
+ StringBuilder sb = new StringBuilder();
+ while (num != 0) {
+ sb.append(map[num & 0b1111]);
+ num >>>= 4; // 因为考虑的是补码形式,因此符号位就不能有特殊的意义,需要使用无符号右移,左边填 0
+ }
+ return sb.reverse().toString();
+}
+```
+
+**26 进制**
+
+[168. Excel Sheet Column Title (Easy)](https://leetcode.com/problems/excel-sheet-column-title/description/)
+
+```html
+1 -> A
+2 -> B
+3 -> C
+...
+26 -> Z
+27 -> AA
+28 -> AB
+```
+
+因为是从 1 开始计算的,而不是从 0 开始,因此需要对 n 执行 -1 操作。
+
+```java
+public String convertToTitle(int n) {
+ if (n == 0) {
+ return "";
+ }
+ n--;
+ return convertToTitle(n / 26) + (char) (n % 26 + 'A');
+}
+```
+
+### 阶乘
+
+**统计阶乘尾部有多少个 0**
+
+[172. Factorial Trailing Zeroes (Easy)](https://leetcode.com/problems/factorial-trailing-zeroes/description/)
+
+尾部的 0 由 2 * 5 得来,2 的数量明显多于 5 的数量,因此只要统计有多少个 5 即可。
+
+对于一个数 N,它所包含 5 的个数为:N/5 + N/52 + N/53 + ...,其中 N/5 表示不大于 N 的数中 5 的倍数贡献一个 5,N/52 表示不大于 N 的数中 52 的倍数再贡献一个 5 ...。
+
+```java
+public int trailingZeroes(int n) {
+ return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5);
+}
+```
+
+如果统计的是 N! 的二进制表示中最低位 1 的位置,只要统计有多少个 2 即可,该题目出自 [编程之美:2.2](#) 。和求解有多少个 5 一样,2 的个数为 N/2 + N/22 + N/23 + ...
+
+### 字符串加法减法
+
+**二进制加法**
+
+[67. Add Binary (Easy)](https://leetcode.com/problems/add-binary/description/)
+
+```html
+a = "11"
+b = "1"
+Return "100".
+```
+
+```java
+public String addBinary(String a, String b) {
+ int i = a.length() - 1, j = b.length() - 1, carry = 0;
+ StringBuilder str = new StringBuilder();
+ while (carry == 1 || i >= 0 || j >= 0) {
+ if (i >= 0 && a.charAt(i--) == '1') {
+ carry++;
+ }
+ if (j >= 0 && b.charAt(j--) == '1') {
+ carry++;
+ }
+ str.append(carry % 2);
+ carry /= 2;
+ }
+ return str.reverse().toString();
+}
+```
+
+**字符串加法**
+
+[415. Add Strings (Easy)](https://leetcode.com/problems/add-strings/description/)
+
+字符串的值为非负整数。
+
+```java
+public String addStrings(String num1, String num2) {
+ StringBuilder str = new StringBuilder();
+ int carry = 0, i = num1.length() - 1, j = num2.length() - 1;
+ while (carry == 1 || i >= 0 || j >= 0) {
+ int x = i < 0 ? 0 : num1.charAt(i--) - '0';
+ int y = j < 0 ? 0 : num2.charAt(j--) - '0';
+ str.append((x + y + carry) % 10);
+ carry = (x + y + carry) / 10;
+ }
+ return str.reverse().toString();
+}
+```
+
+### 相遇问题
+
+**改变数组元素使所有的数组元素都相等**
+
+[462. Minimum Moves to Equal Array Elements II (Medium)](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/description/)
+
+```html
+Input:
+[1,2,3]
+
+Output:
+2
+
+Explanation:
+Only two moves are needed (remember each move increments or decrements one element):
+
+[1,2,3] => [2,2,3] => [2,2,2]
+```
+
+每次可以对一个数组元素加一或者减一,求最小的改变次数。
+
+这是个典型的相遇问题,移动距离最小的方式是所有元素都移动到中位数。理由如下:
+
+设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。
+
+设数组长度为 N,则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。
+
+**解法 1**
+
+先排序,时间复杂度:O(NlogN)
+
+```java
+public int minMoves2(int[] nums) {
+ Arrays.sort(nums);
+ int move = 0;
+ int l = 0, h = nums.length - 1;
+ while (l <= h) {
+ move += nums[h] - nums[l];
+ l++;
+ h--;
+ }
+ return move;
+}
+```
+
+**解法 2**
+
+使用快速选择找到中位数,时间复杂度 O(N)
+
+```java
+public int minMoves2(int[] nums) {
+ int move = 0;
+ int median = findKthSmallest(nums, nums.length / 2);
+ for (int num : nums) {
+ move += Math.abs(num - median);
+ }
+ return move;
+}
+
+private int findKthSmallest(int[] nums, int k) {
+ int l = 0, h = nums.length - 1;
+ while (l < h) {
+ int j = partition(nums, l, h);
+ if (j == k) {
+ break;
+ }
+ if (j < k) {
+ l = j + 1;
+ } else {
+ h = j - 1;
+ }
+ }
+ return nums[k];
+}
+
+private int partition(int[] nums, int l, int h) {
+ int i = l, j = h + 1;
+ while (true) {
+ while (nums[++i] < nums[l] && i < h) ;
+ while (nums[--j] > nums[l] && j > l) ;
+ if (i >= j) {
+ break;
+ }
+ swap(nums, i, j);
+ }
+ swap(nums, l, j);
+ return j;
+}
+
+private void swap(int[] nums, int i, int j) {
+ int tmp = nums[i];
+ nums[i] = nums[j];
+ nums[j] = tmp;
+}
+```
+
+### 多数投票问题
+
+**数组中出现次数多于 n / 2 的元素**
+
+[169. Majority Element (Easy)](https://leetcode.com/problems/majority-element/description/)
+
+先对数组排序,最中间那个数出现次数一定多于 n / 2。
+
+```java
+public int majorityElement(int[] nums) {
+ Arrays.sort(nums);
+ return nums[nums.length / 2];
+}
+```
+
+可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(N)。可以这么理解该算法:使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不相等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2,因为如果多于 i / 2 的话 cnt 就一定不会为 0。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。
+
+```java
+public int majorityElement(int[] nums) {
+ int cnt = 0, majority = nums[0];
+ for (int num : nums) {
+ majority = (cnt == 0) ? num : majority;
+ cnt = (majority == num) ? cnt + 1 : cnt - 1;
+ }
+ return majority;
+}
+```
+
+### 其它
+
+**平方数**
+
+[367. Valid Perfect Square (Easy)](https://leetcode.com/problems/valid-perfect-square/description/)
+
+```html
+Input: 16
+Returns: True
+```
+
+平方序列:1,4,9,16,..
+
+间隔:3,5,7,...
+
+间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。
+
+```java
+public boolean isPerfectSquare(int num) {
+ int subNum = 1;
+ while (num > 0) {
+ num -= subNum;
+ subNum += 2;
+ }
+ return num == 0;
+}
+```
+
+**3 的 n 次方**
+
+[326. Power of Three (Easy)](https://leetcode.com/problems/power-of-three/description/)
+
+```java
+public boolean isPowerOfThree(int n) {
+ return n > 0 && (1162261467 % n == 0);
+}
+```
+
+**乘积数组**
+
+[238. Product of Array Except Self (Medium)](https://leetcode.com/problems/product-of-array-except-self/description/)
+
+```html
+For example, given [1,2,3,4], return [24,12,8,6].
+```
+
+给定一个数组,创建一个新数组,新数组的每个元素为原始数组中除了该位置上的元素之外所有元素的乘积。
+
+要求时间复杂度为 O(N),并且不能使用除法。
+
+```java
+public int[] productExceptSelf(int[] nums) {
+ int n = nums.length;
+ int[] products = new int[n];
+ Arrays.fill(products, 1);
+ int left = 1;
+ for (int i = 1; i < n; i++) {
+ left *= nums[i - 1];
+ products[i] *= left;
+ }
+ int right = 1;
+ for (int i = n - 2; i >= 0; i--) {
+ right *= nums[i + 1];
+ products[i] *= right;
+ }
+ return products;
+}
+```
+
+**找出数组中的乘积最大的三个数**
+
+[628. Maximum Product of Three Numbers (Easy)](https://leetcode.com/problems/maximum-product-of-three-numbers/description/)
+
+```html
+Input: [1,2,3,4]
+Output: 24
+```
+
+```java
+public int maximumProduct(int[] nums) {
+ int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE, min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
+ for (int n : nums) {
+ if (n > max1) {
+ max3 = max2;
+ max2 = max1;
+ max1 = n;
+ } else if (n > max2) {
+ max3 = max2;
+ max2 = n;
+ } else if (n > max3) {
+ max3 = n;
+ }
+
+ if (n < min1) {
+ min2 = min1;
+ min1 = n;
+ } else if (n < min2) {
+ min2 = n;
+ }
+ }
+ return Math.max(max1*max2*max3, max1*min1*min2);
+}
+```
+
+# 数据结构相关
+
+## 链表
+
+链表是空节点,或者有一个值和一个指向下一个链表的指针,因此很多链表问题可以用递归来处理。
+
+**找出两个链表的交点**
+
+[160. Intersection of Two Linked Lists (Easy)](https://leetcode.com/problems/intersection-of-two-linked-lists/description/)
+
+```html
+A: a1 → a2
+ ↘
+ c1 → c2 → c3
+ ↗
+B: b1 → b2 → b3
+```
+
+要求:时间复杂度为 O(N),空间复杂度为 O(1)
+
+设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。
+
+当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。
+
+```java
+public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
+ ListNode l1 = headA, l2 = headB;
+ while (l1 != l2) {
+ l1 = (l1 == null) ? headB : l1.next;
+ l2 = (l2 == null) ? headA : l2.next;
+ }
+ return l1;
+}
+```
+
+如果只是判断是否存在交点,那么就是另一个问题,即 [编程之美 3.6]() 的问题。有两种解法:
+
+- 把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;
+- 或者直接比较两个链表的最后一个节点是否相同。
+
+**链表反转**
+
+[206. Reverse Linked List (Easy)](https://leetcode.com/problems/reverse-linked-list/description/)
+
+递归
+
+```java
+public ListNode reverseList(ListNode head) {
+ if (head == null || head.next == null) {
+ return head;
+ }
+ ListNode next = head.next;
+ ListNode newHead = reverseList(next);
+ next.next = head;
+ head.next = null;
+ return newHead;
+}
+```
+
+头插法
+
+```java
+public ListNode reverseList(ListNode head) {
+ ListNode newHead = new ListNode(-1);
+ while (head != null) {
+ ListNode next = head.next;
+ head.next = newHead.next;
+ newHead.next = head;
+ head = next;
+ }
+ return newHead.next;
+}
+```
+
+**归并两个有序的链表**
+
+[21. Merge Two Sorted Lists (Easy)](https://leetcode.com/problems/merge-two-sorted-lists/description/)
+
+```java
+public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
+ if (l1 == null) return l2;
+ if (l2 == null) return l1;
+ if (l1.val < l2.val) {
+ l1.next = mergeTwoLists(l1.next, l2);
+ return l1;
+ } else {
+ l2.next = mergeTwoLists(l1, l2.next);
+ return l2;
+ }
+}
+```
+
+**从有序链表中删除重复节点**
+
+[83. Remove Duplicates from Sorted List (Easy)](https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/)
+
+```html
+Given 1->1->2, return 1->2.
+Given 1->1->2->3->3, return 1->2->3.
+```
+
+```java
+public ListNode deleteDuplicates(ListNode head) {
+ if (head == null || head.next == null) return head;
+ head.next = deleteDuplicates(head.next);
+ return head.val == head.next.val ? head.next : head;
+}
+```
+
+**删除链表的倒数第 n 个节点**
+
+[19. Remove Nth Node From End of List (Medium)](https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/)
+
+```html
+Given linked list: 1->2->3->4->5, and n = 2.
+After removing the second node from the end, the linked list becomes 1->2->3->5.
+```
+
+```java
+public ListNode removeNthFromEnd(ListNode head, int n) {
+ ListNode fast = head;
+ while (n-- > 0) {
+ fast = fast.next;
+ }
+ if (fast == null) return head.next;
+ ListNode slow = head;
+ while (fast.next != null) {
+ fast = fast.next;
+ slow = slow.next;
+ }
+ slow.next = slow.next.next;
+ return head;
+}
+```
+
+**交换链表中的相邻结点**
+
+[24. Swap Nodes in Pairs (Medium)](https://leetcode.com/problems/swap-nodes-in-pairs/description/)
+
+```html
+Given 1->2->3->4, you should return the list as 2->1->4->3.
+```
+
+题目要求:不能修改结点的 val 值,O(1) 空间复杂度。
+
+```java
+public ListNode swapPairs(ListNode head) {
+ ListNode node = new ListNode(-1);
+ node.next = head;
+ ListNode pre = node;
+ while (pre.next != null && pre.next.next != null) {
+ ListNode l1 = pre.next, l2 = pre.next.next;
+ ListNode next = l2.next;
+ l1.next = next;
+ l2.next = l1;
+ pre.next = l2;
+
+ pre = l1;
+ }
+ return node.next;
+}
+```
+
+**链表求和**
+
+[445. Add Two Numbers II (Medium)](https://leetcode.com/problems/add-two-numbers-ii/description/)
+
+```html
+Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
+Output: 7 -> 8 -> 0 -> 7
+```
+
+题目要求:不能修改原始链表。
+
+```java
+public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
+ Stack l1Stack = buildStack(l1);
+ Stack l2Stack = buildStack(l2);
+ ListNode head = new ListNode(-1);
+ int carry = 0;
+ while (!l1Stack.isEmpty() || !l2Stack.isEmpty() || carry != 0) {
+ int x = l1Stack.isEmpty() ? 0 : l1Stack.pop();
+ int y = l2Stack.isEmpty() ? 0 : l2Stack.pop();
+ int sum = x + y + carry;
+ ListNode node = new ListNode(sum % 10);
+ node.next = head.next;
+ head.next = node;
+ carry = sum / 10;
+ }
+ return head.next;
+}
+
+private Stack buildStack(ListNode l) {
+ Stack stack = new Stack<>();
+ while (l != null) {
+ stack.push(l.val);
+ l = l.next;
+ }
+ return stack;
+}
+```
+
+**回文链表**
+
+[234. Palindrome Linked List (Easy)](https://leetcode.com/problems/palindrome-linked-list/description/)
+
+题目要求:以 O(1) 的空间复杂度来求解。
+
+切成两半,把后半段反转,然后比较两半是否相等。
+
+```java
+public boolean isPalindrome(ListNode head) {
+ if (head == null || head.next == null) return true;
+ ListNode slow = head, fast = head.next;
+ while (fast != null && fast.next != null) {
+ slow = slow.next;
+ fast = fast.next.next;
+ }
+ if (fast != null) slow = slow.next; // 偶数节点,让 slow 指向下一个节点
+ cut(head, slow); // 切成两个链表
+ return isEqual(head, reverse(slow));
+}
+
+private void cut(ListNode head, ListNode cutNode) {
+ while (head.next != cutNode) {
+ head = head.next;
+ }
+ head.next = null;
+}
+
+private ListNode reverse(ListNode head) {
+ ListNode newHead = null;
+ while (head != null) {
+ ListNode nextNode = head.next;
+ head.next = newHead;
+ newHead = head;
+ head = nextNode;
+ }
+ return newHead;
+}
+
+private boolean isEqual(ListNode l1, ListNode l2) {
+ while (l1 != null && l2 != null) {
+ if (l1.val != l2.val) return false;
+ l1 = l1.next;
+ l2 = l2.next;
+ }
+ return true;
+}
+```
+
+**分隔链表**
+
+[725. Split Linked List in Parts(Medium)](https://leetcode.com/problems/split-linked-list-in-parts/description/)
+
+```html
+Input:
+root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
+Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
+Explanation:
+The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.
+```
+
+题目描述:把链表分隔成 k 部分,每部分的长度都应该尽可能相同,排在前面的长度应该大于等于后面的。
+
+```java
+public ListNode[] splitListToParts(ListNode root, int k) {
+ int N = 0;
+ ListNode cur = root;
+ while (cur != null) {
+ N++;
+ cur = cur.next;
+ }
+ int mod = N % k;
+ int size = N / k;
+ ListNode[] ret = new ListNode[k];
+ cur = root;
+ for (int i = 0; cur != null && i < k; i++) {
+ ret[i] = cur;
+ int curSize = size + (mod-- > 0 ? 1 : 0);
+ for (int j = 0; j < curSize - 1; j++) {
+ cur = cur.next;
+ }
+ ListNode next = cur.next;
+ cur.next = null;
+ cur = next;
+ }
+ return ret;
+}
+```
+
+**链表元素按奇偶聚集**
+
+[328. Odd Even Linked List (Medium)](https://leetcode.com/problems/odd-even-linked-list/description/)
+
+```html
+Example:
+Given 1->2->3->4->5->NULL,
+return 1->3->5->2->4->NULL.
+```
+
+```java
+public ListNode oddEvenList(ListNode head) {
+ if (head == null) {
+ return head;
+ }
+ ListNode odd = head, even = head.next, evenHead = even;
+ while (even != null && even.next != null) {
+ odd.next = odd.next.next;
+ odd = odd.next;
+ even.next = even.next.next;
+ even = even.next;
+ }
+ odd.next = evenHead;
+ return head;
+}
+```
+
+## 树
+
+### 递归
+
+一棵树要么是空树,要么有两个指针,每个指针指向一棵树。树是一种递归结构,很多树的问题可以使用递归来处理。
+
+**树的高度**
+
+[104. Maximum Depth of Binary Tree (Easy)](https://leetcode.com/problems/maximum-depth-of-binary-tree/description/)
+
+```java
+public int maxDepth(TreeNode root) {
+ if (root == null) return 0;
+ return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
+}
+```
+
+**平衡树**
+
+[110. Balanced Binary Tree (Easy)](https://leetcode.com/problems/balanced-binary-tree/description/)
+
+```html
+ 3
+ / \
+ 9 20
+ / \
+ 15 7
+```
+
+平衡树左右子树高度差都小于等于 1
+
+```java
+private boolean result = true;
+
+public boolean isBalanced(TreeNode root) {
+ maxDepth(root);
+ return result;
+}
+
+public int maxDepth(TreeNode root) {
+ if (root == null) return 0;
+ int l = maxDepth(root.left);
+ int r = maxDepth(root.right);
+ if (Math.abs(l - r) > 1) result = false;
+ return 1 + Math.max(l, r);
+}
+```
+
+**两节点的最长路径**
+
+[543. Diameter of Binary Tree (Easy)](https://leetcode.com/problems/diameter-of-binary-tree/description/)
+
+```html
+Input:
+
+ 1
+ / \
+ 2 3
+ / \
+ 4 5
+
+Return 3, which is the length of the path [4,2,1,3] or [5,2,1,3].
+```
+
+```java
+private int max = 0;
+
+public int diameterOfBinaryTree(TreeNode root) {
+ depth(root);
+ return max;
+}
+
+private int depth(TreeNode root) {
+ if (root == null) return 0;
+ int leftDepth = depth(root.left);
+ int rightDepth = depth(root.right);
+ max = Math.max(max, leftDepth + rightDepth);
+ return Math.max(leftDepth, rightDepth) + 1;
+}
+```
+
+**翻转树**
+
+[226. Invert Binary Tree (Easy)](https://leetcode.com/problems/invert-binary-tree/description/)
+
+```java
+public TreeNode invertTree(TreeNode root) {
+ if (root == null) return null;
+ TreeNode left = root.left; // 后面的操作会改变 left 指针,因此先保存下来
+ root.left = invertTree(root.right);
+ root.right = invertTree(left);
+ return root;
+}
+```
+
+**归并两棵树**
+
+[617. Merge Two Binary Trees (Easy)](https://leetcode.com/problems/merge-two-binary-trees/description/)
+
+```html
+Input:
+ Tree 1 Tree 2
+ 1 2
+ / \ / \
+ 3 2 1 3
+ / \ \
+ 5 4 7
+
+Output:
+ 3
+ / \
+ 4 5
+ / \ \
+ 5 4 7
+```
+
+```java
+public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
+ if (t1 == null && t2 == null) return null;
+ if (t1 == null) return t2;
+ if (t2 == null) return t1;
+ TreeNode root = new TreeNode(t1.val + t2.val);
+ root.left = mergeTrees(t1.left, t2.left);
+ root.right = mergeTrees(t1.right, t2.right);
+ return root;
+}
+```
+
+**判断路径和是否等于一个数**
+
+[Leetcdoe : 112. Path Sum (Easy)](https://leetcode.com/problems/path-sum/description/)
+
+```html
+Given the below binary tree and sum = 22,
+
+ 5
+ / \
+ 4 8
+ / / \
+ 11 13 4
+ / \ \
+ 7 2 1
+
+return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
+```
+
+路径和定义为从 root 到 leaf 的所有节点的和。
+
+```java
+public boolean hasPathSum(TreeNode root, int sum) {
+ if (root == null) return false;
+ if (root.left == null && root.right == null && root.val == sum) return true;
+ return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
+}
+```
+
+**统计路径和等于一个数的路径数量**
+
+[437. Path Sum III (Easy)](https://leetcode.com/problems/path-sum-iii/description/)
+
+```html
+root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
+
+ 10
+ / \
+ 5 -3
+ / \ \
+ 3 2 11
+ / \ \
+3 -2 1
+
+Return 3. The paths that sum to 8 are:
+
+1. 5 -> 3
+2. 5 -> 2 -> 1
+3. -3 -> 11
+```
+
+路径不一定以 root 开头,也不一定以 leaf 结尾,但是必须连续。
+
+```java
+public int pathSum(TreeNode root, int sum) {
+ if (root == null) return 0;
+ int ret = pathSumStartWithRoot(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
+ return ret;
+}
+
+private int pathSumStartWithRoot(TreeNode root, int sum) {
+ if (root == null) return 0;
+ int ret = 0;
+ if (root.val == sum) ret++;
+ ret += pathSumStartWithRoot(root.left, sum - root.val) + pathSumStartWithRoot(root.right, sum - root.val);
+ return ret;
+}
+```
+
+**子树**
+
+[572. Subtree of Another Tree (Easy)](https://leetcode.com/problems/subtree-of-another-tree/description/)
+
+```html
+Given tree s:
+ 3
+ / \
+ 4 5
+ / \
+ 1 2
+
+Given tree t:
+ 4
+ / \
+ 1 2
+
+Return true, because t has the same structure and node values with a subtree of s.
+
+Given tree s:
+
+ 3
+ / \
+ 4 5
+ / \
+ 1 2
+ /
+ 0
+
+Given tree t:
+ 4
+ / \
+ 1 2
+
+Return false.
+```
+
+```java
+public boolean isSubtree(TreeNode s, TreeNode t) {
+ if (s == null) return false;
+ return isSubtreeWithRoot(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
+}
+
+private boolean isSubtreeWithRoot(TreeNode s, TreeNode t) {
+ if (t == null && s == null) return true;
+ if (t == null || s == null) return false;
+ if (t.val != s.val) return false;
+ return isSubtreeWithRoot(s.left, t.left) && isSubtreeWithRoot(s.right, t.right);
+}
+```
+
+**树的对称**
+
+[101. Symmetric Tree (Easy)](https://leetcode.com/problems/symmetric-tree/description/)
+
+```html
+ 1
+ / \
+ 2 2
+ / \ / \
+3 4 4 3
+```
+
+```java
+public boolean isSymmetric(TreeNode root) {
+ if (root == null) return true;
+ return isSymmetric(root.left, root.right);
+}
+
+private boolean isSymmetric(TreeNode t1, TreeNode t2) {
+ if (t1 == null && t2 == null) return true;
+ if (t1 == null || t2 == null) return false;
+ if (t1.val != t2.val) return false;
+ return isSymmetric(t1.left, t2.right) && isSymmetric(t1.right, t2.left);
+}
+```
+
+**最小路径**
+
+[111. Minimum Depth of Binary Tree (Easy)](https://leetcode.com/problems/minimum-depth-of-binary-tree/description/)
+
+树的根节点到叶子节点的最小路径长度
+
+```java
+public int minDepth(TreeNode root) {
+ if (root == null) return 0;
+ int left = minDepth(root.left);
+ int right = minDepth(root.right);
+ if (left == 0 || right == 0) return left + right + 1;
+ return Math.min(left, right) + 1;
+}
+```
+
+**统计左叶子节点的和**
+
+[404. Sum of Left Leaves (Easy)](https://leetcode.com/problems/sum-of-left-leaves/description/)
+
+```html
+ 3
+ / \
+ 9 20
+ / \
+ 15 7
+
+There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24.
+```
+
+```java
+public int sumOfLeftLeaves(TreeNode root) {
+ if (root == null) return 0;
+ if (isLeaf(root.left)) return root.left.val + sumOfLeftLeaves(root.right);
+ return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
+}
+
+private boolean isLeaf(TreeNode node){
+ if (node == null) return false;
+ return node.left == null && node.right == null;
+}
+```
+
+**相同节点值的最大路径长度**
+
+[687. Longest Univalue Path (Easy)](https://leetcode.com/problems/longest-univalue-path/)
+
+```html
+ 1
+ / \
+ 4 5
+ / \ \
+ 4 4 5
+
+Output : 2
+```
+
+```java
+private int path = 0;
+
+public int longestUnivaluePath(TreeNode root) {
+ dfs(root);
+ return path;
+}
+
+private int dfs(TreeNode root){
+ if (root == null) return 0;
+ int left = dfs(root.left);
+ int right = dfs(root.right);
+ int leftPath = root.left != null && root.left.val == root.val ? left + 1 : 0;
+ int rightPath = root.right != null && root.right.val == root.val ? right + 1 : 0;
+ path = Math.max(path, leftPath + rightPath);
+ return Math.max(leftPath, rightPath);
+}
+```
+
+**间隔遍历**
+
+[337. House Robber III (Medium)](https://leetcode.com/problems/house-robber-iii/description/)
+
+```html
+ 3
+ / \
+ 2 3
+ \ \
+ 3 1
+Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
+```
+
+```java
+public int rob(TreeNode root) {
+ if (root == null) return 0;
+ int val1 = root.val;
+ if (root.left != null) val1 += rob(root.left.left) + rob(root.left.right);
+ if (root.right != null) val1 += rob(root.right.left) + rob(root.right.right);
+ int val2 = rob(root.left) + rob(root.right);
+ return Math.max(val1, val2);
+}
+```
+
+**找出二叉树中第二小的节点**
+
+[671. Second Minimum Node In a Binary Tree (Easy)](https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/description/)
+
+```html
+Input:
+ 2
+ / \
+ 2 5
+ / \
+ 5 7
+
+Output: 5
+```
+
+一个节点要么具有 0 个或 2 个子节点,如果有子节点,那么根节点是最小的节点。
+
+```java
+public int findSecondMinimumValue(TreeNode root) {
+ if (root == null) return -1;
+ if (root.left == null && root.right == null) return -1;
+ int leftVal = root.left.val;
+ int rightVal = root.right.val;
+ if (leftVal == root.val) leftVal = findSecondMinimumValue(root.left);
+ if (rightVal == root.val) rightVal = findSecondMinimumValue(root.right);
+ if (leftVal != -1 && rightVal != -1) return Math.min(leftVal, rightVal);
+ if (leftVal != -1) return leftVal;
+ return rightVal;
+}
+```
+
+### 层次遍历
+
+使用 BFS 进行层次遍历。不需要使用两个队列来分别存储当前层的节点和下一层的节点,因为在开始遍历一层的节点时,当前队列中的节点数就是当前层的节点数,只要控制遍历这么多节点数,就能保证这次遍历的都是当前层的节点。
+
+**一棵树每层节点的平均数**
+
+[637. Average of Levels in Binary Tree (Easy)](https://leetcode.com/problems/average-of-levels-in-binary-tree/description/)
+
+```java
+public List averageOfLevels(TreeNode root) {
+ List ret = new ArrayList<>();
+ if (root == null) return ret;
+ Queue queue = new LinkedList<>();
+ queue.add(root);
+ while (!queue.isEmpty()) {
+ int cnt = queue.size();
+ double sum = 0;
+ for (int i = 0; i < cnt; i++) {
+ TreeNode node = queue.poll();
+ sum += node.val;
+ if (node.left != null) queue.add(node.left);
+ if (node.right != null) queue.add(node.right);
+ }
+ ret.add(sum / cnt);
+ }
+ return ret;
+}
+```
+
+**得到左下角的节点**
+
+[513. Find Bottom Left Tree Value (Easy)](https://leetcode.com/problems/find-bottom-left-tree-value/description/)
+
+```html
+Input:
+
+ 1
+ / \
+ 2 3
+ / / \
+ 4 5 6
+ /
+ 7
+
+Output:
+7
+```
+
+```java
+public int findBottomLeftValue(TreeNode root) {
+ Queue queue = new LinkedList<>();
+ queue.add(root);
+ while (!queue.isEmpty()) {
+ root = queue.poll();
+ if (root.right != null) queue.add(root.right);
+ if (root.left != null) queue.add(root.left);
+ }
+ return root.val;
+}
+```
+
+### 前中后序遍历
+
+```html
+ 1
+ / \
+ 2 3
+ / \ \
+4 5 6
+```
+
+- 层次遍历顺序:[1 2 3 4 5 6]
+- 前序遍历顺序:[1 2 4 5 3 6]
+- 中序遍历顺序:[4 2 5 1 3 6]
+- 后序遍历顺序:[4 5 2 6 3 1]
+
+层次遍历使用 BFS 实现,利用的就是 BFS 一层一层遍历的特性;而前序、中序、后序遍历利用了 DFS 实现。
+
+前序、中序、后序遍只是在对节点访问的顺序有一点不同,其它都相同。
+
+① 前序
+
+```java
+void dfs(TreeNode root) {
+ visit(root);
+ dfs(root.left);
+ dfs(root.right);
+}
+```
+
+② 中序
+
+```java
+void dfs(TreeNode root) {
+ dfs(root.left);
+ visit(root);
+ dfs(root.right);
+}
+```
+
+③ 后序
+
+```java
+void dfs(TreeNode root) {
+ dfs(root.left);
+ dfs(root.right);
+ visit(root);
+}
+```
+
+**非递归实现二叉树的前序遍历**
+
+[144. Binary Tree Preorder Traversal (Medium)](https://leetcode.com/problems/binary-tree-preorder-traversal/description/)
+
+```java
+public List preorderTraversal(TreeNode root) {
+ List ret = new ArrayList<>();
+ Stack stack = new Stack<>();
+ stack.push(root);
+ while (!stack.isEmpty()) {
+ TreeNode node = stack.pop();
+ if (node == null) continue;
+ ret.add(node.val);
+ stack.push(node.right); // 先右后左,保证左子树先遍历
+ stack.push(node.left);
+ }
+ return ret;
+}
+```
+
+**非递归实现二叉树的后序遍历**
+
+[145. Binary Tree Postorder Traversal (Medium)](https://leetcode.com/problems/binary-tree-postorder-traversal/description/)
+
+前序遍历为 root -> left -> right,后序遍历为 left -> right -> root。可以修改前序遍历成为 root -> right -> left,那么这个顺序就和后序遍历正好相反。
+
+```java
+public List postorderTraversal(TreeNode root) {
+ List ret = new ArrayList<>();
+ Stack stack = new Stack<>();
+ stack.push(root);
+ while (!stack.isEmpty()) {
+ TreeNode node = stack.pop();
+ if (node == null) continue;
+ ret.add(node.val);
+ stack.push(node.left);
+ stack.push(node.right);
+ }
+ Collections.reverse(ret);
+ return ret;
+}
+```
+
+**非递归实现二叉树的中序遍历**
+
+[94. Binary Tree Inorder Traversal (Medium)](https://leetcode.com/problems/binary-tree-inorder-traversal/description/)
+
+```java
+public List inorderTraversal(TreeNode root) {
+ List ret = new ArrayList<>();
+ if (root == null) return ret;
+ Stack stack = new Stack<>();
+ TreeNode cur = root;
+ while (cur != null || !stack.isEmpty()) {
+ while (cur != null) {
+ stack.push(cur);
+ cur = cur.left;
+ }
+ TreeNode node = stack.pop();
+ ret.add(node.val);
+ cur = node.right;
+ }
+ return ret;
+}
+```
+
+### BST
+
+二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点。
+
+二叉查找树中序遍历有序。
+
+**修剪二叉查找树**
+
+[669. Trim a Binary Search Tree (Easy)](https://leetcode.com/problems/trim-a-binary-search-tree/description/)
+
+```html
+Input:
+
+ 3
+ / \
+ 0 4
+ \
+ 2
+ /
+ 1
+
+ L = 1
+ R = 3
+
+Output:
+
+ 3
+ /
+ 2
+ /
+ 1
+```
+
+题目描述:只保留值在 L \~ R 之间的节点
+
+```java
+public TreeNode trimBST(TreeNode root, int L, int R) {
+ if (root == null) return null;
+ if (root.val > R) return trimBST(root.left, L, R);
+ if (root.val < L) return trimBST(root.right, L, R);
+ root.left = trimBST(root.left, L, R);
+ root.right = trimBST(root.right, L, R);
+ return root;
+}
+```
+
+**寻找二叉查找树的第 k 个元素**
+
+[230. Kth Smallest Element in a BST (Medium)](https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/)
+
+
+中序遍历解法:
+
+```java
+private int cnt = 0;
+private int val;
+
+public int kthSmallest(TreeNode root, int k) {
+ inOrder(root, k);
+ return val;
+}
+
+private void inOrder(TreeNode node, int k) {
+ if (node == null) return;
+ inOrder(node.left, k);
+ cnt++;
+ if (cnt == k) {
+ val = node.val;
+ return;
+ }
+ inOrder(node.right, k);
+}
+```
+
+递归解法:
+
+```java
+public int kthSmallest(TreeNode root, int k) {
+ int leftCnt = count(root.left);
+ if (leftCnt == k - 1) return root.val;
+ if (leftCnt > k - 1) return kthSmallest(root.left, k);
+ return kthSmallest(root.right, k - leftCnt - 1);
+}
+
+private int count(TreeNode node) {
+ if (node == null) return 0;
+ return 1 + count(node.left) + count(node.right);
+}
+```
+
+**把二叉查找树每个节点的值都加上比它大的节点的值**
+
+[Convert BST to Greater Tree (Easy)](https://leetcode.com/problems/convert-bst-to-greater-tree/description/)
+
+```html
+Input: The root of a Binary Search Tree like this:
+
+ 5
+ / \
+ 2 13
+
+Output: The root of a Greater Tree like this:
+
+ 18
+ / \
+ 20 13
+```
+
+先遍历右子树。
+
+```java
+private int sum = 0;
+
+public TreeNode convertBST(TreeNode root) {
+ traver(root);
+ return root;
+}
+
+private void traver(TreeNode node) {
+ if (node == null) return;
+ traver(node.right);
+ sum += node.val;
+ node.val = sum;
+ traver(node.left);
+}
+```
+
+**二叉查找树的最近公共祖先**
+
+[235. Lowest Common Ancestor of a Binary Search Tree (Easy)](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/)
+
+```html
+ _______6______
+ / \
+ ___2__ ___8__
+ / \ / \
+0 4 7 9
+ / \
+ 3 5
+
+For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
+```
+
+```java
+public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
+ if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);
+ if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);
+ return root;
+}
+```
+
+**二叉树的最近公共祖先**
+
+[236. Lowest Common Ancestor of a Binary Tree (Medium) ](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/)
+
+```html
+ _______3______
+ / \
+ ___5__ ___1__
+ / \ / \
+6 2 0 8
+ / \
+ 7 4
+
+For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.
+```
+
+```java
+public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
+ if (root == null || root == p || root == q) return root;
+ TreeNode left = lowestCommonAncestor(root.left, p, q);
+ TreeNode right = lowestCommonAncestor(root.right, p, q);
+ return left == null ? right : right == null ? left : root;
+}
+```
+
+**从有序数组中构造二叉查找树**
+
+[108. Convert Sorted Array to Binary Search Tree (Easy)](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/description/)
+
+```java
+public TreeNode sortedArrayToBST(int[] nums) {
+ return toBST(nums, 0, nums.length - 1);
+}
+
+private TreeNode toBST(int[] nums, int sIdx, int eIdx){
+ if (sIdx > eIdx) return null;
+ int mIdx = (sIdx + eIdx) / 2;
+ TreeNode root = new TreeNode(nums[mIdx]);
+ root.left = toBST(nums, sIdx, mIdx - 1);
+ root.right = toBST(nums, mIdx + 1, eIdx);
+ return root;
+}
+```
+
+**根据有序链表构造平衡的二叉查找树**
+
+[109. Convert Sorted List to Binary Search Tree (Medium)](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/description/)
+
+```html
+Given the sorted linked list: [-10,-3,0,5,9],
+
+One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:
+
+ 0
+ / \
+ -3 9
+ / /
+ -10 5
+```
+
+```java
+public TreeNode sortedListToBST(ListNode head) {
+ if (head == null) return null;
+ if (head.next == null) return new TreeNode(head.val);
+ ListNode preMid = preMid(head);
+ ListNode mid = preMid.next;
+ preMid.next = null; // 断开链表
+ TreeNode t = new TreeNode(mid.val);
+ t.left = sortedListToBST(head);
+ t.right = sortedListToBST(mid.next);
+ return t;
+}
+
+private ListNode preMid(ListNode head) {
+ ListNode slow = head, fast = head.next;
+ ListNode pre = head;
+ while (fast != null && fast.next != null) {
+ pre = slow;
+ slow = slow.next;
+ fast = fast.next.next;
+ }
+ return pre;
+}
+```
+
+**在二叉查找树中寻找两个节点,使它们的和为一个给定值**
+
+[653. Two Sum IV - Input is a BST (Easy)](https://leetcode.com/problems/two-sum-iv-input-is-a-bst/description/)
+
+```html
+Input:
+
+ 5
+ / \
+ 3 6
+ / \ \
+2 4 7
+
+Target = 9
+
+Output: True
+```
+
+使用中序遍历得到有序数组之后,再利用双指针对数组进行查找。
+
+应该注意到,这一题不能用分别在左右子树两部分来处理这种思想,因为两个待求的节点可能分别在左右子树中。
+
+```java
+public boolean findTarget(TreeNode root, int k) {
+ List nums = new ArrayList<>();
+ inOrder(root, nums);
+ int i = 0, j = nums.size() - 1;
+ while (i < j) {
+ int sum = nums.get(i) + nums.get(j);
+ if (sum == k) return true;
+ if (sum < k) i++;
+ else j--;
+ }
+ return false;
+}
+
+private void inOrder(TreeNode root, List nums) {
+ if (root == null) return;
+ inOrder(root.left, nums);
+ nums.add(root.val);
+ inOrder(root.right, nums);
+}
+```
+
+**在二叉查找树中查找两个节点之差的最小绝对值**
+
+[530. Minimum Absolute Difference in BST (Easy)](https://leetcode.com/problems/minimum-absolute-difference-in-bst/description/)
+
+```html
+Input:
+
+ 1
+ \
+ 3
+ /
+ 2
+
+Output:
+
+1
+```
+
+利用二叉查找树的中序遍历为有序的性质,计算中序遍历中临近的两个节点之差的绝对值,取最小值。
+
+```java
+private int minDiff = Integer.MAX_VALUE;
+private TreeNode preNode = null;
+
+public int getMinimumDifference(TreeNode root) {
+ inOrder(root);
+ return minDiff;
+}
+
+private void inOrder(TreeNode node) {
+ if (node == null) return;
+ inOrder(node.left);
+ if (preNode != null) minDiff = Math.min(minDiff, node.val - preNode.val);
+ preNode = node;
+ inOrder(node.right);
+}
+```
+
+**寻找二叉查找树中出现次数最多的值**
+
+[501. Find Mode in Binary Search Tree (Easy)](https://leetcode.com/problems/find-mode-in-binary-search-tree/description/)
+
+```html
+ 1
+ \
+ 2
+ /
+ 2
+
+return [2].
+```
+
+答案可能不止一个,也就是有多个值出现的次数一样多。
+
+```java
+private int curCnt = 1;
+private int maxCnt = 1;
+private TreeNode preNode = null;
+
+public int[] findMode(TreeNode root) {
+ List maxCntNums = new ArrayList<>();
+ inOrder(root, maxCntNums);
+ int[] ret = new int[maxCntNums.size()];
+ int idx = 0;
+ for (int num : maxCntNums) {
+ ret[idx++] = num;
+ }
+ return ret;
+}
+
+private void inOrder(TreeNode node, List nums) {
+ if (node == null) return;
+ inOrder(node.left, nums);
+ if (preNode != null) {
+ if (preNode.val == node.val) curCnt++;
+ else curCnt = 1;
+ }
+ if (curCnt > maxCnt) {
+ maxCnt = curCnt;
+ nums.clear();
+ nums.add(node.val);
+ } else if (curCnt == maxCnt) {
+ nums.add(node.val);
+ }
+ preNode = node;
+ inOrder(node.right, nums);
+}
+```
+
+### Trie
+
+