<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>数据结构 on Liangweidong's blog</title><link>https://liangweidonggood.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</link><description>Recent content in 数据结构 on Liangweidong's blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Fri, 15 Jun 2018 00:00:00 +0800</lastBuildDate><atom:link href="https://liangweidonggood.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/index.xml" rel="self" type="application/rss+xml"/><item><title>Java 面试合集：Redis 数据结构与线程模型</title><link>https://liangweidonggood.github.io/p/java-mianshi-redis-shujujiegou-xiancheng/</link><pubDate>Fri, 15 Jun 2018 00:00:00 +0800</pubDate><guid>https://liangweidonggood.github.io/p/java-mianshi-redis-shujujiegou-xiancheng/</guid><description>&lt;img src="https://liangweidonggood.github.io/p/java-mianshi-redis-shujujiegou-xiancheng/image/cover.jpg" alt="Featured image of post Java 面试合集：Redis 数据结构与线程模型" /&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;本文写于 2018 年 6 月&lt;/strong&gt;——Redis 4.0 主线、Redis 5.0（Stream 类型）2018-10 发布前夜。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一8-大数据类型应用场景"&gt;一、8 大数据类型应用场景
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;底层实现&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;String&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;缓存 / 计数器 / 限流 / 分布式锁 / 共享 Session&lt;/td&gt;
					&lt;td&gt;int + SDS（简单动态字符串）&lt;/td&gt;
					&lt;td&gt;最基础类型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Hash&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;缓存对象 / 购物车&lt;/td&gt;
					&lt;td&gt;压缩列表 / 哈希表&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;7.0 中，压缩列表已经废弃了，交由 listpack 来实现了&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;List&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消息队列&lt;/td&gt;
					&lt;td&gt;双向链表 / 压缩列表&lt;/td&gt;
					&lt;td&gt;简单的字符串列表，最大长度为 &lt;code&gt;2^32 - 1&lt;/code&gt;，40 亿。&lt;strong&gt;3.2 版本之后，底层数据结构就只由 quicklist 实现了&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Set&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;点赞 / 共同关注 / 抽奖活动&lt;/td&gt;
					&lt;td&gt;哈希表 / 整数集合&lt;/td&gt;
					&lt;td&gt;无序并唯一的键值集合&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ZSet&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;排行榜 / 电话排序 / 姓名排序&lt;/td&gt;
					&lt;td&gt;压缩列表 / 跳表&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;7.0 中，压缩列表已经废弃了，交由 listpack 来实现了&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;BitMap（2.2 版新增）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;签到 / 用户登陆状态 / 布隆过滤器&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;统计二值状态&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;HyperLogLog（2.8 版新增）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;百万级以上的网页 UV 计数&lt;/td&gt;
					&lt;td&gt;自定义&lt;/td&gt;
					&lt;td&gt;用于「统计基数」&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;GEO（3.2 版新增）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;滴滴叫车&lt;/td&gt;
					&lt;td&gt;Sorted Set&lt;/td&gt;
					&lt;td&gt;地理坐标&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Stream（5.0 版新增）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消息队列&lt;/td&gt;
					&lt;td&gt;自定义&lt;/td&gt;
					&lt;td&gt;完美地实现消息队列&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="11-选型决策"&gt;1.1 选型决策
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;graph TD
 A[需要存什么?] --&gt; B{单个值?}
 B --&gt;|是| C[String / BitMap / HyperLogLog]
 B --&gt;|否| D{有序?}
 D --&gt;|是| E[ZSet / List / Stream]
 D --&gt;|否| F{唯一?}
 F --&gt;|是| G[Set]
 F --&gt;|否| H[Hash / List]&lt;/pre&gt;&lt;h2 id="二redis-线程模型"&gt;二、Redis 线程模型
