auto commit

This commit is contained in:
CyC2018 2019-03-20 13:07:49 +08:00
parent 6929a96a35
commit ae995ea593
54 changed files with 495 additions and 497 deletions

View File

@ -14,15 +14,15 @@
Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其他机器中。
<div align="center"> <img src="pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/> </div><br>
# 二、与虚拟机的比较
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
<div align="center"> <img src="pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png" width="250px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png" width="250px"/> </div><br>
<div align="center"> <img src="pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png" width="250"/> </div><br>
## 启动速度
@ -76,7 +76,7 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
构建容器时通过在镜像的基础上添加一个可写层writable layer用来保存着容器运行过程中的修改。
<div align="center"> <img src="pics/docker-filesystems-busyboxrw.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/docker-filesystems-busyboxrw.png"/> </div><br>
# 参考资料

View File

@ -18,7 +18,7 @@
Git 属于分布式版本控制系统,而 SVN 属于集中式。
<div align="center"> <img src="pics/fac3dfd6-1656-4329-9a80-7f6c51ef30c5_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fac3dfd6-1656-4329-9a80-7f6c51ef30c5_200.png"/> </div><br>
集中式版本控制只有中心服务器拥有一份代码,而分布式版本控制每个人的电脑上就有一份完整的代码。
@ -40,45 +40,45 @@ Github 就是一个中心服务器。
Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库History 中存有所有分支,使用一个 HEAD 指针指向当前分支。
<div align="center"> <img src="pics/0f9b9d2a-c5cc-4a3f-b138-2c1035950f39_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0f9b9d2a-c5cc-4a3f-b138-2c1035950f39_200.png"/> </div><br>
- git add files 把文件的修改添加到暂存区
- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
<div align="center"> <img src="pics/11a786f0-5e02-46a6-92f0-f302c9cf6ca3_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/11a786f0-5e02-46a6-92f0-f302c9cf6ca3_200.png"/> </div><br>
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
<div align="center"> <img src="pics/b48b9a7a-f9f8-4cf9-90f1-5cddd685b782_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b48b9a7a-f9f8-4cf9-90f1-5cddd685b782_200.png"/> </div><br>
# 分支实现
使用指针将每个提交连接成一条时间线HEAD 指针指向当前分支指针。
<div align="center"> <img src="pics/84d496d7-54b0-4a9b-9499-ce232057e499_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/84d496d7-54b0-4a9b-9499-ce232057e499_200.png"/> </div><br>
新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
<div align="center"> <img src="pics/7c5bcdbf-e656-4b7c-be82-b247a3589ed5_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7c5bcdbf-e656-4b7c-be82-b247a3589ed5_200.png"/> </div><br>
每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
<div align="center"> <img src="pics/13783e94-b481-4aea-9fa2-9d1973abd47e_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/13783e94-b481-4aea-9fa2-9d1973abd47e_200.png"/> </div><br>
合并分支也只需要改变指针即可。
<div align="center"> <img src="pics/15699a17-5a69-4fbe-852e-9d2b7cf05e80_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/15699a17-5a69-4fbe-852e-9d2b7cf05e80_200.png"/> </div><br>
# 冲突
当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
<div align="center"> <img src="pics/7e82ce01-2afb-4c15-b720-b81049c875c2_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7e82ce01-2afb-4c15-b720-b81049c875c2_200.png"/> </div><br>
Git 会使用 <<<<<<< ======= >>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
@ -100,7 +100,7 @@ Creating a new branch is quick AND simple.
$ git merge --no-ff -m "merge with no-ff" dev
```
<div align="center"> <img src="pics/fa1dc552-8501-439e-b85a-3d9eac704880_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fa1dc552-8501-439e-b85a-3d9eac704880_200.png"/> </div><br>
# 分支管理策略
@ -108,7 +108,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
日常开发在开发分支 dev 上进行。
<div align="center"> <img src="pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
# 储藏Stashing
@ -148,7 +148,7 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
# Git 命令一览
<div align="center"> <img src="pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
比较详细的地址http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf

View File

@ -62,17 +62,17 @@
URI 包含 URL 和 URN。
<div align="center"> <img src="pics/417cb02e-853d-4288-a36e-9161ded2c9fd_200.png" width="600px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/417cb02e-853d-4288-a36e-9161ded2c9fd_200.png" width="600px"> </div><br>
## 请求和响应报文
### 1. 请求报文
<div align="center"> <img src="pics/HTTP_RequestMessageExample.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP_RequestMessageExample.png" width=""/> </div><br>
### 2. 响应报文
<div align="center"> <img src="pics/HTTP_ResponseMessageExample.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP_ResponseMessageExample.png" width=""/> </div><br>
# 二、HTTP 方法
@ -159,7 +159,7 @@ DELETE /file.html HTTP/1.1
CONNECT www.example.com:443 HTTP/1.1
```
<div align="center"> <img src="pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
## TRACE
@ -302,7 +302,7 @@ CONNECT www.example.com:443 HTTP/1.1
## 连接管理
<div align="center"> <img src="pics/HTTP1_x_Connections.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP1_x_Connections.png" width="800"/> </div><br>
### 1. 短连接与长连接
@ -631,11 +631,11 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
- 用户察觉得到正向代理的存在。
<div align="center"> <img src="pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
- 而反向代理一般位于内部网络中,用户察觉不到。
<div align="center"> <img src="pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
### 2. 网关
@ -657,7 +657,7 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
通过使用 SSLHTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
<div align="center"> <img src="pics/ssl-offloading.jpg" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ssl-offloading.jpg" width="700"/> </div><br>
## 加密
@ -668,7 +668,7 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点:运算速度快;
- 缺点:无法安全地将密钥传输给通信方。
<div align="center"> <img src="pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
### 2.非对称密钥加密
@ -681,13 +681,13 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点:可以更安全地将公开密钥传输给通信发送方;
- 缺点:运算速度慢。
<div align="center"> <img src="pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
### 3. HTTPS 采用的加密方式
HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
<div align="center"> <img src="pics/How-HTTPS-Works.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/How-HTTPS-Works.png" width="600"/> </div><br>
## 认证
@ -699,7 +699,7 @@ HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对
进行 HTTPS 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。
<div align="center"> <img src="pics/2017-06-11-ca.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2017-06-11-ca.png" width=""/> </div><br>
## 完整性保护
@ -728,7 +728,7 @@ HTTP/1.x 实现简单是以牺牲性能为代价的:
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
<div align="center"> <img src="pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
在通信过程中,只会有一个 TCP 连接存在它承载了任意数量的双向数据流Stream
@ -736,13 +736,13 @@ HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式
- 消息Message是与逻辑请求或响应对应的完整的一系列帧。
- 帧Frame是最小的通信单位来自不同数据流的帧可以交错发送然后再根据每个帧头的数据流标识符重新组装。
<div align="center"> <img src="pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
## 服务端推送
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
<div align="center"> <img src="pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
## 首部压缩
@ -752,7 +752,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见
不仅如此HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
<div align="center"> <img src="pics/_u4E0B_u8F7D.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4E0B_u8F7D.png" width="600"/> </div><br>
# 八、HTTP/1.1 新特性

View File

@ -97,7 +97,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
<div align="center"> <img src="pics/c2c2b633-c03a-426e-b436-5719a194667b.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c2c2b633-c03a-426e-b436-5719a194667b.png"/> </div><br>
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
@ -277,7 +277,7 @@ public static void main(String[] args) throws IOException {
- Socket客户端类
- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
<div align="center"> <img src="pics/f77f06b6-7359-4066-b85d-3f6c09ddf425.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f77f06b6-7359-4066-b85d-3f6c09ddf425.jpg"/> </div><br>
## Datagram
@ -339,23 +339,23 @@ I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
<div align="center"> <img src="pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5limit 保持不变。
<div align="center"> <img src="pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position并将 position 设置为 0。
<div align="center"> <img src="pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
<div align="center"> <img src="pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
<div align="center"> <img src="pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
## 文件 NIO 实例
@ -413,7 +413,7 @@ NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用
应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
<div align="center"> <img src="pics/8fdbb8f5-2cf8-41dc-b5f1-99d98abb52d9.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8fdbb8f5-2cf8-41dc-b5f1-99d98abb52d9.jpg"/> </div><br>
### 1. 创建选择器

View File

@ -189,7 +189,7 @@ value 数组被声明为 final这意味着 value 数组初始化之后就不
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
<div align="center"> <img src="pics/474e5579-38b1-47d2-8f76-a13ae086b039.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/474e5579-38b1-47d2-8f76-a13ae086b039.jpg"/> </div><br>
**3. 安全性**
@ -1317,7 +1317,7 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception此时程序崩溃并且无法恢复。
<div align="center"> <img src="pics/PPjwP.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/PPjwP.png" width="600"/> </div><br>
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)

View File

@ -24,7 +24,7 @@
## Collection
<div align="center"> <img src="pics/6_2001550476096035.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6_2001550476096035.png"/> </div><br>
### 1. Set
@ -51,7 +51,7 @@
## Map
<div align="center"> <img src="pics/2_2001550426232419.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550426232419.png"/> </div><br>
- TreeMap基于红黑树实现。
@ -66,7 +66,7 @@
## 迭代器模式
<div align="center"> <img src="pics/91aa7c29-438f-4fcc-8c63-2a75899139de.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/91aa7c29-438f-4fcc-8c63-2a75899139de.png"/> </div><br>
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
@ -127,7 +127,7 @@ public class ArrayList<E> extends AbstractList<E>
private static final int DEFAULT_CAPACITY = 10;
```
<div align="center"> <img src="pics/7935be3d-c2b3-4213-90c9-1e68ec4ac4e7.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7935be3d-c2b3-4213-90c9-1e68ec4ac4e7.png"/> </div><br>
### 2. 扩容
@ -391,7 +391,7 @@ transient Node<E> first;
transient Node<E> last;
```
<div align="center"> <img src="pics/09184175-9bf2-40ff-8a68-3b467c77216a.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/09184175-9bf2-40ff-8a68-3b467c77216a.png"/> </div><br>
### 2. 与 ArrayList 的比较
@ -413,7 +413,7 @@ transient Entry[] table;
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
<div align="center"> <img src="pics/1d2719d5-8d60-4c9b-a4ad-b2df7c7615af.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1d2719d5-8d60-4c9b-a4ad-b2df7c7615af.jpg"/> </div><br>
```java
static class Entry<K,V> implements Map.Entry<K,V> {
@ -489,7 +489,7 @@ map.put("K3", "V3");
- 计算键值对所在的桶;
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
<div align="center"> <img src="pics/cf779e26-0382-4495-8463-f1e19e2e38a0.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cf779e26-0382-4495-8463-f1e19e2e38a0.jpg"/> </div><br>
### 3. put 操作
@ -825,7 +825,7 @@ final Segment<K,V>[] segments;
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
```
<div align="center"> <img src="pics/deb18bdb-b3b3-4660-b778-b0823a48db12.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/deb18bdb-b3b3-4660-b778-b0823a48db12.jpg"/> </div><br>
### 2. size 操作

View File