&lt;/h2&gt;&lt;h3 id="21-单线程-vs-多线程"&gt;2.1 单线程 vs 多线程
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;Redis 单线程指的是「接收客户端请求 → 解析请求 → 进行数据读写等操作 → 发送数据给客户端」这个过程是由一个线程（主线程）来完成的，这也是我们常说 Redis 是单线程的原因。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;但是，&lt;strong&gt;Redis 程序并不是单线程的&lt;/strong&gt;，Redis 在启动的时候是会启动后台线程（BIO）的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Redis 在 2.6 版本&lt;/strong&gt;，会启动 2 个后台线程，分别处理关闭文件、AOF 刷盘这两个任务&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis 在 4.0 版本之后&lt;/strong&gt;，新增了一个新的后台线程，用来异步释放 Redis 内存，也就是 lazyfree 线程&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-redis-60-引入多线程-io"&gt;2.2 Redis 6.0 引入多线程 I/O
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;虽然 Redis 的主要工作（网络 I/O 和执行命令）一直是单线程模型，但是 &lt;strong&gt;在 Redis 6.0 版本之后，也采用了多个 I/O 线程来处理网络请求&lt;/strong&gt;，这是因为随着网络硬件的性能提升，Redis 的性能瓶颈有时会出现在网络 I/O 的处理上。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;所以为了提高网络 I/O 的并行度，Redis 6.0 对于网络 I/O 采用多线程来处理。但是对于命令的执行，Redis 仍然使用单线程来处理。&lt;/strong&gt; 所以大家&lt;strong&gt;不要误解&lt;/strong&gt; Redis 有多线程同时执行命令。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Redis 官方表示，&lt;strong&gt;Redis 6.0 版本引入的多线程 I/O 特性对性能提升至少是一倍以上&lt;/strong&gt;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="23-60-线程数配置"&gt;2.3 6.0 线程数配置
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 读请求也使用 io 多线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;reads&lt;/span&gt; &lt;span class="n"&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// io-threads N，表示启用 N-1 个 I/O 线程（主线程也算一个 I/O 线程）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;blockquote&gt;
 &lt;p&gt;官方的建议是如果为 4 核的 CPU，建议线程数设置为 2 或 3，如果为 8 核 CPU 建议线程数设置为 6，线程数一定要小于机器核数，线程数并不是越大越好。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="24-redis-启动后的线程组成"&gt;2.4 Redis 启动后的线程组成
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;因此， Redis 6.0 版本之后，Redis 在启动的时候，默认情况下会 &lt;strong&gt;额外创建 6 个线程&lt;/strong&gt; （&lt;em&gt;这里的线程数不包括主线程&lt;/em&gt; ）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Redis-server&lt;/strong&gt;：Redis 的主线程，主要负责执行命令&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bio_close_file、bio_aof_fsync、bio_lazy_free&lt;/strong&gt;：三个后台线程，分别异步处理关闭文件任务、AOF 刷盘任务、释放内存任务&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;io_thd_1、io_thd_2、io_thd_3&lt;/strong&gt;：三个 I/O 线程，io-threads 默认是 4，所以会启动 3（4-1）个 I/O 多线程，用来分担 Redis 网络 I/O 的压力&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h2 id="三redis-为什么这么快"&gt;三、Redis 为什么这么快
&lt;/h2&gt;&lt;h3 id="31-4-大核心原因"&gt;3.1 4 大核心原因
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;Redis 快的核心原因，可以用一句话概括：&lt;strong&gt;它干的活极其简单，而且它把单线程的优势发挥到了极致，同时通过操作系统底层的&amp;quot;高级外挂&amp;quot;解决了高并发的排队问题。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="原因-1绝大多数请求是纯内存操作"&gt;原因 1：绝大多数请求是纯内存操作
&lt;/h4&gt;&lt;p&gt;这是最根本的基础。Redis 的所有数据都存储在内存中，CPU 读写内存的速度（&lt;strong&gt;纳秒级别&lt;/strong&gt;）比起读写机械硬盘或 SSD（&lt;strong&gt;微秒甚至毫秒级别&lt;/strong&gt;）快了数万倍。&lt;/p&gt;
&lt;h4 id="原因-2避免了多线程的内耗"&gt;原因 2：避免了多线程的&amp;quot;内耗&amp;quot;
&lt;/h4&gt;&lt;p&gt;多线程虽然能并发，但也带来了高昂的代价。Redis 采用单线程，反而完美避开了这些性能杀手：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有线程切换的开销&lt;/strong&gt;：操作系统在切换线程时，需要保存当前线程的上下文并加载新线程的数据。单线程一个人干到底，零切换成本&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有锁的竞争&lt;/strong&gt;：多线程访问共享资源必须加锁，&lt;strong&gt;加锁、解锁以及等待锁的操作非常重&lt;/strong&gt;。Redis 单线程天然保证了所有操作都是&lt;strong&gt;原子性&lt;/strong&gt;的，根本不需要锁&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="原因-3io-多路复用技术底层外挂"&gt;原因 3：I/O 多路复用技术（底层外挂）
&lt;/h4&gt;&lt;p&gt;&amp;ldquo;单线程&amp;quot;指的是 &lt;strong&gt;Redis 核心的网络事件处理器和键值对读写命令&lt;/strong&gt; 是由一个线程串行执行的。但面对海量的客户端连接，单线程怎么可能忙得过来？&lt;/p&gt;
&lt;p&gt;这就是 &lt;strong&gt;I/O 多路复用（I/O Multiplexing）&lt;/strong&gt; 大显身手的地方。Redis 利用了操作系统底层的非阻塞 I/O 机制（在 Linux 上通常是 &lt;code&gt;epoll&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;epoll 工作原理&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌─────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ Redis 主线程 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ┌──────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ epoll_wait() │ ← 阻塞等事件 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └──────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ↓ 有事件发生 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 遍历 fd_list，处理每个就绪 fd │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ Client 1: read() │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ Client 5: read() │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └─ Client 100: read() │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ↓ 业务逻辑 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 执行 Redis 命令（单线程原子） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ↓ 写回响应 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ write() → 多线程异步 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;epoll 优势&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;select&lt;/strong&gt;：O(n) 遍历所有 fd&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;poll&lt;/strong&gt;：O(n) 遍历所有 fd&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;epoll&lt;/strong&gt;：O(1) 事件通知（内核维护就绪链表）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="原因-4精心优化的数据结构"&gt;原因 4：精心优化的数据结构
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;数据结构&lt;/th&gt;
					&lt;th&gt;优化&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;SDS&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;O(1) 长度获取、避免缓冲区溢出、二进制安全&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;跳跃表&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;O(log N) 范围查询，替代红黑树&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;压缩列表&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;连续内存 + 紧凑编码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;dict（哈希表）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;渐进式 rehash，不阻塞&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="四内存淘汰策略"&gt;四、内存淘汰策略
&lt;/h2&gt;&lt;h3 id="41-8-大策略"&gt;4.1 8 大策略
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;策略&lt;/th&gt;
					&lt;th&gt;描述&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;noeviction&lt;/strong&gt;（默认）&lt;/td&gt;
					&lt;td&gt;不淘汰，写入失败返回错误&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;allkeys-lru&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;所有 key 中淘汰最近最少使用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;allkeys-lfu&lt;/strong&gt;（4.0+）&lt;/td&gt;
					&lt;td&gt;所有 key 中淘汰最不经常使用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;allkeys-random&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;所有 key 中随机淘汰&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;volatile-lru&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;设置过期的 key 中淘汰 LRU&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;volatile-lfu&lt;/strong&gt;（4.0+）&lt;/td&gt;
					&lt;td&gt;设置过期的 key 中淘汰 LFU&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;volatile-random&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;设置过期的 key 中随机淘汰&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;volatile-ttl&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;设置过期的 key 中淘汰最近过期&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="42-选型建议"&gt;4.2 选型建议
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;缓存场景&lt;/strong&gt;（容忍丢失）：&lt;code&gt;allkeys-lru&lt;/code&gt; / &lt;code&gt;allkeys-lfu&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据不能丢&lt;/strong&gt;：&lt;code&gt;noeviction&lt;/code&gt; + 监控告警&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混合场景&lt;/strong&gt;：&lt;code&gt;volatile-lru&lt;/code&gt;（仅淘汰过期 key）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="五持久化机制"&gt;五、持久化机制
&lt;/h2&gt;&lt;h3 id="51-三大方式"&gt;5.1 三大方式
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方式&lt;/th&gt;
					&lt;th&gt;文件&lt;/th&gt;
					&lt;th&gt;频率&lt;/th&gt;
					&lt;th&gt;性能&lt;/th&gt;
					&lt;th&gt;数据安全&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RDB&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;dump.rdb&lt;/td&gt;
					&lt;td&gt;定时 / 手动&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
					&lt;td&gt;较低（可能丢失最后一次快照后的数据）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;AOF&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;appendonly.aof&lt;/td&gt;
					&lt;td&gt;每秒&lt;/td&gt;
					&lt;td&gt;中&lt;/td&gt;
					&lt;td&gt;较高（仅丢失 1s 数据）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;混合（4.0+）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;dump + aof&lt;/td&gt;
					&lt;td&gt;-&lt;/td&gt;
					&lt;td&gt;中高&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="52-rdb-触发"&gt;5.2 RDB 触发
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 自动触发（save 命令）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;save &lt;span class="m"&gt;900&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# 900 秒内至少 1 个 key 变更&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;save &lt;span class="m"&gt;300&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;# 300 秒内至少 10 个 key 变更&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;save &lt;span class="m"&gt;60&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt; &lt;span class="c1"&gt;# 60 秒内至少 10000 个 key 变更&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 手动触发&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bgsave &lt;span class="c1"&gt;# 后台异步保存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;save &lt;span class="c1"&gt;# 同步保存（阻塞主线程）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="53-aof-三种策略"&gt;5.3 AOF 三种策略
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# appendfsync 策略&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;appendfsync always &lt;span class="c1"&gt;# 每次写入同步刷盘（最安全，最慢）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;appendfsync everysec &lt;span class="c1"&gt;# 每秒刷盘（默认，推荐）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;appendfsync no &lt;span class="c1"&gt;# 操作系统决定（最快，最不安全）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="六redis-集群方案"&gt;六、Redis 集群方案
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方案&lt;/th&gt;
					&lt;th&gt;数据分片&lt;/th&gt;
					&lt;th&gt;高可用&lt;/th&gt;
					&lt;th&gt;适用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;主从复制&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;✗&lt;/td&gt;
					&lt;td&gt;手动故障切换&lt;/td&gt;
					&lt;td&gt;简单备份&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Sentinel&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;✗&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;自动故障切换&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中小规模&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Codis&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;✓&lt;/td&gt;
					&lt;td&gt;手动 + 代理&lt;/td&gt;
					&lt;td&gt;国产分片方案&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Cluster&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;✓（16384 slot）&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;自动故障切换&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;大规模生产&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="七redis-经典问题"&gt;七、Redis 经典问题