@ -61,7 +61,7 @@
# 一、线程状态转换
<div align="center"> <img src="pics/96706658-b3f8-4f32-8eb3-dcb7fc8d5381.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/96706658-b3f8-4f32-8eb3-dcb7fc8d5381.jpg"/> </div><br>
## 新建New
@ -736,7 +736,7 @@ java.util.concurrentJ.U.C大大提高了并发性能AQS 被认为是 J.
维护了一个计数器 cnt每次调用 countDown() 方法会让计数器的值减 1减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
<div align="center"> <img src="pics/912a7886-fb1d-4a05-902d-ab17ea17007f.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/912a7886-fb1d-4a05-902d-ab17ea17007f.jpg"/> </div><br>
```java
public class CountdownLatchExample {
@ -785,7 +785,7 @@ public CyclicBarrier(int parties) {
}
```
<div align="center"> <img src="pics/f944fac3-482b-4ca3-9447-17aec4a3cca0.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f944fac3-482b-4ca3-9447-17aec4a3cca0.png"/> </div><br>
```java
public class CyclicBarrierExample {
@ -1022,7 +1022,7 @@ public class ForkJoinPool extends AbstractExecutorService
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务避免和队列所属线程发生竞争。例如下图中Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
<div align="center"> <img src="pics/e19452dd-220a-4a6b-bcb0-91ad5e5c4706.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e19452dd-220a-4a6b-bcb0-91ad5e5c4706.png"/> </div><br>
# 九、线程不安全示例
@ -1077,19 +1077,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
<div align="center"> <img src="pics/d2a12961-2b36-4463-b017-ca46a3308b8e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d2a12961-2b36-4463-b017-ca46a3308b8e.png"/> </div><br>
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
<div align="center"> <img src="pics/8162aebb-8fd2-4620-b771-e65751ba7e41.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8162aebb-8fd2-4620-b771-e65751ba7e41.png"/> </div><br>
## 内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
<div align="center"> <img src="pics/b6a7e8af-91bf-44b2-8874-ccc6d9d52afc.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b6a7e8af-91bf-44b2-8874-ccc6d9d52afc.jpg"/> </div><br>
- read把一个变量的值从主内存传输到工作内存中
- load在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
@ -1112,11 +1112,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
下图演示了两个线程同时对 cnt 进行操作load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
<div align="center"> <img src="pics/847b9ba1-b3cd-4e52-aa72-dee0222ae09f.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/847b9ba1-b3cd-4e52-aa72-dee0222ae09f.jpg"/> </div><br>
AtomicInteger 能保证多个线程修改的原子性。
<div align="center"> <img src="pics/3144015c-dcfb-47ac-94a5-bab3b78b0f14.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3144015c-dcfb-47ac-94a5-bab3b78b0f14.jpg"/> </div><br>
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
@ -1224,7 +1224,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
在一个线程内,在程序前面的操作先行发生于后面的操作。
<div align="center"> <img src="pics/94414cd3-5db9-4aca-a2af-539140955c62.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/94414cd3-5db9-4aca-a2af-539140955c62.jpg"/> </div><br>
### 2. 管程锁定规则
@ -1232,7 +1232,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
<div align="center"> <img src="pics/de9d8133-4c98-4e07-b39c-302e162784ea.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/de9d8133-4c98-4e07-b39c-302e162784ea.jpg"/> </div><br>
### 3. volatile 变量规则
@ -1240,7 +1240,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
<div align="center"> <img src="pics/5e6e05d6-1028-4f5c-b9bd-1a40b90d6070.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5e6e05d6-1028-4f5c-b9bd-1a40b90d6070.jpg"/> </div><br>
### 4. 线程启动规则
@ -1248,7 +1248,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
<div align="center"> <img src="pics/bc5826f5-014d-47b4-9a76-d86b80968643.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bc5826f5-014d-47b4-9a76-d86b80968643.jpg"/> </div><br>
### 5. 线程加入规则
@ -1256,7 +1256,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
Thread 对象的结束先行发生于 join() 方法返回。
<div align="center"> <img src="pics/54e6d499-80df-488e-aa7e-081766c41538.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/54e6d499-80df-488e-aa7e-081766c41538.jpg"/> </div><br>
### 6. 线程中断规则
@ -1474,7 +1474,7 @@ public class ThreadLocalExample1 {
它所对应的底层结构图为:
<div align="center"> <img src="pics/066f9c11-0154-42c3-8685-301a70e9bd39.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/066f9c11-0154-42c3-8685-301a70e9bd39.jpg"/> </div><br>
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
@ -1577,17 +1577,17 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
<div align="center"> <img src="pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象包含了 Mark Word 和其它信息。
<div align="center"> <img src="pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
当尝试获取一个锁对象时,如果锁对象标记为 0 01说明锁对象的锁未锁定unlocked状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00表示该对象处于轻量级锁状态。
<div align="center"> <img src="pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
@ -1599,7 +1599,7 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
当有另外一个线程去尝试获取这个锁对象时偏向状态就宣告结束此时撤销偏向Revoke Bias后恢复到未锁定状态或者轻量级锁状态。
<div align="center"> <img src="pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
# 十三、多线程开发良好的实践

View File

@ -30,7 +30,7 @@
# 一、运行时数据区域
<div align="center"> <img src="pics/83e9c5ed-35a1-41fd-b0dd-ce571969b5f3_200.png" width="500px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/83e9c5ed-35a1-41fd-b0dd-ce571969b5f3_200.png" width="500px"> </div><br>
## 程序计数器
@ -40,7 +40,7 @@
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
<div align="center"> <img src="pics/ff5b89ac-798e-4fbc-b0ce-da2fc2358570.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ff5b89ac-798e-4fbc-b0ce-da2fc2358570.jpg"/> </div><br>
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
@ -59,7 +59,7 @@ java -Xss512M HackTheJava
本地方法一般是用其它语言C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
<div align="center"> <img src="pics/1_2001550547261811.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1_2001550547261811.png"/> </div><br>
## 堆
@ -137,7 +137,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收GC Roots 一般
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
<div align="center"> <img src="pics/6dd28bfc-6ef7-47cb-af50-a681ebc1bbaa.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6dd28bfc-6ef7-47cb-af50-a681ebc1bbaa.png"/> </div><br>
### 3. 方法区的回收
@ -217,7 +217,7 @@ obj = null;
### 1. 标记 - 清除
<div align="center"> <img src="pics/3_2001550547558008.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3_2001550547558008.png"/> </div><br>
标记要回收的对象,然后清除。
@ -230,14 +230,14 @@ obj = null;
### 2. 标记 - 整理
<div align="center"> <img src="pics/2_2001550547456403.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550547456403.png"/> </div><br>
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
### 3. 复制
<div align="center"> <img src="pics/4_2001550547640585.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4_2001550547640585.png"/> </div><br>
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
@ -258,7 +258,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1保证了内
## 垃圾收集器
<div align="center"> <img src="pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
@ -267,7 +267,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1保证了内
### 1. Serial 收集器
<div align="center"> <img src="pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
Serial 翻译为串行,也就是说它以串行的方式执行。
@ -279,7 +279,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 2. ParNew 收集器
<div align="center"> <img src="pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
它是 Serial 收集器的多线程版本。
@ -299,7 +299,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 4. Serial Old 收集器
<div align="center"> <img src="pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
是 Serial 收集器的老年代版本,也是给 Client 场景下的虚拟机使用。如果用在 Server 场景下,它有两大用途:
@ -308,7 +308,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 5. Parallel Old 收集器
<div align="center"> <img src="pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
是 Parallel Scavenge 收集器的老年代版本。
@ -316,7 +316,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 6. CMS 收集器
<div align="center"> <img src="pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
CMSConcurrent Mark SweepMark Sweep 指的是标记 - 清除算法。
@ -341,17 +341,17 @@ G1Garbage-First它是一款面向服务端应用的垃圾收集器
堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
<div align="center"> <img src="pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
G1 把堆划分成多个大小相等的独立区域Region新生代和老年代不再物理隔离。
<div align="center"> <img src="pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
每个 Region 都有一个 Remembered Set用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set在做可达性分析的时候就可以避免全堆扫描。
<div align="center"> <img src="pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
如果不计算维护 Remembered Set 的操作G1 收集器的运作大致可划分为以下几个步骤:
@ -439,7 +439,7 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
## 类的生命周期
<div align="center"> <img src="pics/303873db-0d11-4683-a43c-f319b7aef2b6.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/303873db-0d11-4683-a43c-f319b7aef2b6.jpg"/> </div><br>
包括以下 7 个阶段:
@ -614,7 +614,7 @@ System.out.println(ConstClass.HELLOWORLD);
下图展示了类加载器之间的层次关系称为双亲委派模型Parents Delegation Model。该模型要求除了顶层的启动类加载器外其它的类加载器都要有自己的父类加载器。类加载器之间的父子关系一般通过组合关系Composition来实现而不是继承关系Inheritance
<div align="center"> <img src="pics/805812fa-6ab5-4b8f-a0aa-3bdcadaa829d.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/805812fa-6ab5-4b8f-a0aa-3bdcadaa829d.png"/> </div><br>
### 1. 工作过程

View File

@ -59,7 +59,7 @@
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=dp[i-1]+dp[i-2]"/></div> <br>-->
<div align="center"> <img src="pics/14fe1e71-8518-458f-a220-116003061a83.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/14fe1e71-8518-458f-a220-116003061a83.png"/> </div><br>
考虑到 dp[i] 只与 dp[i - 1] 和 dp[i - 2] 有关,因此可以只用两个变量来存储 dp[i - 1] 和 dp[i - 2],使得原来的 O(N) 空间复杂度优化为 O(1) 复杂度。
@ -91,7 +91,7 @@ public int climbStairs(int n) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=max(dp[i-2]+nums[i],dp[i-1])"/></div> <br>-->
<div align="center"> <img src="pics/2de794ca-aa7b-48f3-a556-a0e2708cb976.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2de794ca-aa7b-48f3-a556-a0e2708cb976.jpg"/> </div><br>
```java
public int rob(int[] nums) {
@ -145,7 +145,7 @@ private int rob(int[] nums, int first, int last) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=(i-1)*dp[i-2]+(i-1)*dp[i-1]"/></div> <br>-->
<div align="center"> <img src="pics/da1f96b9-fd4d-44ca-8925-fb14c5733388.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/da1f96b9-fd4d-44ca-8925-fb14c5733388.png"/> </div><br>
## 母牛生产
@ -157,7 +157,7 @@ private int rob(int[] nums, int first, int last) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=dp[i-1]+dp[i-3]"/></div> <br>-->
<div align="center"> <img src="pics/879814ee-48b5-4bcb-86f5-dcc400cb81ad.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/879814ee-48b5-4bcb-86f5-dcc400cb81ad.png"/> </div><br>
# 矩阵路径
@ -203,7 +203,7 @@ public int minPathSum(int[][] grid) {
题目描述:统计从矩阵左上角到右下角的路径总数,每次只能向右或者向下移动。
<div align="center"> <img src="pics/dc82f0f3-c1d4-4ac8-90ac-d5b32a9bd75a.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/dc82f0f3-c1d4-4ac8-90ac-d5b32a9bd75a.jpg"/> </div><br>
```java
public int uniquePaths(int m, int n) {
@ -400,7 +400,7 @@ public int numDecodings(String s) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[n]=max\{1,dp[i]+1|S_i<S_n\&\&i<n\}"/></div> <br>-->
<div align="center"> <img src="pics/ee994da4-0fc7-443d-ac56-c08caf00a204.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ee994da4-0fc7-443d-ac56-c08caf00a204.jpg"/> </div><br>
对于一个长度为 N 的序列,最长递增子序列并不一定会以 S<sub>N</sub> 为结尾,因此 dp[N] 不是序列的最长递增子序列的长度,需要遍历 dp 数组找出最大值才是所要的结果max{ dp[i] | 1 <= i <= N} 即为所求。
@ -567,7 +567,7 @@ public int wiggleMaxLength(int[] nums) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i][j]=\left\{\begin{array}{rcl}dp[i-1][j-1]&&{S1_i==S2_j}\\max(dp[i-1][j],dp[i][j-1])&&{S1_i<>S2_j}\end{array}\right."/></div> <br>-->
<div align="center"> <img src="pics/ecd89a22-c075-4716-8423-e0ba89230e9a.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ecd89a22-c075-4716-8423-e0ba89230e9a.jpg"/> </div><br>
对于长度为 N 的序列 S<sub>1</sub> 和长度为 M 的序列 S<sub>2</sub>dp[N][M] 就是序列 S<sub>1</sub> 和序列 S<sub>2</sub> 的最长公共子序列长度。
@ -607,7 +607,7 @@ public int lengthOfLCS(int[] nums1, int[] nums2) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i][j]=max(dp[i-1][j],dp[i-1][j-w]+v)"/></div> <br>-->
<div align="center"> <img src="pics/8cb2be66-3d47-41ba-b55b-319fc68940d4.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8cb2be66-3d47-41ba-b55b-319fc68940d4.png"/> </div><br>
```java
public int knapsack(int W, int N, int[] weights, int[] values) {
@ -632,7 +632,7 @@ public int knapsack(int W, int N, int[] weights, int[] values) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[j]=max(dp[j],dp[j-w]+v)"/></div> <br>-->
<div align="center"> <img src="pics/9ae89f16-7905-4a6f-88a2-874b4cac91f4.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9ae89f16-7905-4a6f-88a2-874b4cac91f4.jpg"/> </div><br>
因为 dp[j-w] 表示 dp[i-1][j-w],因此不能先求 dp[i][j-w],以防将 dp[i-1][j-w] 覆盖。也就是说要先计算 dp[i][j] 再计算 dp[i][j-w],在程序实现时需要按倒序来循环求解。
@ -976,7 +976,7 @@ public int combinationSum4(int[] nums, int target) {
题目描述:交易之后需要有一天的冷却时间。
<div align="center"> <img src="pics/c847d6e4-3610-4f3c-a909-89a5048426e6.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c847d6e4-3610-4f3c-a909-89a5048426e6.png"/> </div><br>
```java
public int maxProfit(int[] prices) {
@ -1017,7 +1017,7 @@ The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
题目描述:每交易一次,都要支付一定的费用。
<div align="center"> <img src="pics/79e9a938-43e2-4c5a-8de9-fe55522a14c9.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/79e9a938-43e2-4c5a-8de9-fe55522a14c9.png"/> </div><br>
```java
public int maxProfit(int[] prices, int fee) {

View File

@ -191,7 +191,7 @@ public String frequencySort(String s) {
它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。
<div align="center"> <img src="pics/7a3215ec-6fb7-4935-8b0d-cb408208f7cb.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7a3215ec-6fb7-4935-8b0d-cb408208f7cb.png"/> </div><br>
## 按颜色进行排序

View File

@ -32,7 +32,7 @@
# BFS
<div align="center"> <img src="pics/95903878-725b-4ed9-bded-bc4aae0792a9.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/95903878-725b-4ed9-bded-bc4aae0792a9.jpg"/> </div><br>
广度优先搜索一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。
@ -261,7 +261,7 @@ private int getShortestPath(List<Integer>[] graphic, int start, int end) {
# DFS
<div align="center"> <img src="pics/74dc31eb-6baa-47ea-ab1c-d27a0ca35093.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/74dc31eb-6baa-47ea-ab1c-d27a0ca35093.png"/> </div><br>
广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历。
@ -572,7 +572,7 @@ Backtracking回溯属于 DFS。
[17. Letter Combinations of a Phone Number (Medium)](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/)
<div align="center"> <img src="pics/9823768c-212b-4b1a-b69a-b3f59e07b977.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9823768c-212b-4b1a-b69a-b3f59e07b977.jpg"/> </div><br>
```html
Input:Digit string "23"
@ -1149,7 +1149,7 @@ private boolean isPalindrome(String s, int begin, int end) {
[37. Sudoku Solver (Hard)](https://leetcode.com/problems/sudoku-solver/description/)
<div align="center"> <img src="pics/0e8fdc96-83c1-4798-9abe-45fc91d70b9d.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0e8fdc96-83c1-4798-9abe-45fc91d70b9d.png"/> </div><br>
```java
private boolean[][] rowsUsed = new boolean[9][10];
@ -1206,7 +1206,7 @@ private int cubeNum(int i, int j) {
[51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/)
<div align="center"> <img src="pics/067b310c-6877-40fe-9dcf-10654e737485.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/067b310c-6877-40fe-9dcf-10654e737485.jpg"/> </div><br>
在 n\*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,求所有的 n 皇后的解。
@ -1214,11 +1214,11 @@ private int cubeNum(int i, int j) {
45 度对角线标记数组的长度为 2 \* n - 1通过下图可以明确 (r, c) 的位置所在的数组下标为 r + c。
<div align="center"> <img src="pics/6646db4a-7f43-45e4-96ff-0891a57a9ade.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6646db4a-7f43-45e4-96ff-0891a57a9ade.jpg"/> </div><br>
135 度对角线标记数组的长度也是 2 \* n - 1(r, c) 的位置所在的数组下标为 n - 1 - (r - c)。
<div align="center"> <img src="pics/f1ff65ed-bbc2-4b92-8a94-7c5c0874da0f.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f1ff65ed-bbc2-4b92-8a94-7c5c0874da0f.jpg"/> </div><br>
```java
private List<List<String>> solutions;

View File

@ -987,7 +987,7 @@ private void inOrder(TreeNode node, List<Integer> nums) {
# Trie
<div align="center"> <img src="pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
Trie又称前缀树或字典树用于判断字符串是否存在或者是否具有某种字符串前缀。

View File

@ -157,7 +157,7 @@ Linux 发行版是 Linux 内核及各种应用软件的集成版本。
- 编辑模式Insert mode按下 "i" 等按键之后进入,可以对文本进行编辑;
- 指令列模式Bottom-line mode按下 ":" 按键之后进入,用于保存退出等操作。
<div align="center"> <img src="pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
在指令列模式下,有以下命令用于离开或者保存文件。
@ -191,25 +191,25 @@ GNU 计划,译为革奴计划,它的目标是创建一套完全自由的操
IDEATA全称 Advanced Technology Attachment接口速度最大为 133MB/s因为并口线的抗干扰性太差且排线占用空间较大不利电脑内部散热已逐渐被 SATA 所取代。
<div align="center"> <img src="pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
### 2. SATA
SATA 全称 Serial ATA也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多支持热插拔等功能。SATA-II 的接口速度为 300MiB/s而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。
<div align="center"> <img src="pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
### 3. SCSI
SCSI 全称是 Small Computer System Interface小型机系统接口经历多代的发展从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel光纤通道接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。
<div align="center"> <img src="pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
### 4. SAS
SASSerial Attached SCSI是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。
<div align="center"> <img src="pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
## 磁盘的文件名
@ -244,7 +244,7 @@ GPT 没有扩展分区概念,都是主分区,每个 LAB 可以分 4 个分
MBR 不支持 2.2 TB 以上的硬盘GPT 则最多支持到 2<sup>33</sup> TB = 8 ZB。
<div align="center"> <img src="pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
## 开机检测程序
@ -252,7 +252,7 @@ MBR 不支持 2.2 TB 以上的硬盘GPT 则最多支持到 2<sup>33</sup> TB
BIOSBasic Input/Output System基本输入输出系统它是一个固件嵌入在硬件中的软件BIOS 程序存放在断电后内容不会丢失的只读内存中。
<div align="center"> <img src="pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
BIOS 是开机的时候计算机执行的第一个程序这个程序知道可以开机的磁盘并读取磁盘第一个扇区的主要开机记录MBR由主要开机记录MBR执行其中的开机管理程序这个开机管理程序会加载操作系统的核心文件。
@ -260,7 +260,7 @@ BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可
下图中第一扇区的主要开机记录MBR中的开机管理程序提供了两个选单M1、M2M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。
<div align="center"> <img src="pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录MBR而 Linux 可以选择将开机管理程序安装在主要开机记录MBR或者其它分区的启动扇区并且可以设置开机管理程序的选单。
@ -286,17 +286,17 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。
- superblock记录文件系统的整体信息包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
- block bitmap记录 block 是否被使用的位域。
<div align="center"> <img src="pics/BSD_disk.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/BSD_disk.png" width="800"/> </div><br>
## 文件读取
对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block然后把所有 block 的内容读出来。
<div align="center"> <img src="pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
而对于 FAT 文件系统,它没有 inode每个 block 中存储着下一个 block 的编号。
<div align="center"> <img src="pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
## 磁盘碎片
@ -333,7 +333,7 @@ inode 具有以下特点:
inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。
<div align="center"> <img src="pics/inode_with_signatures.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/inode_with_signatures.jpg" width="600"/> </div><br>
## 目录
@ -359,7 +359,7 @@ ext3/ext4 文件系统引入了日志功能,可以利用日志来修复文件
- /usr (unix software resource):所有系统默认软件都会安装到这个目录;
- /var (variable):存放系统或程序运行过程中的数据文件。
<div align="center"> <img src="pics/linux-filesystem.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/linux-filesystem.png" width=""/> </div><br>
# 五、文件
@ -534,7 +534,7 @@ cp [-adfilprsu] source destination
-f :如果目标文件存在时,先删除目标文件
```
<div align="center"> <img src="pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg" width="400px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg" width="400px"> </div><br>
### 1. 实体链接
@ -655,7 +655,7 @@ example: find . -name "shadow*"
+4、4 和 -4 的指示的时间范围如下:
<div align="center"> <img src="pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
**② 与文件拥有者和所属群组有关的选项**
@ -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) |
<br>
<div align="center"> <img src="pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
## SIGCHLD
@ -1181,7 +1181,7 @@ dmtsai lines: 5 columns: 9
在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
<div align="center"> <img src="pics/flow.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/flow.png" width=""/> </div><br>
## wait()

View File

@ -42,7 +42,7 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null则该指针指向节点的所有 key 大于等于 key<sub>i</sub> 且小于等于 key<sub>i+1</sub>
<div align="center"> <img src="pics/10a6d3ee-04b2-46b4-b171-d596e5ab0f84.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/10a6d3ee-04b2-46b4-b171-d596e5ab0f84.jpg"/> </div><br>
### 2. 操作
@ -84,11 +84,11 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
<div align="center"> <img src="pics/4f151e62-6160-47f1-9eff-47b1f4dea4e9.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4f151e62-6160-47f1-9eff-47b1f4dea4e9.jpg"/> </div><br>
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
<div align="center"> <img src="pics/40f29839-fd56-4ed0-9353-39dfe6f0bba5.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/40f29839-fd56-4ed0-9353-39dfe6f0bba5.jpg"/> </div><br>
### 2. 哈希索引
@ -350,7 +350,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
当一个表的数据不断增多时Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
<div align="center"> <img src="pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
## 垂直切分
@ -358,7 +358,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
<div align="center"> <img src="pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
## Sharding 策略
@ -392,7 +392,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
- **I/O 线程** 负责从主服务器上读取二进制日志并写入从服务器的中继日志Relay log
- **SQL 线程** :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中执行。
<div align="center"> <img src="pics/master-slave.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/master-slave.png"/> </div><br>
## 读写分离
@ -406,7 +406,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
<div align="center"> <img src="pics/master-slave-proxy.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/master-slave-proxy.png"/> </div><br>
# 参考资料

View File

@ -67,7 +67,7 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
## STRING
<div align="center"> <img src="pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
```html
> set hello world
@ -82,7 +82,7 @@ OK
## LIST
<div align="center"> <img src="pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
```html
> rpush list-key item
@ -110,7 +110,7 @@ OK
## SET
<div align="center"> <img src="pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
```html
> sadd set-key item
@ -144,7 +144,7 @@ OK
## HASH
<div align="center"> <img src="pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
```html
> hset hash-key sub-key1 value1
@ -175,7 +175,7 @@ OK
## ZSET
<div align="center"> <img src="pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
```html
> zadd zset-key 728 member1
@ -317,11 +317,11 @@ int dictRehash(dict *d, int n) {
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
<div align="center"> <img src="pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png" width="600px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png" width="600px"/> </div><br>
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
<div align="center"> <img src="pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png" width="600px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png" width="600px"/> </div><br>
与红黑树等平衡树相比,跳跃表具有以下优点:
@ -472,7 +472,7 @@ Redis 服务器是一个事件驱动程序。
Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。
<div align="center"> <img src="pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png" width=""/> </div><br>
## 时间事件
@ -525,7 +525,7 @@ def main():
从事件处理的角度来看,服务器运行流程如下:
<div align="center"> <img src="pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="350"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="350"/> </div><br>
# 十一、复制
@ -545,7 +545,7 @@ def main():
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
<div align="center"> <img src="pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
# 十二、Sentinel
@ -580,7 +580,7 @@ Sentinel哨兵可以监听集群中的服务器并在主服务器进入
Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617其中 article 为命名空间ID 为 92617。
<div align="center"> <img src="pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
## 点赞功能
@ -588,13 +588,13 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。
<div align="center"> <img src="pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
## 对文章进行排序
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
<div align="center"> <img src="pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
# 参考资料

View File

@ -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);
```
<div align="center"> <img src="pics/1492928416812_4.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492928416812_4.png"/> </div><br>
## 非阻塞式 I/O
@ -54,7 +54,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。
<div align="center"> <img src="pics/1492929000361_5.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929000361_5.png"/> </div><br>
## 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 复用不需要进程线程创建和切换的开销,系统开销更小。
<div align="center"> <img src="pics/1492929444818_6.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929444818_6.png"/> </div><br>
## 信号驱动 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 利用率更高。
<div align="center"> <img src="pics/1492929553651_7.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929553651_7.png"/> </div><br>
## 异步 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。
<div align="center"> <img src="pics/1492930243286_8.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492930243286_8.png"/> </div><br>
## 五大 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 在第一阶段不会阻塞。
<div align="center"> <img src="pics/1492928105791_3.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492928105791_3.png"/> </div><br>
# 二、I/O 复用

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -48,11 +48,11 @@
- 用 min、max 表示数量范围;
- 用 first、last 表示访问空间的包含范围;
<div align="center"> <img src="pics/a6ebcd0a-a44d-48c8-b29a-dfacece83301.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a6ebcd0a-a44d-48c8-b29a-dfacece83301.png"/> </div><br>
- begin、end 表示访问空间的排除范围,即 end 不包含尾部。
<div align="center"> <img src="pics/3fa0a6cb-a0a4-490a-9a80-7f4888f2500c.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3fa0a6cb-a0a4-490a-9a80-7f4888f2500c.png"/> </div><br>
# 四、良好的代码风格

View File

@ -70,7 +70,7 @@ EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了
Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父节点为 /app1。
<div align="center"> <img src="pics/b3a421e3-41b4-4e99-b612-bc695a7f622f.jpg" width="400px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b3a421e3-41b4-4e99-b612-bc695a7f622f.jpg" width="400px"> </div><br>
### 2. 节点类型
@ -111,7 +111,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
2. 之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。
3. 在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。
<div align="center"> <img src="pics/76c7597a-8316-460d-b8fb-9752c4c43947.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/76c7597a-8316-460d-b8fb-9752c4c43947.jpg"/> </div><br>
## 2PC
@ -123,7 +123,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
协调者询问参与者事务是否执行成功,参与者发回事务执行结果。
<div align="center"> <img src="pics/963fac12-4eac-4922-8a5f-f262c11f80fb.jpg" width="700px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/963fac12-4eac-4922-8a5f-f262c11f80fb.jpg" width="700px"> </div><br>
#### 1.2 提交阶段
@ -131,7 +131,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。
<div align="center"> <img src="pics/9ffb82ad-9b7f-44df-b93f-fc8b3f4093a6.jpg" width="700px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9ffb82ad-9b7f-44df-b93f-fc8b3f4093a6.jpg" width="700px"> </div><br>
### 2. 存在的问题
@ -155,7 +155,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
分布式系统不可能同时满足一致性CConsistency、可用性AAvailability和分区容忍性PPartition Tolerance最多只能同时满足其中两项。
<div align="center"> <img src="pics/c6fdb958-578d-4685-a5fa-400857be91d5.jpg" width="500px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c6fdb958-578d-4685-a5fa-400857be91d5.jpg" width="500px"> </div><br>
## 一致性
@ -184,7 +184,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
- 为了保证一致性CP不能访问未同步完成的节点也就失去了部分可用性
- 为了保证可用性AP允许读取所有节点的数据但是数据可能不一致。
<div align="center"> <img src="pics/0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg"/> </div><br>
# 四、BASE
@ -221,7 +221,7 @@ ACID 要求强一致性,通常运用在传统的数据库系统上。而 BASE
- 接受者Acceptor对每个提议进行投票
- 告知者Learner被告知投票的结果不参与投票过程。
<div align="center"> <img src="pics/b988877c-0f0a-4593-916d-de2081320628.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b988877c-0f0a-4593-916d-de2081320628.jpg"/> </div><br>
## 执行过程
@ -231,19 +231,19 @@ ACID 要求强一致性,通常运用在传统的数据库系统上。而 BASE
下图演示了两个 Proposer 和三个 Acceptor 的系统中运行该算法的初始过程,每个 Proposer 都会向所有 Acceptor 发送 Prepare 请求。
<div align="center"> <img src="pics/1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png"/> </div><br>
当 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 类似。
<div align="center"> <img src="pics/fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg"/> </div><br>
如果 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 类似。
<div align="center"> <img src="pics/2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg"/> </div><br>
### 2. Accept 阶段
@ -253,13 +253,13 @@ Proposer A 接收到两个 Prepare 响应之后,就发送 [n=2, v=8] Accept
Proposer B 过后也收到了两个 Prepare 响应,因此也开始发送 Accept 请求。需要注意的是Accept 请求的 v 需要取它收到的最大提议编号对应的 v 值,也就是 8。因此它发送 [n=4, v=8] 的 Accept 请求。
<div align="center"> <img src="pics/9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png"/> </div><br>
### 3. Learn 阶段
Acceptor 接收到 Accept 请求时,如果序号大于等于该 Acceptor 承诺的最小序号,那么就发送 Learn 提议给所有的 Learner。当 Learner 发现有大多数的 Acceptor 接收了某个提议,那么该提议的提议值就被 Paxos 选择出来。
<div align="center"> <img src="pics/bf667594-bb4b-4634-bf9b-0596a45415ba.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bf667594-bb4b-4634-bf9b-0596a45415ba.jpg"/> </div><br>
## 约束条件
@ -285,47 +285,47 @@ Raft 也是分布式一致性协议,主要是用来竞选主节点。
- 下图展示一个分布式系统的最初阶段,此时只有 Follower 没有 Leader。Node A 等待一个随机的竞选超时时间之后,没收到 Leader 发来的心跳包,因此进入竞选阶段。
<div align="center"> <img src="pics/111521118015898.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111521118015898.gif"/> </div><br>
- 此时 Node A 发送投票请求给其它所有节点。
<div align="center"> <img src="pics/111521118445538.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111521118445538.gif"/> </div><br>
- 其它节点会对请求进行回复,如果超过一半的节点回复了,那么该 Candidate 就会变成 Leader。
<div align="center"> <img src="pics/111521118483039.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111521118483039.gif"/> </div><br>
- 之后 Leader 会周期性地发送心跳包给 FollowerFollower 接收到心跳包,会重新开始计时。
<div align="center"> <img src="pics/111521118640738.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111521118640738.gif"/> </div><br>
## 多个 Candidate 竞选
- 如果有多个 Follower 成为 Candidate并且所获得票数相同那么就需要重新开始投票。例如下图中 Node B 和 Node D 都获得两票,需要重新开始投票。
<div align="center"> <img src="pics/111521119203347.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111521119203347.gif"/> </div><br>
- 由于每个节点设置的随机竞选超时时间不同,因此下一次再次出现多个 Candidate 并获得同样票数的概率很低。
<div align="center"> <img src="pics/111521119368714.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111521119368714.gif"/> </div><br>
## 数据同步
- 来自客户端的修改都会被传入 Leader。注意该修改还未被提交只是写入日志中。
<div align="center"> <img src="pics/71550414107576.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/71550414107576.gif"/> </div><br>
- Leader 会把修改复制到所有 Follower。
<div align="center"> <img src="pics/91550414131331.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/91550414131331.gif"/> </div><br>
- Leader 会等待大多数的 Follower 也进行了修改,然后才将修改提交。
<div align="center"> <img src="pics/101550414151983.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/101550414151983.gif"/> </div><br>
- 此时 Leader 会通知的所有 Follower 让它们也提交修改,此时所有节点的值达成一致。
<div align="center"> <img src="pics/111550414182638.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111550414182638.gif"/> </div><br>
# 参考

View File

@ -58,13 +58,13 @@
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?f(n)=\left\{\begin{array}{rcl}0&&{n=0}\\1&&{n=1}\\f(n-1)+f(n-2)&&{n>1}\end{array}\right."/></div> <br> -->
<div align="center"> <img src="pics/45be9587-6069-4ab7-b9ac-840db1a53744.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/45be9587-6069-4ab7-b9ac-840db1a53744.jpg"/> </div><br>
## 解题思路
如果使用递归求解,会重复计算一些子问题。例如,计算 f(10) 需要计算 f(9) 和 f(8),计算 f(9) 需要计算 f(8) 和 f(7),可以看到 f(8) 被重复计算了。
<div align="center"> <img src="pics/_u6590_u6CE2_u90A3_u5951_u6570_u5217.gif" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u6590_u6CE2_u90A3_u5951_u6570_u5217.gif" width="400"/> </div><br>
递归是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。
@ -126,7 +126,7 @@ public class Solution {
我们可以用 2\*1 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 2\*1 的小矩形无重叠地覆盖一个 2\*n 的大矩形,总共有多少种方法?
<div align="center"> <img src="pics/d1ed87eb-da5a-4728-b0dc-e3705aa028ea.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d1ed87eb-da5a-4728-b0dc-e3705aa028ea.gif"/> </div><br>
## 解题思路
@ -153,7 +153,7 @@ public int RectCover(int n) {
一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
<div align="center"> <img src="pics/a0e90bd3-747d-4c3a-8fa0-179c59eeded0_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a0e90bd3-747d-4c3a-8fa0-179c59eeded0_200.png"/> </div><br>
## 解题思路
@ -180,7 +180,7 @@ public int JumpFloor(int n) {
一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级... 它也可以跳上 n 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
<div align="center"> <img src="pics/cbd5f6f6-18de-4711-9e01-0f94e66f81b8_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cbd5f6f6-18de-4711-9e01-0f94e66f81b8_200.png"/> </div><br>
## 解题思路
@ -304,7 +304,7 @@ private int minNumber(int[] nums, int l, int h) {
例如下面的矩阵包含了一条 bfce 路径。
<div align="center"> <img src="pics/2_2001550466182933.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550466182933.png"/> </div><br>
## 解题思路
@ -514,7 +514,7 @@ public int NumberOf1(int n) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?x^n=\left\{\begin{array}{rcl}(x*x)^{n/2}&&{n\%2=0}\\x*(x*x)^{n/2}&&{n\%2=1}\end{array}\right."/></div> <br>-->
<div align="center"> <img src="pics/48b1d459-8832-4e92-938a-728aae730739.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/48b1d459-8832-4e92-938a-728aae730739.jpg"/> </div><br>
因为 (x\*x)<sup>n/2</sup> 可以通过递归求解,并且每次递归 n 都减小一半,因此整个算法的时间复杂度为 O(logN)。
@ -583,13 +583,13 @@ private void printNumber(char[] number) {
① 如果该节点不是尾节点,那么可以直接将下一个节点的值赋给该节点,然后令该节点指向下下个节点,再删除下一个节点,时间复杂度为 O(1)。
<div align="center"> <img src="pics/27ff9548-edb6-4465-92c8-7e6386e0b185.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/27ff9548-edb6-4465-92c8-7e6386e0b185.png" width="600"/> </div><br>
② 如果链表只有一个节点,那么直接
② 否则,就需要先遍历链表,找到节点的前一个节点,然后让前一个节点指向 null时间复杂度为 O(N)。
<div align="center"> <img src="pics/280f7728-594f-4811-a03a-fa8d32c013da.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/280f7728-594f-4811-a03a-fa8d32c013da.png" width="600"/> </div><br>
综上,如果进行 N 次操作,那么大约需要操作节点的次数为 N-1+N=2N-1其中 N-1 表示 N-1 个不是尾节点的每个节点以 O(1) 的时间复杂度操作节点的总次数N 表示 1 个尾节点以 O(N) 的时间复杂度操作节点的总次数。(2N-1)/N \~ 2因此该算法的平均时间复杂度为 O(1)。
@ -623,7 +623,7 @@ public ListNode deleteNode(ListNode head, ListNode tobeDelete) {
## 题目描述
<div align="center"> <img src="pics/8433fbb2-c35c-45ef-831d-e3ca42aebd51.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8433fbb2-c35c-45ef-831d-e3ca42aebd51.png" width="500"/> </div><br>
## 解题描述

View File

@ -90,7 +90,7 @@ public boolean isNumeric(char[] str) {
需要保证奇数和奇数,偶数和偶数之间的相对位置不变,这和书本不太一样。
<div align="center"> <img src="pics/7_2001550475133282.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7_2001550475133282.png"/> </div><br>
## 解题思路
@ -120,7 +120,7 @@ public void reOrderArray(int[] nums) {
设链表的长度为 N。设两个指针 P1 和 P2先让 P1 移动 K 个节点,则还有 N - K 个节点可以移动。此时让 P1 和 P2 同时移动,可以知道当 P1 移动到链表结尾时P2 移动到 N - K 个节点处,该位置就是倒数第 K 个节点。
<div align="center"> <img src="pics/ea2304ce-268b-4238-9486-4d8f8aea8ca4.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ea2304ce-268b-4238-9486-4d8f8aea8ca4.png" width="500"/> </div><br>
```java
public ListNode FindKthToTail(ListNode head, int k) {
@ -154,7 +154,7 @@ public ListNode FindKthToTail(ListNode head, int k) {
在相遇点slow 要到环的入口点还需要移动 z 个节点,如果让 fast 重新从头开始移动,并且速度变为每次移动一个节点,那么它到环入口点还需要移动 x 个节点。在上面已经推导出 x=z因此 fast 和 slow 将在环入口点相遇。
<div align="center"> <img src="pics/d5d3b7ae-2712-412e-98f1-633ce6ec5955.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d5d3b7ae-2712-412e-98f1-633ce6ec5955.png" width="500"/> </div><br>
```java
@ -216,7 +216,7 @@ public ListNode ReverseList(ListNode head) {
## 题目描述
<div align="center"> <img src="pics/43f2cafa-3568-4a89-a895-4725666b94a6.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/43f2cafa-3568-4a89-a895-4725666b94a6.png" width="500"/> </div><br>
## 解题思路
@ -268,7 +268,7 @@ public ListNode Merge(ListNode list1, ListNode list2) {
## 题目描述
<div align="center"> <img src="pics/4583e24f-424b-4d50-8a14-2c38a1827d4a.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4583e24f-424b-4d50-8a14-2c38a1827d4a.png" width="500"/> </div><br>
## 解题思路
@ -296,7 +296,7 @@ private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) {
## 题目描述
<div align="center"> <img src="pics/a2d13178-f1ef-4811-a240-1fe95b55b1eb.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a2d13178-f1ef-4811-a240-1fe95b55b1eb.png" width="300"/> </div><br>
## 解题思路
@ -322,7 +322,7 @@ private void swap(TreeNode root) {
## 题目描述
<div align="center"> <img src="pics/f42443e0-208d-41ea-be44-c7fd97d2e3bf.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f42443e0-208d-41ea-be44-c7fd97d2e3bf.png" width="300"/> </div><br>
## 解题思路
@ -352,7 +352,7 @@ boolean isSymmetrical(TreeNode t1, TreeNode t2) {
下图的矩阵顺时针打印结果为1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10
<div align="center"> <img src="pics/8_2001550475451664.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8_2001550475451664.png"/> </div><br>
## 解题思路

View File

@ -110,7 +110,7 @@ public boolean IsPopOrder(int[] pushSequence, int[] popSequence) {
例如以下二叉树层次遍历的结果为1,2,3,4,5,6,7
<div align="center"> <img src="pics/348bc2db-582e-4aca-9f88-38c40e9a0e69.png" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/348bc2db-582e-4aca-9f88-38c40e9a0e69.png" width="250"/> </div><br>
## 解题思路
@ -218,7 +218,7 @@ public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
例如,下图是后序遍历序列 1,3,2 所对应的二叉搜索树。
<div align="center"> <img src="pics/836a4eaf-4798-4e48-b52a-a3dab9435ace.png" width="150"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/836a4eaf-4798-4e48-b52a-a3dab9435ace.png" width="150"/> </div><br>
## 解题思路
@ -253,7 +253,7 @@ private boolean verify(int[] sequence, int first, int last) {
下图的二叉树有两条和为 22 的路径10, 5, 7 和 10, 12
<div align="center"> <img src="pics/f5477abd-c246-4851-89ab-6b1cde2549b1.png" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f5477abd-c246-4851-89ab-6b1cde2549b1.png" width="200"/> </div><br>
## 解题思路
@ -300,21 +300,21 @@ public class RandomListNode {
}
```
<div align="center"> <img src="pics/a01d1516-8168-461a-a24b-620b9cfc40f4.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a01d1516-8168-461a-a24b-620b9cfc40f4.png" width="300"/> </div><br>
## 解题思路
第一步,在每个节点的后面插入复制的节点。
<div align="center"> <img src="pics/2e6c72f5-3b8e-4e32-b87b-9491322628fe.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2e6c72f5-3b8e-4e32-b87b-9491322628fe.png" width="600"/> </div><br>
第二步,对复制节点的 random 链接进行赋值。
<div align="center"> <img src="pics/323ffd6c-8b54-4f3e-b361-555a6c8bf218.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/323ffd6c-8b54-4f3e-b361-555a6c8bf218.png" width="600"/> </div><br>
第三步,拆分。
<div align="center"> <img src="pics/8f3b9519-d705-48fe-87ad-2e4052fc81d2.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8f3b9519-d705-48fe-87ad-2e4052fc81d2.png" width="600"/> </div><br>
```java
public RandomListNode Clone(RandomListNode pHead) {
@ -356,7 +356,7 @@ public RandomListNode Clone(RandomListNode pHead) {
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
<div align="center"> <img src="pics/79b12431-6d9d-4a7d-985b-1b79bc5bf5fb.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/79b12431-6d9d-4a7d-985b-1b79bc5bf5fb.png" width="400"/> </div><br>
## 解题思路

View File

@ -50,7 +50,7 @@ Output:
以 (2, 3, 1, 0, 2, 5) 为例,遍历到位置 4 时,该位置上的数为 2但是第 2 个位置上已经有一个 2 的值了,因此可以知道 2 重复:
<div align="center"> <img src="pics/_u6570_u7EC4_u4E2D_u91CD_u590D_1548260392361.gif" width="250px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u6570_u7EC4_u4E2D_u91CD_u590D_1548260392361.gif" width="250px"> </div><br>
```java
public boolean duplicate(int[] nums, int length, int[] duplication) {
@ -103,7 +103,7 @@ Given target = 20, return false.
该二维数组中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间,当前元素的查找区间为左下角的所有元素。
<div align="center"> <img src="pics/_u4E8C_u7EF4_u6570_u7EC4_u4E2D_.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4E8C_u7EF4_u6570_u7EC4_u4E2D_.gif"/> </div><br>
```java
public boolean Find(int target, int[][] matrix) {
@ -148,7 +148,7 @@ Output:
从后向前遍是为了在改变 P2 所指向的内容时,不会影响到 P1 遍历原来字符串的内容。
<div align="center"> <img src="pics/_u66FF_u6362_u7A7A_u683C.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u66FF_u6362_u7A7A_u683C.gif"/> </div><br>
```java
public String replaceSpace(StringBuffer str) {
@ -180,13 +180,13 @@ public String replaceSpace(StringBuffer str) {
从尾到头反过来打印出每个结点的值。
<div align="center"> <img src="pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548293972480.gif" width="250px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548293972480.gif" width="250px"> </div><br>
## 解题思路
### 使用递归
<div align="center"> <img src="pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548296249372.gif" width="200px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548296249372.gif" width="200px"> </div><br>
```java
@ -210,7 +210,7 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
- 第一个节点就是链表的第一个真正存储值的节点。
<div align="center"> <img src="pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548295232667.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548295232667.gif"/> </div><br>
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
@ -235,7 +235,7 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
### 使用栈
<div align="center"> <img src="pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548503461113.gif" width="500px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4ECE_u5C3E_u5230_u5934_u6253_1548503461113.gif" width="500px"> </div><br>
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
@ -264,13 +264,13 @@ preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
```
<div align="center"> <img src="pics/_u91CD_u5EFA_u4E8C_u53C9_u6811-1.gif" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u91CD_u5EFA_u4E8C_u53C9_u6811-1.gif" width="200"/> </div><br>
## 解题思路
前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。
<div align="center"> <img src="pics/_u91CD_u5EFA_u4E8C_u53C9_u6811-21548502782193.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u91CD_u5EFA_u4E8C_u53C9_u6811-21548502782193.gif"/> </div><br>
```java
// 缓存中序遍历数组每个值对应的索引
@ -320,11 +320,11 @@ public class TreeLinkNode {
① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
<div align="center"> <img src="pics/_u4E8C_u53C9_u6811_u7684_u4E0B_.gif" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4E8C_u53C9_u6811_u7684_u4E0B_.gif" width="250"/> </div><br>
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
<div align="center"> <img src="pics/_u4E8C_u53C9_u6811_u7684_u4E0B_1548504426508.gif" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4E8C_u53C9_u6811_u7684_u4E0B_1548504426508.gif" width="250"/> </div><br>
```java
public TreeLinkNode GetNext(TreeLinkNode pNode) {
@ -357,7 +357,7 @@ public TreeLinkNode GetNext(TreeLinkNode pNode) {
in 栈用来处理入栈push操作out 栈用来处理出栈pop操作。一个元素进入 in 栈之后,出栈的顺序被反转。当元素要出栈时,需要先进入 out 栈,此时元素出栈顺序再一次被反转,因此出栈顺序就和最开始入栈顺序是相同的,先进入的元素先退出,这就是队列的顺序。
<div align="center"> <img src="pics/_u7528_u4E24_u4E2A_u6808_u5B9E_.gif" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u7528_u4E24_u4E2A_u6808_u5B9E_.gif" width="500"/> </div><br>
```java

View File

@ -140,7 +140,7 @@ private void merge(int[] nums, int l, int m, int h) {
## 题目描述
<div align="center"> <img src="pics/8f6f9dc9-9ecd-47c8-b50e-2814f0219056.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8f6f9dc9-9ecd-47c8-b50e-2814f0219056.png" width="500"/> </div><br>
## 解题思路
@ -232,7 +232,7 @@ private void inOrder(TreeNode root, int k) {
从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
<div align="center"> <img src="pics/b29f8971-9cb8-480d-b986-0e60c2ece069.png" width="350"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b29f8971-9cb8-480d-b986-0e60c2ece069.png" width="350"/> </div><br>
## 解题思路
@ -250,7 +250,7 @@ public int TreeDepth(TreeNode root) {
平衡二叉树左右子树高度差不超过 1。
<div align="center"> <img src="pics/e026c24d-00fa-4e7c-97a8-95a98cdc383a.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e026c24d-00fa-4e7c-97a8-95a98cdc383a.png" width="300"/> </div><br>
## 解题思路

View File

@ -40,7 +40,7 @@
把 n 个骰子仍在地上,求点数和为 s 的概率。
<div align="center"> <img src="pics/6_2001550474388460.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6_2001550474388460.png"/> </div><br>
## 解题思路
@ -113,7 +113,7 @@ public List<Map.Entry<Integer, Double>> dicesSum(int n) {
五张牌,其中大小鬼为癞子,牌面大小为 0。判断这五张牌是否能组成顺子。
<div align="center"> <img src="pics/5_2001550474110029.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5_2001550474110029.png"/> </div><br>
## 解题思路
@ -172,7 +172,7 @@ public int LastRemaining_Solution(int n, int m) {
可以有一次买入和一次卖出,那么买入必须在前。求最大收益。
<div align="center"> <img src="pics/4_2001550473915641.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4_2001550473915641.png"/> </div><br>
## 解题思路
@ -244,7 +244,7 @@ public int Add(int a, int b) {
给定一个数组 A[0, 1,..., n-1],请构建一个数组 B[0, 1,..., n-1],其中 B 中的元素 B[i]=A[0]\*A[1]\*...\*A[i-1]\*A[i+1]\*...\*A[n-1]。要求不能使用除法。
<div align="center"> <img src="pics/3_2001550473624627.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3_2001550473624627.png"/> </div><br>
## 解题思路
@ -304,7 +304,7 @@ public int StrToInt(String str) {
### 二叉查找树
<div align="center"> <img src="pics/b39a085e-e7a2-4657-b75e-ba1652a4b132.jpg" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b39a085e-e7a2-4657-b75e-ba1652a4b132.jpg" width="300"/> </div><br>
[Leetcode : 235. Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/)
@ -324,7 +324,7 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
### 普通二叉树
<div align="center"> <img src="pics/37a72755-4890-4b42-9eab-b0084e0c54d9.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/37a72755-4890-4b42-9eab-b0084e0c54d9.png" width="300"/> </div><br>
[Leetcode : 236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/)

View File

@ -47,7 +47,7 @@
事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。
<div align="center"> <img src="pics/731a5e8f-a2c2-43ff-b8dd-6aeb9fffbe26.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/731a5e8f-a2c2-43ff-b8dd-6aeb9fffbe26.jpg"/> </div><br>
## ACID
@ -80,7 +80,7 @@
- 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
- 事务满足持久化是为了能应对数据库崩溃的情况。
<div align="center"> <img src="pics/8036ba3d-8de9-44aa-bf5d-1f8ca18ae89b.jpg" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8036ba3d-8de9-44aa-bf5d-1f8ca18ae89b.jpg" width="700"/> </div><br>
## AUTOCOMMIT
@ -94,26 +94,26 @@ MySQL 默认采用自动提交模式。也就是说,如果不显式使用`STAR
T<sub>1</sub> 和 T<sub>2</sub> 两个事务都对一个数据进行修改T<sub>1</sub> 先修改T<sub>2</sub> 随后修改T<sub>2</sub> 的修改覆盖了 T<sub>1</sub> 的修改。
<div align="center"> <img src="pics/26a7c9df-22f6-4df4-845a-745c053ab2e5.jpg" width="350"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/26a7c9df-22f6-4df4-845a-745c053ab2e5.jpg" width="350"/> </div><br>
## 读脏数据
T<sub>1</sub> 修改一个数据T<sub>2</sub> 随后读取这个数据。如果 T<sub>1</sub> 撤销了这次修改,那么 T<sub>2</sub> 读取的数据是脏数据。
<div align="center"> <img src="pics/bab0fba6-38e4-45f7-b34d-3edaad43810f.jpg" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bab0fba6-38e4-45f7-b34d-3edaad43810f.jpg" width="400"/> </div><br>
## 不可重复读
T<sub>2</sub> 读取一个数据T<sub>1</sub> 对该数据做了修改。如果 T<sub>2</sub> 再次读取这个数据,此时读取的结果和第一次读取的结果不同。
<div align="center"> <img src="pics/43bf0957-0386-4c09-9ad7-e163c5b62559.jpg" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/43bf0957-0386-4c09-9ad7-e163c5b62559.jpg" width="400"/> </div><br>
## 幻影读
T<sub>1</sub> 读取某个范围的数据T<sub>2</sub> 在这个范围内插入新的数据T<sub>1</sub> 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
<div align="center"> <img src="pics/2959e455-e6cb-4461-aeb3-e319fe5c41db.jpg" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2959e455-e6cb-4461-aeb3-e319fe5c41db.jpg" width="400"/> </div><br>
----
@ -132,7 +132,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。
<div align="center"> <img src="pics/1a851e90-0d5c-4d4f-ac54-34c20ecfb903.jpg" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1a851e90-0d5c-4d4f-ac54-34c20ecfb903.jpg" width="300"/> </div><br>
## 封锁类型
@ -323,7 +323,7 @@ MVCC 在每行记录后面都保存着两个隐藏的列,用来存储两个版
MVCC 使用到的快照存储在 Undo 日志中该日志通过回滚指针把一个数据行Record的所有快照连接起来。
<div align="center"> <img src="pics/e41405a8-7c05-4f70-8092-e961e28d3112.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e41405a8-7c05-4f70-8092-e961e28d3112.jpg" width=""/> </div><br>
## 实现过程
@ -439,7 +439,7 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
高级别范式的依赖于低级别的范式1NF 是最低级别的范式。
<div align="center"> <img src="pics/c2d343f7-604c-4856-9a3c-c71d6f67fecc.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c2d343f7-604c-4856-9a3c-c71d6f67fecc.png" width="300"/> </div><br>
### 1. 第一范式 (1NF)
@ -539,7 +539,7 @@ Entity-Relationship有三个组成部分实体、属性、联系。
下图的 Course 和 Student 是一对多的关系。
<div align="center"> <img src="pics/292b4a35-4507-4256-84ff-c218f108ee31.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/292b4a35-4507-4256-84ff-c218f108ee31.jpg" width=""/> </div><br>
## 表示出现多次的关系
@ -547,23 +547,23 @@ Entity-Relationship有三个组成部分实体、属性、联系。
下图表示一个课程的先修关系,先修关系出现两个 Course 实体,第一个是先修课程,后一个是后修课程,因此需要用两条线来表示这种关系。
<div align="center"> <img src="pics/8b798007-e0fb-420c-b981-ead215692417.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8b798007-e0fb-420c-b981-ead215692417.jpg" width=""/> </div><br>
## 联系的多向性
虽然老师可以开设多门课,并且可以教授多名学生,但是对于特定的学生和课程,只有一个老师教授,这就构成了一个三元联系。
<div align="center"> <img src="pics/423f2a40-bee1-488e-b460-8e76c48ee560.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/423f2a40-bee1-488e-b460-8e76c48ee560.png" width=""/> </div><br>
一般只使用二元联系,可以把多元联系转换为二元联系。
<div align="center"> <img src="pics/de9b9ea0-1327-4865-93e5-6f805c48bc9e.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/de9b9ea0-1327-4865-93e5-6f805c48bc9e.png" width=""/> </div><br>
## 表示子类
用一个三角形和两条线来连接类和子类,与子类有关的属性和联系都连到子类上,而与父类和子类都有关的连到父类上。
<div align="center"> <img src="pics/7ec9d619-fa60-4a2b-95aa-bf1a62aad408.jpg" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7ec9d619-fa60-4a2b-95aa-bf1a62aad408.jpg" width=""/> </div><br>
# 参考资料

View File

@ -34,7 +34,7 @@
主要包括 Ant、Maven 和 Gradle。
<div align="center"> <img src="pics/df247180-4d5c-4d4b-ab0f-1aec61d13d45.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/df247180-4d5c-4d4b-ab0f-1aec61d13d45.png"/> </div><br>
Gradle 和 Maven 的区别是,它使用 Groovy 这种特定领域语言DSL来管理构建脚本而不再使用 XML 这种标记性语言。因为项目如果庞大的话XML 很容易就变得臃肿。

View File

@ -173,7 +173,7 @@ a.+c
^\s*\/\/.*$
```
<div align="center"> <img src="pics/600e9c75-5033-4dad-ae2b-930957db638e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/600e9c75-5033-4dad-ae2b-930957db638e.png"/> </div><br>
**匹配结果**

View File

@ -19,20 +19,20 @@
消息生产者向消息队列中发送了一个消息之后,只能被一个消费者消费一次。
<div align="center"> <img src="pics/b28a7b1e-bf5a-4e23-8be7-701eacef0111.jpg" width="600px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b28a7b1e-bf5a-4e23-8be7-701eacef0111.jpg" width="600px"/> </div><br>
## 发布/订阅
消息生产者向频道发送一个消息之后,多个消费者可以从该频道订阅到这条消息并消费。
<div align="center"> <img src="pics/1b718cd5-7b1e-496c-9133-2bfd12bb5f89.jpg" width="600px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1b718cd5-7b1e-496c-9133-2bfd12bb5f89.jpg" width="600px"/> </div><br>
发布与订阅模式和观察者模式有以下不同:
- 观察者模式中,观察者和主题都知道对方的存在;而在发布与订阅模式中,发布者与订阅者不知道对方的存在,它们之间通过频道进行通信。
- 观察者模式是同步的,当事件触发时,主题会调用观察者的方法,然后等待方法返回;而发布与订阅模式是异步的,发布者向频道发送一个消息之后,就不需要关心订阅者何时去订阅这个消息,可以立即返回。
<div align="center"> <img src="pics/d011c697-2551-4968-ac51-e5e01a954204.jpg" width="600px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d011c697-2551-4968-ac51-e5e01a954204.jpg" width="600px"/> </div><br>
# 二、使用场景

View File

@ -6,7 +6,7 @@
# 汉诺塔
<div align="center"> <img src="pics/54f1e052-0596-4b5e-833c-e80d75bf3f9b.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/54f1e052-0596-4b5e-833c-e80d75bf3f9b.png" width="300"/> </div><br>
有三个柱子,分别为 from、buffer、to。需要将 from 上的圆盘全部移动到 to 上,并且要保证小圆盘始终在大圆盘上。
@ -14,15 +14,15 @@
① 将 n-1 个圆盘从 from -> buffer
<div align="center"> <img src="pics/8587132a-021d-4f1f-a8ec-5a9daa7157a7.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8587132a-021d-4f1f-a8ec-5a9daa7157a7.png" width="300"/> </div><br>
② 将 1 个圆盘从 from -> to
<div align="center"> <img src="pics/2861e923-4862-4526-881c-15529279d49c.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2861e923-4862-4526-881c-15529279d49c.png" width="300"/> </div><br>
③ 将 n-1 个圆盘从 buffer -> to
<div align="center"> <img src="pics/1c4e8185-8153-46b6-bd5a-288b15feeae6.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1c4e8185-8153-46b6-bd5a-288b15feeae6.png" width="300"/> </div><br>
如果只有一个圆盘,那么只需要进行一次移动操作。
@ -73,7 +73,7 @@ from H1 to H3
生成编码时,从根节点出发,向左遍历则添加二进制位 0向右则添加二进制位 1直到遍历到叶子节点叶子节点代表的字符的编码就是这个路径编码。
<div align="center"> <img src="pics/3ff4f00a-2321-48fd-95f4-ce6001332151.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3ff4f00a-2321-48fd-95f4-ce6001332151.png" width="400"/> </div><br>
```java
public class Huffman {

View File

@ -12,7 +12,7 @@
用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。
<div align="center"> <img src="pics/9d0a637c-6a8f-4f5a-99b9-fdcfa26793ff.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9d0a637c-6a8f-4f5a-99b9-fdcfa26793ff.png" width="400"/> </div><br>
| 方法 | 描述 |
| :---: | :---: |
@ -51,7 +51,7 @@ public abstract class UF {
但是 union 操作代价却很高,需要将其中一个连通分量中的所有节点 id 值都修改为另一个节点的 id 值。
<div align="center"> <img src="pics/8f0cc500-5994-4c7a-91a9-62885d658662.png" width="350"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8f0cc500-5994-4c7a-91a9-62885d658662.png" width="350"/> </div><br>
```java
public class QuickFindUF extends UF {
@ -91,7 +91,7 @@ public class QuickFindUF extends UF {
但是 find 操作开销很大,因为同一个连通分量的节点 id 值不同id 值只是用来指向另一个节点。因此需要一直向上查找操作,直到找到最上层的节点。
<div align="center"> <img src="pics/5d4a5181-65fb-4bf2-a9c6-899cab534b44.png" width="350"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5d4a5181-65fb-4bf2-a9c6-899cab534b44.png" width="350"/> </div><br>
```java
public class QuickUnionUF extends UF {
@ -124,7 +124,7 @@ public class QuickUnionUF extends UF {
这种方法可以快速进行 union 操作,但是 find 操作和树高成正比,最坏的情况下树的高度为节点的数目。
<div align="center"> <img src="pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png" width="130"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png" width="130"/> </div><br>
# 加权 Quick Union
@ -132,7 +132,7 @@ public class QuickUnionUF extends UF {
理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。
<div align="center"> <img src="pics/a4c17d43-fa5e-4935-b74e-147e7f7e782c.png" width="170"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a4c17d43-fa5e-4935-b74e-147e7f7e782c.png" width="170"/> </div><br>
```java
public class WeightedQuickUnionUF extends UF {

View File

@ -58,7 +58,7 @@ public abstract class Sort<T extends Comparable<T>> {
选择排序需要 \~N<sup>2</sup>/2 次比较和 \~N 次交换,它的运行时间与输入无关,这个特点使得它对一个已经排序的数组也需要这么多的比较和交换操作。
<div align="center"> <img src="pics/21550397584141.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/21550397584141.gif"/> </div><br>
```java
public class Selection<T extends Comparable<T>> extends Sort<T> {
@ -85,7 +85,7 @@ public class Selection<T extends Comparable<T>> extends Sort<T> {
在一轮循环中,如果没有发生交换,就说明数组已经是有序的,此时可以直接退出。
<div align="center"> <img src="pics/31550398353573.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/31550398353573.gif"/> </div><br>
```java
public class Bubble<T extends Comparable<T>> extends Sort<T> {
@ -121,7 +121,7 @@ public class Bubble<T extends Comparable<T>> extends Sort<T> {
以下演示了在一轮循环中,将元素 2 插入到左侧已经排序的数组中。
<div align="center"> <img src="pics/51550399426594.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/51550399426594.gif"/> </div><br>
```java
public class Insertion<T extends Comparable<T>> extends Sort<T> {
@ -146,7 +146,7 @@ public class Insertion<T extends Comparable<T>> extends Sort<T> {
希尔排序使用插入排序对间隔 h 的序列进行排序。通过不断减小 h最后令 h=1就可以使得整个数组是有序的。
<div align="center"> <img src="pics/cb5d2258-a60e-4364-94a7-3429a3064554_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cb5d2258-a60e-4364-94a7-3429a3064554_200.png"/> </div><br>
```java
public class Shell<T extends Comparable<T>> extends Sort<T> {
@ -180,7 +180,7 @@ public class Shell<T extends Comparable<T>> extends Sort<T> {
归并排序的思想是将数组分成两部分,分别进行排序,然后归并起来。
<div align="center"> <img src="pics/2_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_200.png"/> </div><br>
## 1. 归并方法
@ -275,7 +275,7 @@ public class Down2UpMergeSort<T extends Comparable<T>> extends MergeSort<T> {
- 归并排序将数组分为两个子数组分别排序,并将有序的子数组归并使得整个数组排序;
- 快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。
<div align="center"> <img src="pics/3_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3_200.png"/> </div><br>
```java
public class QuickSort<T extends Comparable<T>> extends Sort<T> {
@ -306,7 +306,7 @@ public class QuickSort<T extends Comparable<T>> extends Sort<T> {
取 a[l] 作为切分元素,然后从数组的左端向右扫描直到找到第一个大于等于它的元素,再从数组的右端向左扫描找到第一个小于它的元素,交换这两个元素。不断进行这个过程,就可以保证左指针 i 的左侧元素都不大于切分元素,右指针 j 的右侧元素都不小于切分元素。当两个指针相遇时,将切分元素 a[l] 和 a[j] 交换位置。
<div align="center"> <img src="pics/61550402057509.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/61550402057509.gif"/> </div><br>
```java
private int partition(T[] nums, int l, int h) {
@ -410,7 +410,7 @@ public T select(T[] nums, int k) {
堆可以用数组来表示,这是因为堆是完全二叉树,而完全二叉树很容易就存储在数组中。位置 k 的节点的父节点位置为 k/2而它的两个子节点的位置分别为 2k 和 2k+1。这里不使用数组索引为 0 的位置,是为了更清晰地描述节点的位置关系。
<div align="center"> <img src="pics/8_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8_200.png"/> </div><br>
```java
public class Heap<T extends Comparable<T>> {
@ -446,7 +446,7 @@ public class Heap<T extends Comparable<T>> {
在堆中,当一个节点比父节点大,那么需要交换这个两个节点。交换后还可能比它新的父节点大,因此需要不断地进行比较和交换操作,把这种操作称为上浮。
<div align="center"> <img src="pics/81550405360028.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/81550405360028.gif"/> </div><br>
```java
private void swim(int k) {
@ -459,7 +459,7 @@ private void swim(int k) {
类似地,当一个节点比子节点来得小,也需要不断地向下进行比较和交换操作,把这种操作称为下沉。一个节点如果有两个子节点,应当与两个子节点中最大那个节点进行交换。
<div align="center"> <img src="pics/91550405374894.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/91550405374894.gif"/> </div><br>
```java
private void sink(int k) {
@ -508,13 +508,13 @@ public T delMax() {
无序数组建立堆最直接的方法是从左到右遍历数组进行上浮操作。一个更高效的方法是从右至左进行下沉操作,如果一个节点的两个节点都已经是堆有序,那么进行下沉操作可以使得这个节点为根节点的堆有序。叶子节点不需要进行下沉操作,可以忽略叶子节点的元素,因此只需要遍历一半的元素即可。
<div align="center"> <img src="pics/101550406418006.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/101550406418006.gif"/> </div><br>
#### 5.2 交换堆顶元素与最后一个元素
交换之后需要进行下沉操作维持堆的有序状态。
<div align="center"> <img src="pics/111550407277293.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/111550407277293.gif"/> </div><br>
```java
public class HeapSort<T extends Comparable<T>> extends Sort<T> {

View File

@ -245,15 +245,15 @@ public class BinarySearchOrderedST<Key extends Comparable<Key>, Value> implement
**二叉树** 是一个空链接,或者是一个有左右两个链接的节点,每个链接都指向一颗子二叉树。
<div align="center"> <img src="pics/f9f9f993-8ece-4da7-b848-af9b438fad76.png" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f9f9f993-8ece-4da7-b848-af9b438fad76.png" width="200"/> </div><br>
**二叉查找树** BST是一颗二叉树并且每个节点的值都大于等于其左子树中的所有节点的值而小于等于右子树的所有节点的值。
<div align="center"> <img src="pics/8ae4550b-f0cb-4e4d-9e2b-c550538bf230.png" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8ae4550b-f0cb-4e4d-9e2b-c550538bf230.png" width="200"/> </div><br>
BST 有一个重要性质,就是它的中序遍历结果递增排序。
<div align="center"> <img src="pics/fbe54203-c005-48f0-8883-b05e564a3173.png" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fbe54203-c005-48f0-8883-b05e564a3173.png" width="200"/> </div><br>
基本数据结构:
@ -327,7 +327,7 @@ private Value get(Node x, Key key) {
当插入的键不存在于树中,需要创建一个新节点,并且更新上层节点的链接指向该节点,使得该节点正确地链接到树中。
<div align="center"> <img src="pics/107a6a2b-f15b-4cad-bced-b7fb95258c9c.png" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/107a6a2b-f15b-4cad-bced-b7fb95258c9c.png" width="200"/> </div><br>
```java
@Override
@ -356,11 +356,11 @@ private Node put(Node x, Key key, Value value) {
最好的情况下树是完全平衡的,每条空链接和根节点的距离都为 logN。
<div align="center"> <img src="pics/4d741402-344d-4b7c-be01-e57184bcad0e.png" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4d741402-344d-4b7c-be01-e57184bcad0e.png" width="200"/> </div><br>
在最坏的情况下,树的高度为 N。
<div align="center"> <img src="pics/be7dca03-12ec-456b-8b54-b1b3161f5531.png" width="200"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/be7dca03-12ec-456b-8b54-b1b3161f5531.png" width="200"/> </div><br>
## 4. floor()
@ -438,7 +438,7 @@ private Node min(Node x) {
令指向最小节点的链接指向最小节点的右子树。
<div align="center"> <img src="pics/dd15a984-e977-4644-b127-708cddb8ca99.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/dd15a984-e977-4644-b127-708cddb8ca99.png" width="500"/> </div><br>
```java
public void deleteMin() {
@ -459,7 +459,7 @@ public Node deleteMin(Node x) {
- 如果待删除的节点只有一个子树, 那么只需要让指向待删除节点的链接指向唯一的子树即可;
- 否则,让右子树的最小节点替换该节点。
<div align="center"> <img src="pics/fa568fac-ac58-48dd-a9bb-23b3065bf2dc.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fa568fac-ac58-48dd-a9bb-23b3065bf2dc.png" width="400"/> </div><br>
```java
public void delete(Key key) {
@ -522,7 +522,7 @@ private List<Key> keys(Node x, Key l, Key h) {
2-3 查找树引入了 2- 节点和 3- 节点,目的是为了让树平衡。一颗完美平衡的 2-3 查找树的所有空链接到根节点的距离应该是相同的。
<div align="center"> <img src="pics/ff396233-1bb1-4e74-8bc2-d7c90146f5dd.png" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ff396233-1bb1-4e74-8bc2-d7c90146f5dd.png" width="250"/> </div><br>
## 1. 插入操作
@ -532,11 +532,11 @@ private List<Key> keys(Node x, Key l, Key h) {
- 如果插入到 2- 节点上,那么直接将新节点和原来的节点组成 3- 节点即可。
<div align="center"> <img src="pics/7f38a583-2f2e-4738-97af-510e6fb403a7.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7f38a583-2f2e-4738-97af-510e6fb403a7.png" width="400"/> </div><br>
- 如果是插入到 3- 节点上,就会产生一个临时 4- 节点时,需要将 4- 节点分裂成 3 个 2- 节点,并将中间的 2- 节点移到上层节点中。如果上移操作继续产生临时 4- 节点则一直进行分裂上移,直到不存在临时 4- 节点。
<div align="center"> <img src="pics/ef280699-da36-4b38-9735-9b048a3c7fe0.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ef280699-da36-4b38-9735-9b048a3c7fe0.png" width="500"/> </div><br>
## 2. 性质
@ -548,7 +548,7 @@ private List<Key> keys(Node x, Key l, Key h) {
红黑树是 2-3 查找树,但它不需要分别定义 2- 节点和 3- 节点,而是在普通的二叉查找树之上,为节点添加颜色。指向一个节点的链接颜色如果为红色,那么这个节点和上层节点表示的是一个 3- 节点,而黑色则是普通链接。
<div align="center"> <img src="pics/4f48e806-f90b-4c09-a55f-ac0cd641c047.png" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4f48e806-f90b-4c09-a55f-ac0cd641c047.png" width="250"/> </div><br>
红黑树具有以下性质:
@ -557,7 +557,7 @@ private List<Key> keys(Node x, Key l, Key h) {
画红黑树时可以将红链接画平。
<div align="center"> <img src="pics/3086c248-b552-499e-b101-9cffe5c2773e.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3086c248-b552-499e-b101-9cffe5c2773e.png" width="300"/> </div><br>
```java
public class RedBlackBST<Key extends Comparable<Key>, Value> extends BST<Key, Value> {
@ -577,7 +577,7 @@ public class RedBlackBST<Key extends Comparable<Key>, Value> extends BST<Key, Va
因为合法的红链接都为左链接,如果出现右链接为红链接,那么就需要进行左旋转操作。
<div align="center"> <img src="pics/9110c1a0-8a54-4145-a814-2477d0128114.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9110c1a0-8a54-4145-a814-2477d0128114.png" width="450"/> </div><br>
```java
public Node rotateLeft(Node h) {
@ -596,7 +596,7 @@ public Node rotateLeft(Node h) {
进行右旋转是为了转换两个连续的左红链接,这会在之后的插入过程中探讨。
<div align="center"> <img src="pics/e2f0d889-2330-424c-8193-198edebecff7.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e2f0d889-2330-424c-8193-198edebecff7.png" width="450"/> </div><br>
```java
public Node rotateRight(Node h) {
@ -614,7 +614,7 @@ public Node rotateRight(Node h) {
一个 4- 节点在红黑树中表现为一个节点的左右子节点都是红色的。分裂 4- 节点除了需要将子节点的颜色由红变黑之外,同时需要将父节点的颜色由黑变红,从 2-3 树的角度看就是将中间节点移到上层节点。
<div align="center"> <img src="pics/af4639f9-af54-4400-aaf5-4e261d96ace7.png" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/af4639f9-af54-4400-aaf5-4e261d96ace7.png" width="300"/> </div><br>
```java
void flipColors(Node h) {
@ -632,7 +632,7 @@ void flipColors(Node h) {
- 如果左子节点是红色的,而且左子节点的左子节点也是红色的,进行右旋转;
- 如果左右子节点均为红色的,进行颜色转换。
<div align="center"> <img src="pics/08427d38-8df1-49a1-8990-e0ce5ee36ca2.png" width="400"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/08427d38-8df1-49a1-8990-e0ce5ee36ca2.png" width="400"/> </div><br>
```java
@Override
@ -757,7 +757,7 @@ public class Transaction {
对于 N 个键M 条链表 (N>M),如果哈希函数能够满足均匀性的条件,每条链表的大小趋向于 N/M因此未命中的查找和插入操作所需要的比较次数为 \~N/M。
<div align="center"> <img src="pics/9_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9_200.png"/> </div><br>
## 3. 线性探测法
@ -765,7 +765,7 @@ public class Transaction {
使用线性探测法,数组的大小 M 应当大于键的个数 NM>N)。
<div align="center"> <img src="pics/121550407878282.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/121550407878282.gif"/> </div><br>
```java
public class LinearProbingHashST<Key, Value> implements UnorderedST<Key, Value> {
@ -866,7 +866,7 @@ public void delete(Key key) {
线性探测法的成本取决于连续条目的长度,连续条目也叫聚簇。当聚簇很长时,在查找和插入时也需要进行很多次探测。例如下图中 2\~5 位置就是一个聚簇。
<div align="center"> <img src="pics/11_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/11_200.png"/> </div><br>
α = N/Mα 称为使用率。理论证明,当 α 小于 1/2 时探测的预计次数只在 1.5 到 2.5 之间。为了保证散列表的性能,应当调整数组的大小,使得 α 在 [1/4, 1/2] 之间。

View File

@ -201,7 +201,7 @@ CDN 主要有以下优点:
- 通过部署多台服务器,从而提高系统整体的带宽性能;
- 多台服务器可以看成是一种冗余机制,从而具有高可用性。
<div align="center"> <img src="pics/15313ed8-a520-4799-a300-2b6b36be314f.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/15313ed8-a520-4799-a300-2b6b36be314f.jpg"/> </div><br>
# 五、缓存问题
@ -262,11 +262,11 @@ Distributed Hash TableDHT 是一种哈希分布方式,其目的是为了
将哈希空间 [0, 2<sup>n</sup>-1] 看成一个哈希环,每个服务器节点都配置到哈希环上。每个数据对象通过哈希取模得到哈希值之后,存放到哈希环中顺时针方向第一个大于等于该哈希值的节点上。
<div align="center"> <img src="pics/68b110b9-76c6-4ee2-b541-4145e65adb3e.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/68b110b9-76c6-4ee2-b541-4145e65adb3e.jpg"/> </div><br>
一致性哈希在增加或者删除节点时只会影响到哈希环中相邻的节点,例如下图中新增节点 X只需要将它前一个节点 C 上的数据重新进行分布即可,对于节点 A、B、D 都没有影响。
<div align="center"> <img src="pics/66402828-fb2b-418f-83f6-82153491bcfe.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/66402828-fb2b-418f-83f6-82153491bcfe.jpg"/> </div><br>
## 虚拟节点

View File

@ -22,7 +22,7 @@
从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0\~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。
<div align="center"> <img src="pics/7b281b1e-0595-402b-ae35-8c91084c33c1.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7b281b1e-0595-402b-ae35-8c91084c33c1.png"/> </div><br>
# 分页系统地址映射
@ -32,7 +32,7 @@
下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址0010 000000000100前 4 位是存储页面号 2读取表项内容为110 1页表项最后一位表示是否存在于内存中1 表示存在。后 12 位存储偏移量。这个页对应的页框的地址为 110 000000000100
<div align="center"> <img src="pics/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png" width="500"/> </div><br>
# 页面置换算法
@ -68,7 +68,7 @@
<div align="center"><img src="https://latex.codecogs.com/gif.latex?47071012126"/></div> <br>
<div align="center"> <img src="pics/eb859228-c0f2-4bce-910d-d9f76929352b.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png"/> </div><br>
## 3. 最近未使用
@ -99,7 +99,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候检查最老页面的 R 位。如果 R 位是 0那么这个页面既老又没有被使用可以立刻置换掉如果是 1就将 R 位清 0并把该页面放到链表的尾端修改它的装入时间使它就像刚装入的一样然后继续从链表的头部开始搜索。
<div align="center"> <img src="pics/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png"/> </div><br>
## 6. 时钟
@ -107,7 +107,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。
<div align="center"> <img src="pics/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png"/> </div><br>
# 分段
@ -115,11 +115,11 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
下图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。
<div align="center"> <img src="pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png"/> </div><br>
分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。
<div align="center"> <img src="pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png"/> </div><br>
# 段页式

View File

@ -76,7 +76,7 @@
如果一个进程在用户态需要使用内核态的功能,就进行系统调用从而陷入内核,由操作系统代为完成。
<div align="center"> <img src="pics/tGPV0.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/tGPV0.png" width="600"/> </div><br>
Linux 的系统调用主要有以下这些:
@ -105,7 +105,7 @@ Linux 的系统调用主要有以下这些:
因为需要频繁地在用户态和核心态之间进行切换,所以会有一定的性能损失。
<div align="center"> <img src="pics/2_14_microkernelArchitecture.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_14_microkernelArchitecture.jpg"/> </div><br>
# 中断分类

View File

@ -20,7 +20,7 @@
# 必要条件
<div align="center"> <img src="pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png"/> </div><br>
- 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。
- 占有和等待:已经得到了某个资源的进程可以再请求新的资源。
@ -52,7 +52,7 @@
## 1. 每种类型一个资源的死锁检测
<div align="center"> <img src="pics/b1fa0453-a4b0-4eae-a352-48acca8fff74.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b1fa0453-a4b0-4eae-a352-48acca8fff74.png"/> </div><br>
上图为资源分配图,其中方框表示资源,圆圈表示进程。资源指向进程表示该资源已经分配给该进程,进程指向资源表示进程请求获取该资源。
@ -62,7 +62,7 @@
## 2. 每种类型多个资源的死锁检测
<div align="center"> <img src="pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png"/> </div><br>
上图中,有三个进程四个资源,每个数据代表的含义如下:
@ -111,7 +111,7 @@
## 1. 安全状态
<div align="center"> <img src="pics/ed523051-608f-4c3f-b343-383e2d194470.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ed523051-608f-4c3f-b343-383e2d194470.png"/> </div><br>
图 a 的第二列 Has 表示已拥有的资源数,第三列 Max 表示总共需要的资源数Free 表示还有可以使用的资源数。从图 a 开始出发,先让 B 拥有所需的所有资源(图 b运行结束后释放 B此时 Free 变为 5图 c接着以同样的方式运行 C 和 A使得所有进程都能成功运行因此可以称图 a 所示的状态时安全的。
@ -123,13 +123,13 @@
一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,算法要做的是判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求;否则予以分配。
<div align="center"> <img src="pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png"/> </div><br>
上图 c 为不安全状态,因此算法会拒绝之前的请求,从而避免进入图 c 中的状态。
## 3. 多个资源的银行家算法
<div align="center"> <img src="pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png"/> </div><br>
上图中有五个进程,四个资源。左边的图表示已经分配的资源,右边的图表示还需要分配的资源。最右边的 E、P 以及 A 分别表示:总资源、已分配资源以及可用资源,注意这三个为向量,而不是具体数值,例如 A=(1020),表示 4 个资源分别还剩下 1/0/2/0。

View File

@ -16,7 +16,7 @@
- 制动手臂Actuator arm用于在磁道之间移动磁头
- 主轴Spindle使整个盘面转动。
<div align="center"> <img src="pics/014fbc4d-d873-4a12-b160-867ddaed9807.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/014fbc4d-d873-4a12-b160-867ddaed9807.jpg"/> </div><br>
# 磁盘调度算法
@ -44,7 +44,7 @@
虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现饥饿现象。具体来说,两端的磁道请求更容易出现饥饿现象。
<div align="center"> <img src="pics/4e2485e4-34bd-4967-9f02-0c093b797aaa.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4e2485e4-34bd-4967-9f02-0c093b797aaa.png"/> </div><br>
## 3. 电梯算法
@ -56,7 +56,7 @@
因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。
<div align="center"> <img src="pics/271ce08f-c124-475f-b490-be44fedc6d2e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/271ce08f-c124-475f-b490-be44fedc6d2e.png"/> </div><br>

View File

@ -36,7 +36,7 @@
下图显示了 4 个程序创建了 4 个进程,这 4 个进程可以并发地执行。
<div align="center"> <img src="pics/a6ac2b08-3861-4e85-baa8-382287bfee9f.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a6ac2b08-3861-4e85-baa8-382287bfee9f.png"/> </div><br>
## 2. 线程
@ -46,7 +46,7 @@
QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。
<div align="center"> <img src="pics/3cd630ea-017c-488d-ad1d-732b4efeddf5.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3cd630ea-017c-488d-ad1d-732b4efeddf5.png"/> </div><br>
## 3. 区别
@ -68,7 +68,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
# 进程状态的切换
<div align="center"> <img src="pics/ProcessState.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ProcessState.png" width="500"/> </div><br>
- 就绪状态ready等待被调度
- 运行状态running
@ -116,7 +116,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
- 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。
- 而如果时间片过长,那么实时性就不能得到保证。
<div align="center"> <img src="pics/8c662999-c16c-481c-9f40-1fdba5bc9167.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8c662999-c16c-481c-9f40-1fdba5bc9167.png"/> </div><br>
**2.2 优先级调度**
@ -134,7 +134,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。
<div align="center"> <img src="pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png"/> </div><br>
## 3. 实时系统
@ -453,7 +453,7 @@ void reader()
## 2. 哲学家进餐问题
<div align="center"> <img src="pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg"/> </div><br>
五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。
@ -547,7 +547,7 @@ int pipe(int fd[2]);
- 只支持半双工通信(单向交替传输);
- 只能在父子进程中使用。
<div align="center"> <img src="pics/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png"/> </div><br>
## 2. FIFO
@ -561,7 +561,7 @@ int mkfifoat(int fd, const char *path, mode_t mode);
FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。
<div align="center"> <img src="pics/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png"/> </div><br>
## 3. 消息队列

View File

@ -28,7 +28,7 @@ gcc -o hello hello.c
这个过程大致如下:
<div align="center"> <img src="pics/b396d726-b75f-4a32-89a2-03a7b6e19f6f.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b396d726-b75f-4a32-89a2-03a7b6e19f6f.jpg" width="800"/> </div><br>
- 预处理阶段:处理以 # 开头的预处理命令;
- 编译阶段:翻译成汇编文件;
@ -42,7 +42,7 @@ gcc -o hello hello.c
- 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。
- 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。
<div align="center"> <img src="pics/47d98583-8bb0-45cc-812d-47eefa0a4a40.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/47d98583-8bb0-45cc-812d-47eefa0a4a40.jpg"/> </div><br>
# 目标文件
@ -62,7 +62,7 @@ gcc -o hello hello.c
- 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中;
- 在内存中,一个共享库的 .text 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。
<div align="center"> <img src="pics/76dc7769-1aac-4888-9bea-064f1caa8e77.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/76dc7769-1aac-4888-9bea-064f1caa8e77.jpg"/> </div><br>

View File

@ -96,7 +96,7 @@
如果一个进程在用户态需要使用内核态的功能,就进行系统调用从而陷入内核,由操作系统代为完成。
<div align="center"> <img src="pics/tGPV0.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/tGPV0.png" width="600"/> </div><br>
Linux 的系统调用主要有以下这些:
@ -125,7 +125,7 @@ Linux 的系统调用主要有以下这些:
因为需要频繁地在用户态和核心态之间进行切换,所以会有一定的性能损失。
<div align="center"> <img src="pics/2_14_microkernelArchitecture.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_14_microkernelArchitecture.jpg"/> </div><br>
## 中断分类
@ -153,7 +153,7 @@ Linux 的系统调用主要有以下这些:
下图显示了 4 个程序创建了 4 个进程,这 4 个进程可以并发地执行。
<div align="center"> <img src="pics/a6ac2b08-3861-4e85-baa8-382287bfee9f.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a6ac2b08-3861-4e85-baa8-382287bfee9f.png"/> </div><br>
### 2. 线程
@ -163,7 +163,7 @@ Linux 的系统调用主要有以下这些:
QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。
<div align="center"> <img src="pics/3cd630ea-017c-488d-ad1d-732b4efeddf5.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3cd630ea-017c-488d-ad1d-732b4efeddf5.png"/> </div><br>
### 3. 区别
@ -185,7 +185,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
## 进程状态的切换
<div align="center"> <img src="pics/ProcessState.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ProcessState.png" width="500"/> </div><br>
- 就绪状态ready等待被调度
- 运行状态running
@ -233,7 +233,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
- 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。
- 而如果时间片过长,那么实时性就不能得到保证。
<div align="center"> <img src="pics/8c662999-c16c-481c-9f40-1fdba5bc9167.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8c662999-c16c-481c-9f40-1fdba5bc9167.png"/> </div><br>
**2.2 优先级调度**
@ -251,7 +251,7 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。
<div align="center"> <img src="pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png"/> </div><br>
### 3. 实时系统
@ -570,7 +570,7 @@ void reader()
### 2. 哲学家进餐问题
<div align="center"> <img src="pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg"/> </div><br>
五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。
@ -664,7 +664,7 @@ int pipe(int fd[2]);
- 只支持半双工通信(单向交替传输);
- 只能在父子进程中使用。
<div align="center"> <img src="pics/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png"/> </div><br>
### 2. FIFO
@ -678,7 +678,7 @@ int mkfifoat(int fd, const char *path, mode_t mode);
FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。
<div align="center"> <img src="pics/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png"/> </div><br>
### 3. 消息队列
@ -708,7 +708,7 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
## 必要条件
<div align="center"> <img src="pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png"/> </div><br>
- 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。
- 占有和等待:已经得到了某个资源的进程可以再请求新的资源。
@ -740,7 +740,7 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
### 1. 每种类型一个资源的死锁检测
<div align="center"> <img src="pics/b1fa0453-a4b0-4eae-a352-48acca8fff74.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b1fa0453-a4b0-4eae-a352-48acca8fff74.png"/> </div><br>
上图为资源分配图,其中方框表示资源,圆圈表示进程。资源指向进程表示该资源已经分配给该进程,进程指向资源表示进程请求获取该资源。
@ -750,7 +750,7 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
### 2. 每种类型多个资源的死锁检测
<div align="center"> <img src="pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png"/> </div><br>
上图中,有三个进程四个资源,每个数据代表的含义如下:
@ -799,7 +799,7 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
### 1. 安全状态
<div align="center"> <img src="pics/ed523051-608f-4c3f-b343-383e2d194470.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ed523051-608f-4c3f-b343-383e2d194470.png"/> </div><br>
图 a 的第二列 Has 表示已拥有的资源数,第三列 Max 表示总共需要的资源数Free 表示还有可以使用的资源数。从图 a 开始出发,先让 B 拥有所需的所有资源(图 b运行结束后释放 B此时 Free 变为 5图 c接着以同样的方式运行 C 和 A使得所有进程都能成功运行因此可以称图 a 所示的状态时安全的。
@ -811,13 +811,13 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,算法要做的是判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求;否则予以分配。
<div align="center"> <img src="pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png"/> </div><br>
上图 c 为不安全状态,因此算法会拒绝之前的请求,从而避免进入图 c 中的状态。
### 3. 多个资源的银行家算法
<div align="center"> <img src="pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png"/> </div><br>
上图中有五个进程,四个资源。左边的图表示已经分配的资源,右边的图表示还需要分配的资源。最右边的 E、P 以及 A 分别表示:总资源、已分配资源以及可用资源,注意这三个为向量,而不是具体数值,例如 A=(1020),表示 4 个资源分别还剩下 1/0/2/0。
@ -839,7 +839,7 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0\~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。
<div align="center"> <img src="pics/7b281b1e-0595-402b-ae35-8c91084c33c1.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7b281b1e-0595-402b-ae35-8c91084c33c1.png"/> </div><br>
## 分页系统地址映射
@ -849,7 +849,7 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址0010 000000000100前 4 位是存储页面号 2读取表项内容为110 1页表项最后一位表示是否存在于内存中1 表示存在。后 12 位存储偏移量。这个页对应的页框的地址为 110 000000000100
<div align="center"> <img src="pics/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png" width="500"/> </div><br>
## 页面置换算法
@ -885,7 +885,7 @@ FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户
<div align="center"><img src="https://latex.codecogs.com/gif.latex?47071012126"/></div> <br>
<div align="center"> <img src="pics/eb859228-c0f2-4bce-910d-d9f76929352b.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png"/> </div><br>
### 3. 最近未使用
@ -916,7 +916,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候检查最老页面的 R 位。如果 R 位是 0那么这个页面既老又没有被使用可以立刻置换掉如果是 1就将 R 位清 0并把该页面放到链表的尾端修改它的装入时间使它就像刚装入的一样然后继续从链表的头部开始搜索。
<div align="center"> <img src="pics/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png"/> </div><br>
### 6. 时钟
@ -924,7 +924,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。
<div align="center"> <img src="pics/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png"/> </div><br>
## 分段
@ -932,11 +932,11 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
下图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。
<div align="center"> <img src="pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png"/> </div><br>
分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。
<div align="center"> <img src="pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png"/> </div><br>
## 段页式
@ -963,7 +963,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
- 制动手臂Actuator arm用于在磁道之间移动磁头
- 主轴Spindle使整个盘面转动。
<div align="center"> <img src="pics/014fbc4d-d873-4a12-b160-867ddaed9807.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/014fbc4d-d873-4a12-b160-867ddaed9807.jpg"/> </div><br>
## 磁盘调度算法
@ -991,7 +991,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现饥饿现象。具体来说,两端的磁道请求更容易出现饥饿现象。
<div align="center"> <img src="pics/4e2485e4-34bd-4967-9f02-0c093b797aaa.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4e2485e4-34bd-4967-9f02-0c093b797aaa.png"/> </div><br>
### 3. 电梯算法
@ -1003,7 +1003,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。
<div align="center"> <img src="pics/271ce08f-c124-475f-b490-be44fedc6d2e.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/271ce08f-c124-475f-b490-be44fedc6d2e.png"/> </div><br>
# 六、链接
@ -1029,7 +1029,7 @@ gcc -o hello hello.c
这个过程大致如下:
<div align="center"> <img src="pics/b396d726-b75f-4a32-89a2-03a7b6e19f6f.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b396d726-b75f-4a32-89a2-03a7b6e19f6f.jpg" width="800"/> </div><br>
- 预处理阶段:处理以 # 开头的预处理命令;
- 编译阶段:翻译成汇编文件;
@ -1043,7 +1043,7 @@ gcc -o hello hello.c
- 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。
- 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。
<div align="center"> <img src="pics/47d98583-8bb0-45cc-812d-47eefa0a4a40.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/47d98583-8bb0-45cc-812d-47eefa0a4a40.jpg"/> </div><br>
## 目标文件
@ -1063,7 +1063,7 @@ gcc -o hello hello.c
- 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中;
- 在内存中,一个共享库的 .text 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。
<div align="center"> <img src="pics/76dc7769-1aac-4888-9bea-064f1caa8e77.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/76dc7769-1aac-4888-9bea-064f1caa8e77.jpg"/> </div><br>
# 参考资料

View File

@ -23,13 +23,13 @@
# UDP 首部格式
<div align="center"> <img src="pics/d4c3a4a1-0846-46ec-9cc3-eaddfca71254.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d4c3a4a1-0846-46ec-9cc3-eaddfca71254.jpg" width="600"/> </div><br>
首部字段只有 8 个字节包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。
# TCP 首部格式
<div align="center"> <img src="pics/55dc4e84-573d-4c13-a765-52ed1dd251f9.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/55dc4e84-573d-4c13-a765-52ed1dd251f9.png" width="700"/> </div><br>
- **序号** :用于对字节流进行编号,例如序号为 301表示第一个字节的编号为 301如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。
@ -47,7 +47,7 @@
# TCP 的三次握手
<div align="center"> <img src="pics/e92d0ebc-7d46-413b-aec1-34a39602f787.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e92d0ebc-7d46-413b-aec1-34a39602f787.png" width="600"/> </div><br>
假设 A 为客户端B 为服务器端。
@ -69,7 +69,7 @@
# TCP 的四次挥手
<div align="center"> <img src="pics/f87afe72-c2df-4c12-ac03-9b8d581a8af8.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f87afe72-c2df-4c12-ac03-9b8d581a8af8.jpg" width="600"/> </div><br>
以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK因为 ACK 在连接建立之后都为 1。
@ -119,7 +119,7 @@ TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文
接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {34, 35} 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。
<div align="center"> <img src="pics/a3253deb-8d21-40a1-aae4-7d178e4aa319.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a3253deb-8d21-40a1-aae4-7d178e4aa319.jpg" width="800"/> </div><br>
# TCP 流量控制
@ -131,7 +131,7 @@ TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文
如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
<div align="center"> <img src="pics/51e2ed95-65b8-4ae9-8af3-65602d452a25.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/51e2ed95-65b8-4ae9-8af3-65602d452a25.jpg" width="500"/> </div><br>
TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
@ -142,7 +142,7 @@ TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、
- 接收方有足够大的接收缓存,因此不会发生流量控制;
- 虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。
<div align="center"> <img src="pics/910f613f-514f-4534-87dd-9b4699d59d31.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/910f613f-514f-4534-87dd-9b4699d59d31.png" width="800"/> </div><br>
## 1. 慢开始与拥塞避免
@ -162,7 +162,7 @@ TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、
慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1而快恢复 cwnd 设定为 ssthresh。
<div align="center"> <img src="pics/f61b5419-c94a-4df1-8d4d-aed9ae8cc6d5.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f61b5419-c94a-4df1-8d4d-aed9ae8cc6d5.png" width="600"/> </div><br>

View File

@ -22,7 +22,7 @@ DNS 是一个分布式数据库,提供了主机名和 IP 地址之间相互转
域名具有层次结构,从上到下依次为:根域名、顶级域名、二级域名。
<div align="center"> <img src="pics/b54eeb16-0b0e-484c-be62-306f57c40d77.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b54eeb16-0b0e-484c-be62-306f57c40d77.jpg"/> </div><br>
DNS 可以使用 UDP 或者 TCP 进行传输,使用的端口号都为 53。大多数情况下 DNS 使用 UDP 进行传输,这就要求域名解析器和域名服务器都必须自己处理超时和重传来保证可靠性。在两种情况下会使用 TCP 进行传输:
@ -40,11 +40,11 @@ FTP 使用 TCP 进行连接,它需要两个连接来传送一个文件:
- 主动模式:服务器端主动建立数据连接,其中服务器端的端口号为 20客户端的端口号随机但是必须大于 1024因为 0\~1023 是熟知端口号。
<div align="center"> <img src="pics/03f47940-3843-4b51-9e42-5dcaff44858b.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/03f47940-3843-4b51-9e42-5dcaff44858b.jpg"/> </div><br>
- 被动模式:客户端主动建立数据连接,其中客户端的端口号由客户端自己指定,服务器端的端口号随机。
<div align="center"> <img src="pics/be5c2c61-86d2-4dba-a289-b48ea23219de.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/be5c2c61-86d2-4dba-a289-b48ea23219de.jpg"/> </div><br>
主动模式要求客户端开放端口号给服务器端,需要去配置客户端的防火墙。被动模式只需要服务器端开放端口号即可,无需客户端配置防火墙。但是被动模式会导致服务器端的安全性减弱,因为开放了过多的端口号。
@ -61,7 +61,7 @@ DHCP 工作过程如下:
3. 如果客户端选择了某个 DHCP 服务器提供的信息,那么就发送 Request 报文给该 DHCP 服务器。
4. DHCP 服务器发送 Ack 报文,表示客户端此时可以使用提供给它的信息。
<div align="center"> <img src="pics/bf16c541-0717-473b-b75d-4115864f4fbf.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bf16c541-0717-473b-b75d-4115864f4fbf.jpg"/> </div><br>
# 远程登录协议
@ -75,13 +75,13 @@ TELNET 可以适应许多计算机和操作系统的差异,例如不同操作
邮件协议包含发送协议和读取协议,发送协议常用 SMTP读取协议常用 POP3 和 IMAP。
<div align="center"> <img src="pics/7b3efa99-d306-4982-8cfb-e7153c33aab4.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7b3efa99-d306-4982-8cfb-e7153c33aab4.png" width="700"/> </div><br>
## 1. SMTP
SMTP 只能发送 ASCII 码,而互联网邮件扩充 MIME 可以发送二进制文件。MIME 并没有改动或者取代 SMTP而是增加邮件主体的结构定义了非 ASCII 码的编码规则。
<div align="center"> <img src="pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png" width=""/> </div><br>
## 2. POP3

View File

@ -22,27 +22,27 @@
网络把主机连接起来,而互联网是把多种不同的网络连接起来,因此互联网是网络的网络。
<div align="center"> <img src="pics/network-of-networks.gif" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/network-of-networks.gif" width="450"/> </div><br>
# ISP
互联网服务提供商 ISP 可以从互联网管理机构获得许多 IP 地址,同时拥有通信线路以及路由器等联网设备,个人或机构向 ISP 缴纳一定的费用就可以接入互联网。
<div align="center"> <img src="pics/7_2001550811502556.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7_2001550811502556.png" width="500"/> </div><br>
目前的互联网是一种多层次 ISP 结构ISP 根据覆盖面积的大小分为第一层 ISP、区域 ISP 和接入 ISP。互联网交换点 IXP 允许两个 ISP 直接相连而不用经过第三个 ISP。
<div align="center"> <img src="pics/8_2001550812038190.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8_2001550812038190.png" width="500"/> </div><br>
# 主机之间的通信方式
- 客户-服务器C/S客户是服务的请求方服务器是服务的提供方。
<div align="center"> <img src="pics/2_2001550810366269.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550810366269.png"/> </div><br>
- 对等P2P不区分客户和服务器。
<div align="center"> <img src="pics/3_2001550810442775.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3_2001550810442775.png"/> </div><br>
# 电路交换与分组交换
@ -60,7 +60,7 @@
总时延 = 排队时延 + 处理时延 + 传输时延 + 传播时延
<div align="center"> <img src="pics/4_2001550810732828.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4_2001550810732828.png" width="600"/> </div><br>
## 1. 排队时延
@ -88,7 +88,7 @@
# 计算机网络体系结构
<div align="center"> <img src="pics/f5d40b01-abf2-435e-9ce7-7889c41b2fa6.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f5d40b01-abf2-435e-9ce7-7889c41b2fa6.jpg" width="500"/> </div><br>
## 1. 五层协议
@ -119,7 +119,7 @@
TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接使用 IP 层或者网络接口层。
<div align="center"> <img src="pics/6_2001550811175246.png" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6_2001550811175246.png" width="250"/> </div><br>
## 4. 数据在各层之间的传递过程

View File

@ -16,7 +16,7 @@
模拟信号是连续的信号,数字信号是离散的信号。带通调制把数字信号转换为模拟信号。
<div align="center"> <img src="pics/c34f4503-f62c-4043-9dc6-3e03288657df.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c34f4503-f62c-4043-9dc6-3e03288657df.jpg" width="500"/> </div><br>

View File

@ -26,7 +26,7 @@
使用 IP 协议,可以把异构的物理网络连接起来,使得在网络层看起来好像是一个统一的网络。
<div align="center"> <img src="pics/e3b53605-0c10-4a7e-be02-a9064778f8a5.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3b53605-0c10-4a7e-be02-a9064778f8a5.png" width="800"/> </div><br>
与 IP 协议配套使用的还有三个协议:
@ -36,7 +36,7 @@
# IP 数据报格式
<div align="center"> <img src="pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg" width="700"/> </div><br>
- **版本** : 有 4IPv4和 6IPv6两个值
@ -56,7 +56,7 @@
- **片偏移** : 和标识符一起,用于发生分片的情况。片偏移的单位为 8 字节。
<div align="center"> <img src="pics/23ba890e-e11c-45e2-a20c-64d217f83430.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png" width="700"/> </div><br>
# IP 地址编址方式
@ -72,7 +72,7 @@ IP 地址的编址方式经历了三个历史阶段:
IP 地址 ::= {< 网络号 >, < 主机号 >}
<div align="center"> <img src="pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png" width="500"/> </div><br>
## 2. 子网划分
@ -102,27 +102,27 @@ CIDR 的地址掩码可以继续称为子网掩码,子网掩码首 1 长度为
网络层实现主机之间的通信而链路层实现具体每段链路之间的通信。因此在通信过程中IP 数据报的源地址和目的地址始终不变,而 MAC 地址随着链路的改变而改变。
<div align="center"> <img src="pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg" width="700"/> </div><br>
ARP 实现由 IP 地址得到 MAC 地址。
<div align="center"> <img src="pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg" width="500"/> </div><br>
每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到 MAC 地址的映射表。
如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到 MAC 地址的映射。
<div align="center"> <img src="pics/8006a450-6c2f-498c-a928-c927f758b1d0.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png" width="700"/> </div><br>
# 网际控制报文协议 ICMP
ICMP 是为了更有效地转发 IP 数据报和提高交付成功的机会。它封装在 IP 数据报中,但是不属于高层协议。
<div align="center"> <img src="pics/e3124763-f75e-46c3-ba82-341e6c98d862.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3124763-f75e-46c3-ba82-341e6c98d862.jpg" width="500"/> </div><br>
ICMP 报文分为差错报告报文和询问报文。
<div align="center"> <img src="pics/aa29cc88-7256-4399-8c7f-3cf4a6489559.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/aa29cc88-7256-4399-8c7f-3cf4a6489559.png" width="600"/> </div><br>
## 1. Ping
@ -155,7 +155,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
下图中,场所 A 和 B 的通信经过互联网,如果场所 A 的主机 X 要和另一个场所 B 的主机 Y 通信IP 数据报的源地址是 10.1.0.1,目的地址是 10.2.0.3。数据报先发送到与互联网相连的路由器 R1R1 对内部数据进行加密,然后重新加上数据报的首部,源地址是路由器 R1 的全球地址 125.1.2.3,目的地址是路由器 R2 的全球地址 194.4.5.6。路由器 R2 收到数据报后将数据部分进行解密,恢复原来的数据报,此时目的地址为 10.2.0.3,就交付给 Y。
<div align="center"> <img src="pics/1556770b-8c01-4681-af10-46f1df69202c.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1556770b-8c01-4681-af10-46f1df69202c.jpg" width="800"/> </div><br>
# 网络地址转换 NAT
@ -163,7 +163,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
在以前NAT 将本地 IP 和全球 IP 一一对应,这种方式下拥有 n 个全球 IP 地址的专用网内最多只可以同时有 n 台主机接入互联网。为了更有效地利用全球 IP 地址,现在常用的 NAT 转换表把传输层的端口号也用上了,使得多个专用网内部的主机共用一个全球 IP 地址。使用端口号的 NAT 也叫做网络地址与端口转换 NAPT。
<div align="center"> <img src="pics/2719067e-b299-4639-9065-bed6729dbf0b.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2719067e-b299-4639-9065-bed6729dbf0b.png" width=""/> </div><br>
# 路由器的结构
@ -171,7 +171,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
分组转发结构由三个部分组成:交换结构、一组输入端口和一组输出端口。
<div align="center"> <img src="pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg" width="600"/> </div><br>
# 路由器分组转发流程
@ -182,7 +182,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
- 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;
- 报告转发分组出错。
<div align="center"> <img src="pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg" width="800"/> </div><br>
# 路由选择协议
@ -239,7 +239,7 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
每个 AS 都必须配置 BGP 发言人,通过在两个相邻 BGP 发言人之间建立 TCP 连接来交换路由信息。
<div align="center"> <img src="pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png" width="600"/> </div><br>

View File

@ -28,7 +28,7 @@
将网络层传下来的分组添加首部和尾部,用于标记帧的开始和结束。
<div align="center"> <img src="pics/9c60793f-5e7f-453b-8413-35890c24abc4.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9c60793f-5e7f-453b-8413-35890c24abc4.png" width="500"/> </div><br>
## 2. 透明传输
@ -36,7 +36,7 @@
帧使用首部和尾部进行定界,如果帧的数据部分含有和首部尾部相同的内容,那么帧的开始和结束位置就会被错误的判定。需要在数据部分出现首部尾部相同的内容前面插入转义字符。如果数据部分出现转义字符,那么就在转义字符前面再加个转义字符。在接收端进行处理之后可以还原出原始数据。这个过程透明传输的内容是转义字符,用户察觉不到转义字符的存在。
<div align="center"> <img src="pics/839207f5-52fd-4516-9370-956dcdf2c2b5.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/839207f5-52fd-4516-9370-956dcdf2c2b5.png" width="600"/> </div><br>
## 3. 差错检测
@ -64,13 +64,13 @@
频分复用的所有主机在相同的时间占用不同的频率带宽资源。
<div align="center"> <img src="pics/7e6cb8fc-1b82-4135-8b03-ebcfc546d94c.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7e6cb8fc-1b82-4135-8b03-ebcfc546d94c.png" width="450"/> </div><br>
## 2. 时分复用
时分复用的所有主机在不同的时间占用相同的频率带宽资源。
<div align="center"> <img src="pics/49e53613-46f8-4308-9ee5-c09d62367577.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/49e53613-46f8-4308-9ee5-c09d62367577.png" width="450"/> </div><br>
使用频分复用和时分复用进行通信,在通信的过程中主机会一直占用一部分信道资源。但是由于计算机数据的突发性质,通信过程没必要一直占用信道资源而不让出给其它用户使用,因此这两种方式对信道的利用率都不高。
@ -78,7 +78,7 @@
是对时分复用的一种改进,不固定每个用户在时分复用帧中的位置,只要有数据就集中起来组成统计时分复用帧然后发送。
<div align="center"> <img src="pics/e3360fa0-680e-486b-945f-09ff5d8612e4.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3360fa0-680e-486b-945f-09ff5d8612e4.png" width="450"/> </div><br>
## 4. 波分复用
@ -104,7 +104,7 @@
码分复用需要发送的数据量为原先的 m 倍。
<div align="center"> <img src="pics/c7875be7-fce5-43c7-ac77-d8dbe6c0ae1b.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c7875be7-fce5-43c7-ac77-d8dbe6c0ae1b.png" width="600"/> </div><br>
# CSMA/CD 协议
@ -118,13 +118,13 @@ CSMA/CD 表示载波监听多点接入 / 碰撞检测。
当发生碰撞时,站点要停止发送,等待一段时间再发送。这个时间采用 **截断二进制指数退避算法** 来确定。从离散的整数集合 {0, 1, .., (2<sup>k</sup>-1)} 中随机取出一个数,记作 r然后取 r 倍的争用期作为重传等待时间。
<div align="center"> <img src="pics/9bd12b89-f99c-49f4-ae45-410f76a713d6.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9bd12b89-f99c-49f4-ae45-410f76a713d6.png" width="500"/> </div><br>
# PPP 协议
互联网用户通常需要连接到某个 ISP 之后才能接入到互联网PPP 协议是用户计算机和 ISP 进行通信时所使用的数据链路层协议。
<div align="center"> <img src="pics/2f237854-bb35-4c57-a7fe-ab2ab144f56e.jpg" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2f237854-bb35-4c57-a7fe-ab2ab144f56e.jpg" width="300"/> </div><br>
PPP 的帧格式:
@ -133,7 +133,7 @@ PPP 的帧格式:
- FCS 字段是使用 CRC 的检验序列
- 信息部分的长度不超过 1500
<div align="center"> <img src="pics/63010737-2cb4-48f3-999f-09194481b227.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/63010737-2cb4-48f3-999f-09194481b227.png" width="500"/> </div><br>
# MAC 地址
@ -149,7 +149,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
可以按照网络拓扑结构对局域网进行分类:
<div align="center"> <img src="pics/df01dbcd-4a3c-4877-86e8-5590d7589788.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/df01dbcd-4a3c-4877-86e8-5590d7589788.jpg" width="800"/> </div><br>
# 以太网
@ -165,7 +165,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
- **数据** :长度在 46-1500 之间,如果太小则需要填充;
- **FCS** :帧检验序列,使用的是 CRC 检验方法;
<div align="center"> <img src="pics/420f4dc0-6c4b-486c-afea-274299014462.png" width="550"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/420f4dc0-6c4b-486c-afea-274299014462.png" width="550"/> </div><br>
# 交换机
@ -175,7 +175,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
下图中,交换机有 4 个接口,主机 A 向主机 B 发送数据帧时,交换机把主机 A 到接口 1 的映射写入交换表中。为了发送数据帧到 B先查交换表此时没有主机 B 的表项,那么主机 A 就发送广播帧,主机 C 和主机 D 会丢弃该帧,主机 B 回应该帧向主机 A 发送数据包时,交换机查找交换表得到主机 A 映射的接口为 1就发送数据帧到接口 1同时交换机添加主机 B 到接口 2 的映射。
<div align="center"> <img src="pics/80646c77-1f32-484c-810e-af80ce00f902.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/80646c77-1f32-484c-810e-af80ce00f902.png" width="800"/> </div><br>
# 虚拟局域网
@ -185,7 +185,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
使用 VLAN 干线连接来建立虚拟局域网,每台交换机上的一个特殊接口被设置为干线接口,以互连 VLAN 交换机。IEEE 定义了一种扩展的以太网帧格式 802.1Q,它在标准以太网帧上加进了 4 字节首部 VLAN 标签,用于表示该帧属于哪一个虚拟局域网。
<div align="center"> <img src="pics/99208bd0-1454-4618-9969-0c2deb8bba0f.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/99208bd0-1454-4618-9969-0c2deb8bba0f.png" width="500"/> </div><br>

View File

@ -59,27 +59,27 @@
网络把主机连接起来,而互联网是把多种不同的网络连接起来,因此互联网是网络的网络。
<div align="center"> <img src="pics/network-of-networks.gif" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/network-of-networks.gif" width="450"/> </div><br>
## ISP
互联网服务提供商 ISP 可以从互联网管理机构获得许多 IP 地址,同时拥有通信线路以及路由器等联网设备,个人或机构向 ISP 缴纳一定的费用就可以接入互联网。
<div align="center"> <img src="pics/7_2001550811502556.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7_2001550811502556.png" width="500"/> </div><br>
目前的互联网是一种多层次 ISP 结构ISP 根据覆盖面积的大小分为第一层 ISP、区域 ISP 和接入 ISP。互联网交换点 IXP 允许两个 ISP 直接相连而不用经过第三个 ISP。
<div align="center"> <img src="pics/8_2001550812038190.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8_2001550812038190.png" width="500"/> </div><br>
## 主机之间的通信方式
- 客户-服务器C/S客户是服务的请求方服务器是服务的提供方。
<div align="center"> <img src="pics/2_2001550810366269.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550810366269.png"/> </div><br>
- 对等P2P不区分客户和服务器。
<div align="center"> <img src="pics/3_2001550810442775.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3_2001550810442775.png"/> </div><br>
## 电路交换与分组交换
@ -97,7 +97,7 @@
总时延 = 排队时延 + 处理时延 + 传输时延 + 传播时延
<div align="center"> <img src="pics/4_2001550810732828.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4_2001550810732828.png" width="600"/> </div><br>
### 1. 排队时延
@ -125,7 +125,7 @@
## 计算机网络体系结构
<div align="center"> <img src="pics/f5d40b01-abf2-435e-9ce7-7889c41b2fa6.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f5d40b01-abf2-435e-9ce7-7889c41b2fa6.jpg" width="500"/> </div><br>
### 1. 五层协议
@ -156,7 +156,7 @@
TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接使用 IP 层或者网络接口层。
<div align="center"> <img src="pics/6_2001550811175246.png" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6_2001550811175246.png" width="250"/> </div><br>
### 4. 数据在各层之间的传递过程
@ -178,7 +178,7 @@ TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接
模拟信号是连续的信号,数字信号是离散的信号。带通调制把数字信号转换为模拟信号。
<div align="center"> <img src="pics/c34f4503-f62c-4043-9dc6-3e03288657df.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c34f4503-f62c-4043-9dc6-3e03288657df.jpg" width="500"/> </div><br>
# 三、数据链路层
@ -188,7 +188,7 @@ TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接
将网络层传下来的分组添加首部和尾部,用于标记帧的开始和结束。
<div align="center"> <img src="pics/9c60793f-5e7f-453b-8413-35890c24abc4.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9c60793f-5e7f-453b-8413-35890c24abc4.png" width="500"/> </div><br>
### 2. 透明传输
@ -196,7 +196,7 @@ TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接
帧使用首部和尾部进行定界,如果帧的数据部分含有和首部尾部相同的内容,那么帧的开始和结束位置就会被错误的判定。需要在数据部分出现首部尾部相同的内容前面插入转义字符。如果数据部分出现转义字符,那么就在转义字符前面再加个转义字符。在接收端进行处理之后可以还原出原始数据。这个过程透明传输的内容是转义字符,用户察觉不到转义字符的存在。
<div align="center"> <img src="pics/839207f5-52fd-4516-9370-956dcdf2c2b5.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/839207f5-52fd-4516-9370-956dcdf2c2b5.png" width="600"/> </div><br>
### 3. 差错检测
@ -224,13 +224,13 @@ TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接
频分复用的所有主机在相同的时间占用不同的频率带宽资源。
<div align="center"> <img src="pics/7e6cb8fc-1b82-4135-8b03-ebcfc546d94c.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7e6cb8fc-1b82-4135-8b03-ebcfc546d94c.png" width="450"/> </div><br>
### 2. 时分复用
时分复用的所有主机在不同的时间占用相同的频率带宽资源。
<div align="center"> <img src="pics/49e53613-46f8-4308-9ee5-c09d62367577.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/49e53613-46f8-4308-9ee5-c09d62367577.png" width="450"/> </div><br>
使用频分复用和时分复用进行通信,在通信的过程中主机会一直占用一部分信道资源。但是由于计算机数据的突发性质,通信过程没必要一直占用信道资源而不让出给其它用户使用,因此这两种方式对信道的利用率都不高。
@ -238,7 +238,7 @@ TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接
是对时分复用的一种改进,不固定每个用户在时分复用帧中的位置,只要有数据就集中起来组成统计时分复用帧然后发送。
<div align="center"> <img src="pics/e3360fa0-680e-486b-945f-09ff5d8612e4.png" width="450"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3360fa0-680e-486b-945f-09ff5d8612e4.png" width="450"/> </div><br>
### 4. 波分复用
@ -264,7 +264,7 @@ TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接
码分复用需要发送的数据量为原先的 m 倍。
<div align="center"> <img src="pics/c7875be7-fce5-43c7-ac77-d8dbe6c0ae1b.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c7875be7-fce5-43c7-ac77-d8dbe6c0ae1b.png" width="600"/> </div><br>
## CSMA/CD 协议
@ -278,13 +278,13 @@ CSMA/CD 表示载波监听多点接入 / 碰撞检测。
当发生碰撞时,站点要停止发送,等待一段时间再发送。这个时间采用 **截断二进制指数退避算法** 来确定。从离散的整数集合 {0, 1, .., (2<sup>k</sup>-1)} 中随机取出一个数,记作 r然后取 r 倍的争用期作为重传等待时间。
<div align="center"> <img src="pics/9bd12b89-f99c-49f4-ae45-410f76a713d6.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9bd12b89-f99c-49f4-ae45-410f76a713d6.png" width="500"/> </div><br>
## PPP 协议
互联网用户通常需要连接到某个 ISP 之后才能接入到互联网PPP 协议是用户计算机和 ISP 进行通信时所使用的数据链路层协议。
<div align="center"> <img src="pics/2f237854-bb35-4c57-a7fe-ab2ab144f56e.jpg" width="300"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2f237854-bb35-4c57-a7fe-ab2ab144f56e.jpg" width="300"/> </div><br>
PPP 的帧格式:
@ -293,7 +293,7 @@ PPP 的帧格式:
- FCS 字段是使用 CRC 的检验序列
- 信息部分的长度不超过 1500
<div align="center"> <img src="pics/63010737-2cb4-48f3-999f-09194481b227.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/63010737-2cb4-48f3-999f-09194481b227.png" width="500"/> </div><br>
## MAC 地址
@ -309,7 +309,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
可以按照网络拓扑结构对局域网进行分类:
<div align="center"> <img src="pics/df01dbcd-4a3c-4877-86e8-5590d7589788.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/df01dbcd-4a3c-4877-86e8-5590d7589788.jpg" width="800"/> </div><br>
## 以太网
@ -325,7 +325,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
- **数据** :长度在 46-1500 之间,如果太小则需要填充;
- **FCS** :帧检验序列,使用的是 CRC 检验方法;
<div align="center"> <img src="pics/420f4dc0-6c4b-486c-afea-274299014462.png" width="550"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/420f4dc0-6c4b-486c-afea-274299014462.png" width="550"/> </div><br>
## 交换机
@ -335,7 +335,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
下图中,交换机有 4 个接口,主机 A 向主机 B 发送数据帧时,交换机把主机 A 到接口 1 的映射写入交换表中。为了发送数据帧到 B先查交换表此时没有主机 B 的表项,那么主机 A 就发送广播帧,主机 C 和主机 D 会丢弃该帧,主机 B 回应该帧向主机 A 发送数据包时,交换机查找交换表得到主机 A 映射的接口为 1就发送数据帧到接口 1同时交换机添加主机 B 到接口 2 的映射。
<div align="center"> <img src="pics/80646c77-1f32-484c-810e-af80ce00f902.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/80646c77-1f32-484c-810e-af80ce00f902.png" width="800"/> </div><br>
## 虚拟局域网
@ -345,7 +345,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
使用 VLAN 干线连接来建立虚拟局域网,每台交换机上的一个特殊接口被设置为干线接口,以互连 VLAN 交换机。IEEE 定义了一种扩展的以太网帧格式 802.1Q,它在标准以太网帧上加进了 4 字节首部 VLAN 标签,用于表示该帧属于哪一个虚拟局域网。
<div align="center"> <img src="pics/99208bd0-1454-4618-9969-0c2deb8bba0f.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/99208bd0-1454-4618-9969-0c2deb8bba0f.png" width="500"/> </div><br>
# 四、网络层
@ -355,7 +355,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
使用 IP 协议,可以把异构的物理网络连接起来,使得在网络层看起来好像是一个统一的网络。
<div align="center"> <img src="pics/e3b53605-0c10-4a7e-be02-a9064778f8a5.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3b53605-0c10-4a7e-be02-a9064778f8a5.png" width="800"/> </div><br>
与 IP 协议配套使用的还有三个协议:
@ -365,7 +365,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
## IP 数据报格式
<div align="center"> <img src="pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg" width="700"/> </div><br>
- **版本** : 有 4IPv4和 6IPv6两个值
@ -385,7 +385,7 @@ MAC 地址是链路层地址,长度为 6 字节48 位),用于唯一标
- **片偏移** : 和标识符一起,用于发生分片的情况。片偏移的单位为 8 字节。
<div align="center"> <img src="pics/23ba890e-e11c-45e2-a20c-64d217f83430.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png" width="700"/> </div><br>
## IP 地址编址方式
@ -401,7 +401,7 @@ IP 地址的编址方式经历了三个历史阶段:
IP 地址 ::= {< 网络号 >, < 主机号 >}
<div align="center"> <img src="pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png" width="500"/> </div><br>
### 2. 子网划分
@ -431,27 +431,27 @@ CIDR 的地址掩码可以继续称为子网掩码,子网掩码首 1 长度为
网络层实现主机之间的通信而链路层实现具体每段链路之间的通信。因此在通信过程中IP 数据报的源地址和目的地址始终不变,而 MAC 地址随着链路的改变而改变。
<div align="center"> <img src="pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg" width="700"/> </div><br>
ARP 实现由 IP 地址得到 MAC 地址。
<div align="center"> <img src="pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg" width="500"/> </div><br>
每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到 MAC 地址的映射表。
如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到 MAC 地址的映射。
<div align="center"> <img src="pics/8006a450-6c2f-498c-a928-c927f758b1d0.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png" width="700"/> </div><br>
## 网际控制报文协议 ICMP
ICMP 是为了更有效地转发 IP 数据报和提高交付成功的机会。它封装在 IP 数据报中,但是不属于高层协议。
<div align="center"> <img src="pics/e3124763-f75e-46c3-ba82-341e6c98d862.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3124763-f75e-46c3-ba82-341e6c98d862.jpg" width="500"/> </div><br>
ICMP 报文分为差错报告报文和询问报文。
<div align="center"> <img src="pics/aa29cc88-7256-4399-8c7f-3cf4a6489559.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/aa29cc88-7256-4399-8c7f-3cf4a6489559.png" width="600"/> </div><br>
### 1. Ping
@ -484,7 +484,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
下图中,场所 A 和 B 的通信经过互联网,如果场所 A 的主机 X 要和另一个场所 B 的主机 Y 通信IP 数据报的源地址是 10.1.0.1,目的地址是 10.2.0.3。数据报先发送到与互联网相连的路由器 R1R1 对内部数据进行加密,然后重新加上数据报的首部,源地址是路由器 R1 的全球地址 125.1.2.3,目的地址是路由器 R2 的全球地址 194.4.5.6。路由器 R2 收到数据报后将数据部分进行解密,恢复原来的数据报,此时目的地址为 10.2.0.3,就交付给 Y。
<div align="center"> <img src="pics/1556770b-8c01-4681-af10-46f1df69202c.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1556770b-8c01-4681-af10-46f1df69202c.jpg" width="800"/> </div><br>
## 网络地址转换 NAT
@ -492,7 +492,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
在以前NAT 将本地 IP 和全球 IP 一一对应,这种方式下拥有 n 个全球 IP 地址的专用网内最多只可以同时有 n 台主机接入互联网。为了更有效地利用全球 IP 地址,现在常用的 NAT 转换表把传输层的端口号也用上了,使得多个专用网内部的主机共用一个全球 IP 地址。使用端口号的 NAT 也叫做网络地址与端口转换 NAPT。
<div align="center"> <img src="pics/2719067e-b299-4639-9065-bed6729dbf0b.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2719067e-b299-4639-9065-bed6729dbf0b.png" width=""/> </div><br>
## 路由器的结构
@ -500,7 +500,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
分组转发结构由三个部分组成:交换结构、一组输入端口和一组输出端口。
<div align="center"> <img src="pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg" width="600"/> </div><br>
## 路由器分组转发流程
@ -511,7 +511,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。
- 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;
- 报告转发分组出错。
<div align="center"> <img src="pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg" width="800"/> </div><br>
## 路由选择协议
@ -568,7 +568,7 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
每个 AS 都必须配置 BGP 发言人,通过在两个相邻 BGP 发言人之间建立 TCP 连接来交换路由信息。
<div align="center"> <img src="pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png" width="600"/> </div><br>
# 五、传输层
@ -582,13 +582,13 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
## UDP 首部格式
<div align="center"> <img src="pics/d4c3a4a1-0846-46ec-9cc3-eaddfca71254.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d4c3a4a1-0846-46ec-9cc3-eaddfca71254.jpg" width="600"/> </div><br>
首部字段只有 8 个字节包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。
## TCP 首部格式
<div align="center"> <img src="pics/55dc4e84-573d-4c13-a765-52ed1dd251f9.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/55dc4e84-573d-4c13-a765-52ed1dd251f9.png" width="700"/> </div><br>
- **序号** :用于对字节流进行编号,例如序号为 301表示第一个字节的编号为 301如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。
@ -606,7 +606,7 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
## TCP 的三次握手
<div align="center"> <img src="pics/e92d0ebc-7d46-413b-aec1-34a39602f787.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e92d0ebc-7d46-413b-aec1-34a39602f787.png" width="600"/> </div><br>
假设 A 为客户端B 为服务器端。
@ -628,7 +628,7 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。
## TCP 的四次挥手
<div align="center"> <img src="pics/f87afe72-c2df-4c12-ac03-9b8d581a8af8.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f87afe72-c2df-4c12-ac03-9b8d581a8af8.jpg" width="600"/> </div><br>
以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK因为 ACK 在连接建立之后都为 1。
@ -678,7 +678,7 @@ TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文
接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {34, 35} 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。
<div align="center"> <img src="pics/a3253deb-8d21-40a1-aae4-7d178e4aa319.jpg" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a3253deb-8d21-40a1-aae4-7d178e4aa319.jpg" width="800"/> </div><br>
## TCP 流量控制
@ -690,7 +690,7 @@ TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文
如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
<div align="center"> <img src="pics/51e2ed95-65b8-4ae9-8af3-65602d452a25.jpg" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/51e2ed95-65b8-4ae9-8af3-65602d452a25.jpg" width="500"/> </div><br>
TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
@ -701,7 +701,7 @@ TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、
- 接收方有足够大的接收缓存,因此不会发生流量控制;
- 虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。
<div align="center"> <img src="pics/910f613f-514f-4534-87dd-9b4699d59d31.png" width="800"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/910f613f-514f-4534-87dd-9b4699d59d31.png" width="800"/> </div><br>
### 1. 慢开始与拥塞避免
@ -721,7 +721,7 @@ TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、
慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1而快恢复 cwnd 设定为 ssthresh。
<div align="center"> <img src="pics/f61b5419-c94a-4df1-8d4d-aed9ae8cc6d5.png" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f61b5419-c94a-4df1-8d4d-aed9ae8cc6d5.png" width="600"/> </div><br>
# 六、应用层
@ -731,7 +731,7 @@ DNS 是一个分布式数据库,提供了主机名和 IP 地址之间相互转
域名具有层次结构,从上到下依次为:根域名、顶级域名、二级域名。
<div align="center"> <img src="pics/b54eeb16-0b0e-484c-be62-306f57c40d77.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b54eeb16-0b0e-484c-be62-306f57c40d77.jpg"/> </div><br>
DNS 可以使用 UDP 或者 TCP 进行传输,使用的端口号都为 53。大多数情况下 DNS 使用 UDP 进行传输,这就要求域名解析器和域名服务器都必须自己处理超时和重传来保证可靠性。在两种情况下会使用 TCP 进行传输:
@ -749,11 +749,11 @@ FTP 使用 TCP 进行连接,它需要两个连接来传送一个文件:
- 主动模式:服务器端主动建立数据连接,其中服务器端的端口号为 20客户端的端口号随机但是必须大于 1024因为 0\~1023 是熟知端口号。
<div align="center"> <img src="pics/03f47940-3843-4b51-9e42-5dcaff44858b.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/03f47940-3843-4b51-9e42-5dcaff44858b.jpg"/> </div><br>
- 被动模式:客户端主动建立数据连接,其中客户端的端口号由客户端自己指定,服务器端的端口号随机。
<div align="center"> <img src="pics/be5c2c61-86d2-4dba-a289-b48ea23219de.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/be5c2c61-86d2-4dba-a289-b48ea23219de.jpg"/> </div><br>
主动模式要求客户端开放端口号给服务器端,需要去配置客户端的防火墙。被动模式只需要服务器端开放端口号即可,无需客户端配置防火墙。但是被动模式会导致服务器端的安全性减弱,因为开放了过多的端口号。
@ -770,7 +770,7 @@ DHCP 工作过程如下:
3. 如果客户端选择了某个 DHCP 服务器提供的信息,那么就发送 Request 报文给该 DHCP 服务器。
4. DHCP 服务器发送 Ack 报文,表示客户端此时可以使用提供给它的信息。
<div align="center"> <img src="pics/bf16c541-0717-473b-b75d-4115864f4fbf.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bf16c541-0717-473b-b75d-4115864f4fbf.jpg"/> </div><br>
## 远程登录协议
@ -784,13 +784,13 @@ TELNET 可以适应许多计算机和操作系统的差异,例如不同操作
邮件协议包含发送协议和读取协议,发送协议常用 SMTP读取协议常用 POP3 和 IMAP。
<div align="center"> <img src="pics/7b3efa99-d306-4982-8cfb-e7153c33aab4.png" width="700"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7b3efa99-d306-4982-8cfb-e7153c33aab4.png" width="700"/> </div><br>
### 1. SMTP
SMTP 只能发送 ASCII 码,而互联网邮件扩充 MIME 可以发送二进制文件。MIME 并没有改动或者取代 SMTP而是增加邮件主体的结构定义了非 ASCII 码的编码规则。
<div align="center"> <img src="pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png" width=""/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png" width=""/> </div><br>
### 2. POP3

View File

@ -54,7 +54,7 @@
私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。
<div align="center"> <img src="pics/562f2844-d77c-40e0-887a-28a7128abd42.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/562f2844-d77c-40e0-887a-28a7128abd42.png"/> </div><br>
### Implementation
@ -255,7 +255,7 @@ secondName
这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。
<div align="center"> <img src="pics/c79da808-0f28-4a36-bc04-33ccc5b83c13.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c79da808-0f28-4a36-bc04-33ccc5b83c13.png"/> </div><br>
### Implementation
@ -338,7 +338,7 @@ public class Client {
下图中Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
<div align="center"> <img src="pics/1818e141-8700-4026-99f7-900a545875f5.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1818e141-8700-4026-99f7-900a545875f5.png"/> </div><br>
### Implementation
@ -402,7 +402,7 @@ public class ConcreteFactory2 extends Factory {
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory而工厂方法模式使用了继承。
<div align="center"> <img src="pics/8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png"/> </div><br>
### Implementation
@ -492,7 +492,7 @@ public class Client {
### Class Diagram
<div align="center"> <img src="pics/13b0940e-d1d7-4b17-af4f-b70cb0a75e08.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/13b0940e-d1d7-4b17-af4f-b70cb0a75e08.png"/> </div><br>
### Implementation
@ -582,7 +582,7 @@ abcdefghijklmnopqrstuvwxyz
### Class Diagram
<div align="center"> <img src="pics/a40661e4-1a71-46d2-a158-ff36f7fc3331.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a40661e4-1a71-46d2-a158-ff36f7fc3331.png"/> </div><br>
### Implementation
@ -643,7 +643,7 @@ abc
- Handler定义处理请求的接口并且实现后继链successor
<div align="center"> <img src="pics/691f11eb-31a7-46be-9de1-61f433c4b3c7.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/691f11eb-31a7-46be-9de1-61f433c4b3c7.png"/> </div><br>
### Implementation
@ -781,13 +781,13 @@ request2 is handle by ConcreteHandler2
- Invoker通过它来调用命令
- Client可以设置命令与命令的接收者
<div align="center"> <img src="pics/ae1b27b8-bc13-42e7-ac12-a2242e125499.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ae1b27b8-bc13-42e7-ac12-a2242e125499.png"/> </div><br>
### Implementation
设计一个遥控器,可以控制电灯开关。
<div align="center"> <img src="pics/e6bded8e-41a0-489a-88a6-638e88ab7666.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e6bded8e-41a0-489a-88a6-638e88ab7666.jpg"/> </div><br>
```java
public interface Command {
@ -902,7 +902,7 @@ public class Client {
- TerminalExpression终结符表达式每个终结符都需要一个 TerminalExpression。
- Context上下文包含解释器之外的一些全局信息。
<div align="center"> <img src="pics/794239e3-4baf-4aad-92df-f02f59b2a6fe.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/794239e3-4baf-4aad-92df-f02f59b2a6fe.png"/> </div><br>
### Implementation
@ -1027,7 +1027,7 @@ false
- Iterator 主要定义了 hasNext() 和 next() 方法。
- Client 组合了 Aggregate为了迭代遍历 Aggregate也需要组合 Iterator。
<div align="center"> <img src="pics/b0f61ac2-a4b6-4042-9cf0-ccf4238c1ff7.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b0f61ac2-a4b6-4042-9cf0-ccf4238c1ff7.png"/> </div><br>
### Implementation
@ -1116,17 +1116,17 @@ public class Client {
- Mediator中介者定义一个接口用于与各同事Colleague对象通信。
- Colleague同事相关对象
<div align="center"> <img src="pics/d0afdd23-c9a5-4d1c-9b3d-404bff3bd0d1.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d0afdd23-c9a5-4d1c-9b3d-404bff3bd0d1.png"/> </div><br>
### Implementation
Alarm闹钟、CoffeePot咖啡壶、Calendar日历、Sprinkler喷头是一组相关的对象在某个对象的事件产生时需要去操作其它对象形成了下面这种依赖结构
<div align="center"> <img src="pics/82cfda3b-b53b-4c89-9fdb-26dd2db0cd02.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/82cfda3b-b53b-4c89-9fdb-26dd2db0cd02.jpg"/> </div><br>
使用中介者模式可以将复杂的依赖结构变成星形结构:
<div align="center"> <img src="pics/5359cbf5-5a79-4874-9b17-f23c53c2cb80.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5359cbf5-5a79-4874-9b17-f23c53c2cb80.jpg"/> </div><br>
```java
public abstract class Colleague {
@ -1286,7 +1286,7 @@ doSprinkler()
- Caretaker负责保存好备忘录
- Menento备忘录存储原始对象的的状态。备忘录实际上有两个接口一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
<div align="center"> <img src="pics/867e93eb-3161-4f39-b2d2-c0cd3788e194.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/867e93eb-3161-4f39-b2d2-c0cd3788e194.png"/> </div><br>
### Implementation
@ -1459,7 +1459,7 @@ public class Client {
主题Subject是被观察的对象而其所有依赖者Observer称为观察者。
<div align="center"> <img src="pics/7a3c6a30-c735-4edb-8115-337288a4f0f2.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7a3c6a30-c735-4edb-8115-337288a4f0f2.jpg" width="600"/> </div><br>
### Class Diagram
@ -1467,13 +1467,13 @@ public class Client {
观察者Observer的注册功能需要调用主题的 registerObserver() 方法。
<div align="center"> <img src="pics/0df5d84c-e7ca-4e3a-a688-bb8e68894467.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0df5d84c-e7ca-4e3a-a688-bb8e68894467.png"/> </div><br>
### Implementation
天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。
<div align="center"> <img src="pics/b1df9732-86ce-4d69-9f06-fba1db7b3b5a.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b1df9732-86ce-4d69-9f06-fba1db7b3b5a.jpg"/> </div><br>
```java
public interface Subject {
@ -1594,13 +1594,13 @@ StatisticsDisplay.update: 1.0 1.0 1.0
### Class Diagram
<div align="center"> <img src="pics/c5085437-54df-4304-b62d-44b961711ba7.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c5085437-54df-4304-b62d-44b961711ba7.png"/> </div><br>
### Implementation
糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。
<div align="center"> <img src="pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg" width="600"/> </div><br>
```java
public interface State {
@ -1901,7 +1901,7 @@ No gumball dispensed
- Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior()setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。
<div align="center"> <img src="pics/1fc969e4-0e7c-441b-b53c-01950d2f2be5.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1fc969e4-0e7c-441b-b53c-01950d2f2be5.png"/> </div><br>
### 与状态模式的比较
@ -1988,13 +1988,13 @@ quack!
### Class Diagram
<div align="center"> <img src="pics/c3c1c0e8-3a78-4426-961f-b46dd0879dd8.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c3c1c0e8-3a78-4426-961f-b46dd0879dd8.png"/> </div><br>
### Implementation
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。
<div align="center"> <img src="pics/11236498-1417-46ce-a1b0-e10054256955.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/11236498-1417-46ce-a1b0-e10054256955.png"/> </div><br>
```java
public abstract class CaffeineBeverage {
@ -2091,7 +2091,7 @@ Tea.addCondiments
- ConcreteVisitor具体访问者存储遍历过程中的累计结果
- ObjectStructure对象结构可以是组合结构或者是一个集合。
<div align="center"> <img src="pics/ec923dc7-864c-47b0-a411-1f2c48d084de.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ec923dc7-864c-47b0-a411-1f2c48d084de.png"/> </div><br>
### Implementation
@ -2296,7 +2296,7 @@ Number of items: 6
### Class Diagram
<div align="center"> <img src="pics/dd3b289c-d90e-44a6-a44c-4880517eb1de.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/dd3b289c-d90e-44a6-a44c-4880517eb1de.png"/> </div><br>
### Implementation
@ -2348,11 +2348,11 @@ public class Client {
把一个类接口转换成另一个用户需要的接口。
<div align="center"> <img src="pics/3d5b828e-5c4d-48d8-a440-281e4a8e1c92.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3d5b828e-5c4d-48d8-a440-281e4a8e1c92.png"/> </div><br>
### Class Diagram
<div align="center"> <img src="pics/0889c0b4-07b4-45fc-873c-e0e16b97f67d.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0889c0b4-07b4-45fc-873c-e0e16b97f67d.png"/> </div><br>
### Implementation
@ -2424,7 +2424,7 @@ public class Client {
- Abstraction定义抽象类的接口
- Implementor定义实现类接口
<div align="center"> <img src="pics/c2cbf5d2-82af-4c78-bd43-495da5adf55f.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c2cbf5d2-82af-4c78-bd43-495da5adf55f.png"/> </div><br>
### Implementation
@ -2582,7 +2582,7 @@ public class Client {
组合对象拥有一个或者多个组件对象,因此组合对象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。
<div align="center"> <img src="pics/77931a4b-72ba-4016-827d-84b9a6845a51.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/77931a4b-72ba-4016-827d-84b9a6845a51.png"/> </div><br>
### Implementation
@ -2714,7 +2714,7 @@ Composite:root
装饰者Decorator和具体组件ConcreteComponent都继承自组件Component具体组件的方法实现不需要依赖于其它对象而装饰者组合了一个组件这样它可以装饰其它装饰者或者具体组件。所谓装饰就是把这个装饰者套在被装饰者之上从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的这属于它的功能然后调用被装饰者的方法实现从而也保留了被装饰者的功能。可以看到具体组件应当是装饰层次的最低层因为只有具体组件的方法实现不需要依赖于其它对象。
<div align="center"> <img src="pics/137c593d-0a9e-47b8-a9e6-b71f540b82dd.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/137c593d-0a9e-47b8-a9e6-b71f540b82dd.png"/> </div><br>
### Implementation
@ -2722,7 +2722,7 @@ Composite:root
下图表示在 DarkRoast 饮料上新增新添加 Mocha 配料,之后又添加了 Whip 配料。DarkRoast 被 Mocha 包裹Mocha 又被 Whip 包裹。它们都继承自相同父类,都有 cost() 方法,外层类的 cost() 方法调用了内层类的 cost() 方法。
<div align="center"> <img src="pics/c9cfd600-bc91-4f3a-9f99-b42f88a5bb24.jpg" width="600"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c9cfd600-bc91-4f3a-9f99-b42f88a5bb24.jpg" width="600"/> </div><br>
```java
public interface Beverage {
@ -2820,7 +2820,7 @@ public class Client {
### Class Diagram
<div align="center"> <img src="pics/f9978fa6-9f49-4a0f-8540-02d269ac448f.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f9978fa6-9f49-4a0f-8540-02d269ac448f.png"/> </div><br>
### Implementation
@ -2879,7 +2879,7 @@ public class Client {
- IntrinsicState内部状态享元对象共享内部状态
- ExtrinsicState外部状态每个享元对象的外部状态不同
<div align="center"> <img src="pics/d52270b4-9097-4667-9f18-f405fc661c99.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d52270b4-9097-4667-9f18-f405fc661c99.png"/> </div><br>
### Implementation
@ -2968,7 +2968,7 @@ Java 利用缓存来加速大量小对象的访问时间。
- 保护代理Protection Proxy按权限控制对象的访问它负责检查调用者是否具有实现一个请求所必须的访问权限。
- 智能代理Smart Reference取代了简单的指针它在访问对象时执行一些附加操作记录对象的引用次数当第一次引用一个对象时将它装入内存在访问一个实际对象前检查是否已经锁定了它以确保其它对象不能改变它。
<div align="center"> <img src="pics/a6c20f60-5eba-427d-9413-352ada4b40fe.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a6c20f60-5eba-427d-9413-352ada4b40fe.png"/> </div><br>
### Implementation

View File

@ -33,11 +33,11 @@
下图中,一共有 6 个客户端产生了 6 个请求,这 6 个请求按 (1, 2, 3, 4, 5, 6) 的顺序发送。(1, 3, 5) 的请求会被发送到服务器 1(2, 4, 6) 的请求会被发送到服务器 2。
<div align="center"> <img src="pics/b02fcffd-ed09-4ef9-bc5f-8f0e0383eb1a.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b02fcffd-ed09-4ef9-bc5f-8f0e0383eb1a.jpg"/> </div><br>
该算法比较适合每个服务器的性能差不多的场景,如果有性能存在差异的情况下,那么性能较差的服务器可能无法承担过大的负载(下图的 Server 2
<div align="center"> <img src="pics/73c72e75-193c-4092-aa43-b9c6703c4a22.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/73c72e75-193c-4092-aa43-b9c6703c4a22.jpg"/> </div><br>
### 2. 加权轮询Weighted Round Robbin
@ -45,7 +45,7 @@
例如下图中,服务器 1 被赋予的权值为 5服务器 2 被赋予的权值为 1那么 (1, 2, 3, 4, 5) 请求会被发送到服务器 1(6) 请求会被发送到服务器 2。
<div align="center"> <img src="pics/92691356-4f7a-46ec-9921-13055d3dcb12.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/92691356-4f7a-46ec-9921-13055d3dcb12.jpg"/> </div><br>
### 3. 最少连接least Connections
@ -53,13 +53,13 @@
例如下图中,(1, 3, 5) 请求会被发送到服务器 1但是 (1, 3) 很快就断开连接,此时只有 (5) 请求连接服务器 1(2, 4, 6) 请求被发送到服务器 2只有 (2) 的连接断开,此时 (6, 4) 请求连接服务器 2。该系统继续运行时服务器 2 会承担过大的负载。
<div align="center"> <img src="pics/8089a19a-6239-47a0-bf69-54203117d4dc.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8089a19a-6239-47a0-bf69-54203117d4dc.jpg"/> </div><br>
最少连接算法就是将请求发送给当前最少连接数的服务器上。
例如下图中,服务器 1 当前连接数最小,那么新到来的请求 6 就会被发送到服务器 1 上。
<div align="center"> <img src="pics/181edd46-e640-472a-9119-a697de0d2a82.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/181edd46-e640-472a-9119-a697de0d2a82.jpg"/> </div><br>
### 4. 加权最少连接Weighted Least Connection
@ -71,7 +71,7 @@
和轮询算法类似,该算法比较适合服务器性能差不多的场景。
<div align="center"> <img src="pics/67173c9f-ac87-496a-bd0a-0b1a5cfa735a.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/67173c9f-ac87-496a-bd0a-0b1a5cfa735a.jpg"/> </div><br>
### 6. 源地址哈希法 (IP Hash)
@ -79,7 +79,7 @@
可以保证同一 IP 的客户端的请求会转发到同一台服务器上用来实现会话粘滞Sticky Session
<div align="center"> <img src="pics/9d3c6bfb-4c4c-4b77-9410-56b3f82106d1.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9d3c6bfb-4c4c-4b77-9410-56b3f82106d1.jpg"/> </div><br>
## 转发实现
@ -94,7 +94,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
该负载均衡转发的缺点比较明显,实际场景中很少使用它。
<div align="center"> <img src="pics/131550414680831.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/131550414680831.gif"/> </div><br>
### 2. DNS 域名解析
@ -110,7 +110,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
大型网站基本使用了 DNS 做为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。也就是说,域名解析的结果为内部的负载均衡服务器 IP 地址。
<div align="center"> <img src="pics/141550414746389.gif"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/141550414746389.gif"/> </div><br>
### 3. 反向代理服务器
@ -167,7 +167,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
- 当服务器宕机时,将丢失该服务器上的所有 Session。
<div align="center"> <img src="pics/6aee49d3-f6c6-4d14-a81a-080c290de875.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6aee49d3-f6c6-4d14-a81a-080c290de875.jpg"/> </div><br>
## Session Replication
@ -178,7 +178,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
- 占用过多内存;
- 同步过程占用网络带宽以及服务器处理器时间。
<div align="center"> <img src="pics/7f403a7a-5228-42c0-af1c-b21635c77016.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7f403a7a-5228-42c0-af1c-b21635c77016.jpg"/> </div><br>
## Session Server
@ -192,7 +192,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
- 需要去实现存取 Session 的代码。
<div align="center"> <img src="pics/27fce0c6-8262-4d11-abb4-243faa2a2eef.jpg"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/27fce0c6-8262-4d11-abb4-243faa2a2eef.jpg"/> </div><br>
参考:

View File

@ -130,7 +130,7 @@ public class Music {
用来描述继承关系,在 Java 中使用 extends 关键字。
<div align="center"> <img src="pics/SoWkIImgAStDuU8goIp9ILLmJyrBBKh.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/SoWkIImgAStDuU8goIp9ILLmJyrBBKh.png"/> </div><br>
```text
@startuml
@ -151,7 +151,7 @@ Vihical <|-- Trunck
用来实现一个接口,在 Java 中使用 implements 关键字。
<div align="center"> <img src="pics/SoWkIImgAStDuU8goIp9ILK8IatCoQn.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/SoWkIImgAStDuU8goIp9ILK8IatCoQn.png"/> </div><br>
```text
@startuml
@ -172,7 +172,7 @@ MoveBehavior <|.. Run
表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还是会存在。
<div align="center"> <img src="pics/SoWkIImgAStDuU8goIp9ILLmJ4ylIar.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/SoWkIImgAStDuU8goIp9ILLmJ4ylIar.png"/> </div><br>
```text
@startuml
@ -195,7 +195,7 @@ Computer o-- Screen
和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在了。比如公司和部门,公司没了部门就不存在了。但是公司和员工就属于聚合关系了,因为公司没了员工还在。
<div align="center"> <img src="pics/SoWkIImgAStDuU8goIp9ILLmpiyjo2_.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/SoWkIImgAStDuU8goIp9ILLmpiyjo2_.png"/> </div><br>
```text
@startuml
@ -216,7 +216,7 @@ Company *-- DepartmentB
表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系一个学校可以有很多学生但是一个学生只属于一个学校因此这是一种多对一的关系在运行开始之前就可以确定。
<div align="center"> <img src="pics/SoWkIImgAStDuU8goIp9ILLmB2xEJyv.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/SoWkIImgAStDuU8goIp9ILLmB2xEJyv.png"/> </div><br>
```text
@startuml
@ -239,7 +239,7 @@ School "1" - "n" Student
- A 类是 B 类方法当中的一个参数;
- A 类向 B 类发送消息,从而影响 B 类发生变化。
<div align="center"> <img src="pics/LOun2W9134NxVugmbJPp15d4LalxC4O.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/LOun2W9134NxVugmbJPp15d4LalxC4O.png"/> </div><br>
```text
@startuml

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1 +0,0 @@
11898003996130227755

View File

@ -1 +0,0 @@
11898003996130227755