&lt;/h2&gt;&lt;h3 id="71-缓存雪崩"&gt;7.1 缓存雪崩
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：大量 key 同时过期，请求打到数据库。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;过期时间加随机值&lt;/strong&gt;：&lt;code&gt;expire = base + random(0, 300)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;熔断降级&lt;/strong&gt;：数据库压力过大时直接拒绝部分请求&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存预热&lt;/strong&gt;：系统启动时把热点数据加载到缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="72-缓存穿透"&gt;7.2 缓存穿透
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：查询不存在的 key，每次都打到数据库。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;空值缓存&lt;/strong&gt;：&lt;code&gt;key -&amp;gt; null&lt;/code&gt;（短 TTL）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布隆过滤器&lt;/strong&gt;：先过布隆过滤器&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接口校验&lt;/strong&gt;：参数合法性检查&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="73-缓存击穿"&gt;7.3 缓存击穿
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：热点 key 突然过期，瞬间大量请求打到数据库。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分布式锁&lt;/strong&gt;：第一个请求查 DB，后续请求等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;永不过期&lt;/strong&gt;：逻辑过期（不设 TTL，值带过期时间字段）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;熔断降级&lt;/strong&gt;：直接返回旧值&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="74-数据不一致"&gt;7.4 数据不一致
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：数据库和缓存数据不一致。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;先更新 DB，再删除缓存&lt;/strong&gt;（Cache-Aside Pattern）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;延迟双删&lt;/strong&gt;：更新 DB → 删除缓存 → 异步延迟再删&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;binlog 订阅&lt;/strong&gt;：监听 binlog 异步更新缓存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设置较短 TTL&lt;/strong&gt;：最终一致性兜底&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="八写在最后"&gt;八、写在最后
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;Redis 面试要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;基础&lt;/strong&gt;：8 大数据类型 + 选型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线程模型&lt;/strong&gt;：单线程 vs 多线程 I/O、I/O 多路复用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快的原因&lt;/strong&gt;：内存操作 + 无锁 + epoll + 优化数据结构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持久化&lt;/strong&gt;：RDB / AOF / 混合&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;集群&lt;/strong&gt;：主从 / Sentinel / Cluster&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;经典问题&lt;/strong&gt;：雪崩 / 穿透 / 击穿 / 一致性&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;h2 id="参考资料"&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://redis.io/documentation" target="_blank" rel="noopener"
 &gt;Redis 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://book.douban.com/subject/25900156/" target="_blank" rel="noopener"
 &gt;Redis 设计与实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/redis/redis" target="_blank" rel="noopener"
 &gt;Redis 源码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://redis.io/docs/manual/client-side-caching/" target="_blank" rel="noopener"
 &gt;Redis 6.0 多线程 I/O 解析&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>常见排序算法完全指南：从冒泡到堆排序</title><link>https://liangweidonggood.github.io/p/chang-jian-pai-xu/</link><pubDate>Fri, 17 Aug 2012 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/chang-jian-pai-xu/</guid><description>&lt;img src="https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/cover.jpg" alt="Featured image of post 常见排序算法完全指南：从冒泡到堆排序" /&gt;&lt;p&gt;排序算法是算法学习的&amp;quot;第一道关卡&amp;quot;，也是面试最高频的考点之一。常见排序家族大致可以分为 &lt;strong&gt;O(n²) 简单排序&lt;/strong&gt;、&lt;strong&gt;O(n log n) 高效排序&lt;/strong&gt;、&lt;strong&gt;O(n) 特殊排序&lt;/strong&gt; 三大类。这篇文章会带你用一张复杂度总览图 + 7 个核心排序的代码与动图串起整个知识体系。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;为什么学排序？&lt;/strong&gt; 排序看似简单，但它几乎是所有算法面试的&amp;quot;开胃菜&amp;quot;——它同时考察你&lt;strong&gt;时间/空间复杂度分析、稳定性判断、原地/非原地、递归/迭代&lt;/strong&gt;等基础能力。更重要的是，很多高级算法（如二分查找、归并思想、Timsort）都建立在排序之上。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一复杂度总览"&gt;一、复杂度总览
&lt;/h2&gt;&lt;p&gt;一张图看懂 10 种常见排序的复杂度、稳定性、空间开销：&lt;/p&gt;
&lt;p&gt;&lt;img alt="常见排序复杂度对比" class="gallery-image" data-flex-basis="355px" data-flex-grow="147" height="1272" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/1682495142751.png" srcset="https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/1682495142751_hu_31787b4ec0d3eb38.png 800w, https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/1682495142751_hu_48ed1a1be2c0d524.png 1600w, https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/1682495142751.png 1882w" width="1882"&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;图源说明&lt;/strong&gt;：上方图片来自原 &lt;code&gt;常见排序.md&lt;/code&gt; 文档的复杂度对比图，汇总了各种排序算法在&lt;strong&gt;最好/最坏/平均时间复杂度、空间复杂度、稳定性&lt;/strong&gt;等关键维度上的表现，建议先记住这张图，再去深入单个算法。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="速记口诀"&gt;速记口诀
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类别&lt;/th&gt;
					&lt;th&gt;包含算法&lt;/th&gt;
					&lt;th&gt;时间复杂度&lt;/th&gt;
					&lt;th&gt;稳定性&lt;/th&gt;
					&lt;th&gt;一句话记忆&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;简单排序&lt;/td&gt;
					&lt;td&gt;冒泡 / 选择 / 插入&lt;/td&gt;
					&lt;td&gt;O(n²)&lt;/td&gt;
					&lt;td&gt;冒泡✓ 选择✗ 插入✓&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;三巨头&amp;rdquo;——最好写、最慢&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;高效排序&lt;/td&gt;
					&lt;td&gt;希尔 / 归并 / 快速 / 堆&lt;/td&gt;
					&lt;td&gt;O(n log n)&lt;/td&gt;
					&lt;td&gt;归并✓ 其他✗&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;工业级&amp;rdquo;——面试重点&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;特殊排序&lt;/td&gt;
					&lt;td&gt;计数 / 桶 / 基数&lt;/td&gt;
					&lt;td&gt;O(n + k)&lt;/td&gt;
					&lt;td&gt;✓&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;非比较&amp;rdquo;——特定场景起飞&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;高级混合&lt;/td&gt;
					&lt;td&gt;Timsort / Introsort&lt;/td&gt;
					&lt;td&gt;O(n log n)&lt;/td&gt;
					&lt;td&gt;✓&lt;/td&gt;
					&lt;td&gt;真实语言内置的排序&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="二冒泡排序入门第一课"&gt;二、冒泡排序：入门第一课
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;动图演示&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img alt="冒泡排序" class="gallery-image" data-flex-basis="771px" data-flex-grow="321" height="257" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F.gif" srcset="https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F_hu_b73d6dabcbc15cd1.gif 800w, https://liangweidonggood.github.io/p/chang-jian-pai-xu/image/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F.gif 826w" width="826"&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;图源说明&lt;/strong&gt;：上方 GIF 来自原 &lt;code&gt;常见排序.md&lt;/code&gt; 文档，演示了冒泡排序逐轮把最大元素&amp;quot;冒泡&amp;quot;到末尾的过程。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="21-核心思想"&gt;2.1 核心思想
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;像水里的气泡一样，&lt;strong&gt;两两比较相邻元素&lt;/strong&gt;，如果前面的比后面的大就交换；这样一轮下来最大的元素一定会&amp;quot;浮&amp;quot;到最右边；重复这个过程 n-1 轮即可完成排序。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="22-python-实现"&gt;2.2 Python 实现
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bubble_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;冒泡排序：原地、稳定、O(n²)&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;swapped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;swapped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 优化：如果这一轮没有交换，说明已经有序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;swapped&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="23-关键点"&gt;2.3 关键点
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定性&lt;/strong&gt;：✓ 稳定（相等元素不会交换相对顺序）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原地性&lt;/strong&gt;：✓ 原地排序（空间 O(1)）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最好情况&lt;/strong&gt;：O(n)（输入已经有序，加 &lt;code&gt;swapped&lt;/code&gt; 标志可提前结束）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最坏情况&lt;/strong&gt;：O(n²)（逆序输入）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么面试爱考&lt;/strong&gt;：能引出&amp;quot;&lt;strong&gt;标志位优化&lt;/strong&gt;&amp;quot;、&amp;quot;&lt;strong&gt;鸡尾酒排序（双向冒泡）&lt;/strong&gt;&amp;ldquo;等延伸讨论&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="24-常见坑"&gt;2.4 常见坑
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;❌ 内层循环写成 &lt;code&gt;range(n)&lt;/code&gt; 而不是 &lt;code&gt;range(n - 1 - i)&lt;/code&gt;——每一轮多比较已经排好序的尾巴&lt;/li&gt;
&lt;li&gt;❌ 漏掉 &lt;code&gt;swapped&lt;/code&gt; 标志位——失去了&amp;quot;已经有序就提前结束&amp;quot;的优化&lt;/li&gt;
&lt;li&gt;❌ 把&amp;rdquo;=&amp;ldquo;和&amp;rdquo;&amp;gt;&amp;ldquo;搞反——影响稳定性判断&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三选择排序最直白但最慢"&gt;三、选择排序：最直白但最慢
&lt;/h2&gt;&lt;h3 id="31-核心思想"&gt;3.1 核心思想
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;每一轮从未排序部分&lt;strong&gt;找出最小值&lt;/strong&gt;，放到已排序部分的末尾。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="32-python-实现"&gt;3.2 Python 实现
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;selection_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;min_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;min_idx&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;min_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;min_idx&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;min_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;min_idx&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="33-关键点"&gt;3.3 关键点
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定性&lt;/strong&gt;：✗ &lt;strong&gt;不稳定&lt;/strong&gt;（交换会跨过相等元素）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原地性&lt;/strong&gt;：✓ 原地&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂度&lt;/strong&gt;：无论输入如何都是 O(n²)（没有最好情况优化）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：&lt;strong&gt;交换次数最少&lt;/strong&gt;（最多 n-1 次），适合&amp;quot;交换代价高&amp;quot;的场景（如写 SSD）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="四插入排序数据越有序越快"&gt;四、插入排序：数据越有序越快
&lt;/h2&gt;&lt;h3 id="41-核心思想"&gt;4.1 核心思想
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;把数组分为&amp;quot;已排序区&amp;quot;和&amp;quot;未排序区&amp;rdquo;，每次从未排序区取一个元素，&lt;strong&gt;向前找到它在已排序区里的插入位置&lt;/strong&gt;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="42-python-实现"&gt;4.2 Python 实现
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;insertion_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 把所有比 key 大的元素都后移一位&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="43-关键点"&gt;4.3 关键点
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定性&lt;/strong&gt;：✓ 稳定&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂度&lt;/strong&gt;：最好 O(n)（已经有序）、最差 O(n²)（逆序）、平均 O(n²)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;杀手锏&lt;/strong&gt;：&lt;strong&gt;对近乎有序的数据极快&lt;/strong&gt;——这就是为什么 Timsort（Python/Java 内置排序）会用它做&amp;quot;小块排序&amp;quot;（run）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="五希尔排序插入排序的跨度升级版"&gt;五、希尔排序：插入排序的&amp;quot;跨度升级版&amp;quot;
&lt;/h2&gt;&lt;h3 id="51-核心思想"&gt;5.1 核心思想
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;插入排序只能一步步挪动，效率差。希尔排序把数组按&amp;quot;&lt;strong&gt;间隔 gap&lt;/strong&gt;&amp;ldquo;分成多个子序列，对每个子序列做插入排序；然后不断缩小 gap，重复；最后 gap=1 时退化为插入排序，但因为前面已经&amp;quot;基本有序&amp;quot;了，所以收尾很快。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="52-python-实现"&gt;5.2 Python 实现
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;shell_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;gap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;gap&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;gap&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;gap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;gap&lt;/span&gt; &lt;span class="o"&gt;//=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="53-关键点"&gt;5.3 关键点
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定性&lt;/strong&gt;：✗ 不稳定（分组打乱了原顺序）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂度&lt;/strong&gt;：平均约 O(n^1.3)，取决于 gap 序列&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;现状&lt;/strong&gt;：理论价值 &amp;gt; 工业价值，现实中基本被快速排序/归并排序取代&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="六归并排序分治的教科书"&gt;六、归并排序：分治的&amp;quot;教科书&amp;rdquo;
&lt;/h2&gt;&lt;h3 id="61-核心思想"&gt;6.1 核心思想
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;分治法&lt;/strong&gt;：把数组从中点分成两半，分别排序后合并（merge）。合并两个有序数组是 O(n)，递归深度 O(log n)，所以总复杂度 O(n log n)。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="62-python-实现"&gt;6.2 Python 实现
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 合并两个有序数组&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="63-关键点"&gt;6.3 关键点
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定性&lt;/strong&gt;：✓ 稳定（合并时用 &lt;code&gt;&amp;lt;=&lt;/code&gt; 而不是 &lt;code&gt;&amp;lt;&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂度&lt;/strong&gt;：始终 O(n log n)，没有最坏情况&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;空间&lt;/strong&gt;：O(n)（需要额外数组）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用&lt;/strong&gt;：Java &lt;code&gt;Arrays.sort()&lt;/code&gt; 对对象数组的排序、Python &lt;code&gt;sorted()&lt;/code&gt; 内部走的就是归并的变体&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="七快速排序实战之王"&gt;七、快速排序：实战之王
&lt;/h2&gt;&lt;h3 id="71-核心思想"&gt;7.1 核心思想
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;分治法&lt;/strong&gt;：选一个&amp;quot;基准&amp;quot;（pivot），把数组分成&amp;quot;小于 pivot&amp;quot;和&amp;quot;大于 pivot&amp;quot;两部分，递归排序这两部分。平均 O(n log n)，最坏 O(n²)（pivot 选得不好）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="72-python-实现最常见的-lomuto-分区"&gt;7.2 Python 实现（最常见的 Lomuto 分区）
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quick_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pivot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 选最右元素作 pivot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pivot_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;quick_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pivot_idx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;quick_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pivot_idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="73-关键点"&gt;7.3 关键点
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定性&lt;/strong&gt;：✗ 不稳定（分区会交换相等元素）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原地性&lt;/strong&gt;：✓ 原地（O(log n) 栈空间）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pivot 选取优化&lt;/strong&gt;：三数取中（median-of-three）或随机 pivot 可以把最坏情况概率降到极低&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;现状&lt;/strong&gt;：C/C++/Rust/Java 基础类型排序底层都用快排的变体（如 Introsort）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="八堆排序原地--on-log-n-的全能选手"&gt;八、堆排序：原地 + O(n log n) 的&amp;quot;全能选手&amp;quot;
&lt;/h2&gt;&lt;h3 id="81-核心思想"&gt;8.1 核心思想
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;利用&lt;strong&gt;二叉堆&lt;/strong&gt;这种数据结构：先 O(n) 把数组建成大顶堆，然后不断把堆顶（最大值）换到末尾 + 下沉调整，循环 n-1 次。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="82-python-实现"&gt;8.2 Python 实现
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;heap_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 建堆（从最后一个非叶子节点开始下沉）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sift_down&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 排序：把堆顶换到末尾，再对前 n-1 个元素重新建堆&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sift_down&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sift_down&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="83-关键点"&gt;8.3 关键点
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定性&lt;/strong&gt;：✗ 不稳定&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原地性&lt;/strong&gt;：✓ 原地（真正的 O(1) 空间）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;现状&lt;/strong&gt;：常用于&amp;quot;&lt;strong&gt;内存极其受限&lt;/strong&gt;&amp;ldquo;的场景（如嵌入式、操作系统内核）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="九核心要点与常见坑"&gt;九、核心要点与常见坑
&lt;/h2&gt;&lt;h3 id="91-核心-n-点"&gt;9.1 核心 N 点
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;稳定性 vs 性能取舍&lt;/strong&gt;：归并/插入/冒泡稳定但慢（O(n²) 或 O(n) 空间）；快排/堆排/希尔快但不稳定&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;比较类 vs 非比较类&lt;/strong&gt;：比较类有 O(n log n) 的理论下限；非比较类（计数/桶/基数）可以突破到 O(n)，但需要数据有特殊结构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原地性&lt;/strong&gt;：堆排是唯一&lt;strong&gt;稳定原地 O(n log n)&lt;/strong&gt; 的算法；归并需要 O(n) 额外空间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;真实语言内置排序都是混合策略&lt;/strong&gt;——Timsort（Python/Java）= 归并 + 插入 + run；Introsort（C++/Rust）= 快排 + 堆排 + 插入&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;工业级默认&amp;quot;是快排/归并的变体&lt;/strong&gt;，不要在生产里手写 O(n²) 排序&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="92-常见-m-个坑"&gt;9.2 常见 M 个坑
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;冒泡忘了加 &lt;code&gt;swapped&lt;/code&gt; 标志&lt;/strong&gt;——失去了&amp;quot;已经有序就提前结束&amp;quot;的优化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;归并合并时用 &lt;code&gt;&amp;lt;&lt;/code&gt; 而不是 &lt;code&gt;&amp;lt;=&lt;/code&gt;&lt;/strong&gt;——破坏稳定性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快排的 pivot 选最左/最右 + 已排序输入&lt;/strong&gt;——直接退化为 O(n²)，递归栈溢出风险&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;堆排的下沉边界写错&lt;/strong&gt;——导致部分元素没参与调整&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;插入排序的内层 while 循环方向写反&lt;/strong&gt;——会无限循环&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混淆&amp;quot;时间复杂度&amp;quot;和&amp;quot;实际运行时间&amp;rdquo;&lt;/strong&gt;——小数据量下 O(n²) 可能比 O(n log n) 更快（缓存友好、常数小）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="十选型速查"&gt;十、选型速查
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;推荐算法&lt;/th&gt;
					&lt;th&gt;理由&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;面试手写&lt;/td&gt;
					&lt;td&gt;冒泡/插入/快排&lt;/td&gt;
					&lt;td&gt;简单、能引出讨论&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;一般工业场景&lt;/td&gt;
					&lt;td&gt;用语言内置排序&lt;/td&gt;
					&lt;td&gt;Timsort/Introsort 已经是最优&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;内存极小 + 大数据&lt;/td&gt;
					&lt;td&gt;堆排序&lt;/td&gt;
					&lt;td&gt;唯一原地 O(n log n)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;链表排序&lt;/td&gt;
					&lt;td&gt;归并排序&lt;/td&gt;
					&lt;td&gt;链表不适合随机访问，归并天然友好&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据基本有序&lt;/td&gt;
					&lt;td&gt;插入排序&lt;/td&gt;
					&lt;td&gt;几乎 O(n)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;大数据 + 整数 + 范围小&lt;/td&gt;
					&lt;td&gt;计数排序/桶排序&lt;/td&gt;
					&lt;td&gt;O(n + k)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;字符串/车牌等定长字段&lt;/td&gt;
					&lt;td&gt;基数排序&lt;/td&gt;
					&lt;td&gt;LSD/MSD 多轮分配&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="参考资料"&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;《算法导论》第 2 章 / 第 6 章 / 第 7 章&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://visualgo.net/en/sorting" target="_blank" rel="noopener"
 &gt;VisuAlgo - Sorting&lt;/a&gt;：在线可视化各种排序&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://en.wikipedia.org/wiki/Timsort" target="_blank" rel="noopener"
 &gt;Timsort 原理&lt;/a&gt;：Python/Java 内置排序&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://en.wikipedia.org/wiki/Introsort" target="_blank" rel="noopener"
 &gt;Introsort 原理&lt;/a&gt;：C++ &lt;code&gt;std::sort&lt;/code&gt; 内部用&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>