第 6 章 排序 — 从 O(n²) 到 O(n),比较与不比的两条路线
第 6 章 排序 — 从 O(n²) 到 O(n),比较与不比的两条路线
这一章讲什么: 怎么把一堆乱序的记录排成有序。它是全书最长的算法章: 十种正经排序 + 五种故意低效的,外加排序问题的六个分类维度。 它在全书链条里的位置: 算法主菜。第 5 章的分治、贪心、稳定性的概念 在这里全部变成具体代码;第 14 章还会回来讲堆排序,与第 10 章的基数排序实现 一起补完这张图。
1. 顶层全景
排序 = 重排记录,使键非降序,且输出是输入的一个排列(不许丢元素!)
│
├─ 比较排序(通用,任何可比的键)
│ O(n²):冒泡 → 鸡尾酒 → 选择 → 插入 (简单,小数组可用)
│ 改进: 梳排序 / 希尔排序 (跳跃缩小,希尔约 O(n^1.5))
│ O(n log n):快排(平均,最坏 O(n²)) / 归并(稳定,要额外空间)
│ 下界:任何比较排序 ≥ O(n log n) (信息论论证)
│
└─ 不比较排序(键必须满足额外条件)
位图排序 O(n):键范围小、无重复、纯数字
计数排序 O(n):允许重复
基数排序 O(n):逐位分桶,最古老(打孔卡),要稳定性兜底
图说:左支通用但撞下界,右支突破下界但钥匙受限。选型先看键,再看 n。2. 主线例子:[22, 9, 60, 12, 4, 56] 走四个代表性算法
用原书的标准演示数组,走四个台阶,每步旁边有具体状态:
第 ① 步:冒泡排序(比较排序的地板)。 相邻比较、逆序就换,每趟把当前
最大值「冒」到右端:22,9 换 → 9,22,60 不换 → 60,12 换 → 60,4 换 →
60,56 换,第一趟结束 [9, 22, 12, 4, 56, 60],60 到位。
共 5+4+3+2+1 = 15 次比较,O(n²) 的来历清清楚楚1。
一个实用增强(习题 6.7):每趟记 swaps,一趟无交换就提前收工——
近乎有序的数组几乎免费2。
第 ② 步:插入排序(小数组之王)。 像理扑克牌:前 i 张已有序,第 i+1 张
从右往左插到位。走查:第一张 22 独成一段;插 9 → [9, 22];插 60 → 原位;
插 12 → [9, 12, 22, 60];插 4 → 一路换到头;插 56 → [9, 12, 22, 56, 60] 完成。
平均也是 O(n²),但近乎有序的输入接近 O(n),这让它是「混合排序」
里小分段的标配3。
第 ③ 步:快速排序(分治旗舰)。 选最右为 pivot,一趟划分把小的换左边:
数组 [22, 9, 60, 12, 4, 56],pivot=56,扫一遍把小于 56 的都换到左侧,
56 落到位置 4;递归排 [22, 9, 12, 4] 与 [60] 即完成。
平均 O(n log n);已排序的输入是它的死穴——每次划分只缩一格,退化 O(n²)4。
三个增强:随机选 pivot / 三值取中(median of three)防有序输入;
小区间切插入排序(CUTOFF=7);双 pivot 分三段(Java 原生数组排序就是它)5。
第 ④ 步:计数排序(不比较的样板)。 允许重复的数字键、范围可估时用。
先数次数再算落点:[22, 9, 60, 12, 4, 56] 的计数表(以 4 为 0 号)中,
键 4、9、12、22、56、60 各 1 次;落点表从 0 累加:4→0、9→1、12→2、22→3、56→4、60→5;
再按落点把每个值写回原数组。两次扫描都是 O(n),总 O(n)——但前提是键范围不大,
否则计数表本身爆掉6。
3. 核心原理
3.1 先立规矩:排序问题的六个分类维度
动笔前先把问题本身说清,书里给了六个维度7:
- 定义:排序 = 按键非降序重新排列,且输出必须是输入的一个排列(元素一个不多一个不少)。
书里的反面教材:
const wrongWayToSort = (inputData) => [];——返回空数组 也算「有序」,所以「不丢元素」必须写进定义8。 - 内部 vs 外部排序:全装得进内存是内部排序(本章全部);装不下要分段 落盘再归并是外部排序——「真到那一步,用系统的 sort 工具」9。
- 原地性(in-place):是否需要与输入规模成正比的额外空间? 快排的递归栈 O(log n) 算原地;归并要 O(n) 辅助数组,不算10。
- 在线 vs 离线:数据流式到来边收边排(在线,如插入排序)还是全到齐再排 (离线,通常更快)。在线算法被迫像贪心一样做「可能后悔」的决定11。
- 稳定性(stable):键相等的元素,排完后的相对顺序是否与输入一致? 重要场景:先按名字排、再按「是否星标」排,第二次排序若稳定,名字序就保住 (书里的 Joliet/Romeo 例子)12。 任何排序都能强行变稳:把键扩成「原键 + 原下标」,排完丢掉下标13。
- 自适应性(adaptive):能否利用输入里已有的有序部分(希尔是,快排近乎反自适应)14。
还有第七件事:JavaScript 自带的 .sort()。不传比较函数时按字符串字典序排——
[22, 9, 60].sort() 得到 [22, 60, 9](9 被当成 "9"),数字排序必须传
(a, b) => a - b15。ES2019 起规范要求 .sort() 稳定;
新出的 .toSorted() 不改原数组(呼应第 2 章的纯度纪律)。
书里态度务实:「多数情况下用 JavaScript 自己的 sort 可能最有效」16。
3.2 比较排序的下界:O(n log n) 是撞不破的墙
为什么所有比较排序都停在 O(n log n)?书里的论证只用了一个类比: 二十个问题游戏——20 个是非题能从 100 万个可能中锁定目标(2²⁰ = 1,048,576)。 排序也一样:n 个元素有 n! 种排列,每次比较回答一个「是/非」, 要区分 n! 种可能就得问 log₂(n!) 次;由斯特林公式,n! 长得像 nⁿ, 所以 log(n!) = O(n log n)17。 推论两条:比较排序再好也到不了 O(n);但如果放弃比较(利用键本身的值), 下界作废——位图/计数/基数就是后门。这个「比较 vs 不比较」的分界 是本章最重要的概念,选型时第一个要问。
3.3 O(n²) 一族:简单、稳定(部分)、好懂
冒泡、鸡尾酒(shuttle,左右往返)、选择、插入,四个都 O(n²),差别在常数与性格:
| 算法 | 一趟干什么 | 性格 |
|---|---|---|
| 冒泡 | 大值逐格右冒 | 写好懂;加交换检查后有适应性 |
| 鸡尾酒 | 左冒一趟、右沉一趟 | 常数约快一倍;乌龟兔子双向都照顾 |
| 选择 | 找最小换到前面 | 交换次数最少(至多 n−1 次),适合写代价高的介质 |
| 插入 | 新元素插进有序段 | 近乎有序时近 O(n);小数组最快 |
「兔子与乌龟」的比喻来自梳排序:大值在数组前部(兔子)一趟就蹿到尾, 小值在尾部(乌龟)每次只能挪一格。梳排序先把间距拉大(除以 1.3), 兔子乌龟都大步跳,间距收到 1 退回冒泡——最坏仍 O(n²) 但实测好得多18。 希尔排序把同样思想用在插入排序上:先按大间距(4)把数组变成 4 条短有序序列, 再间距 2、最后间距 1——末趟插入面对的已经近乎有序,代价大减。 书里用 Knuth 序列(1, 4, 13, 40, …, 3k+1),复杂度约 O(n^1.5)19。
3.4 快排的三个增强:工程化的完整样本
快排平均 O(n log n)、最坏 O(n²)、原地,但「工程版」还要修三件事:
- pivot 选择:固定取最右在已排序输入上必死。解 A:随机取(平摊掉坏输入); 解 B:三值取中——左、中、右三个元素排序后的中位数;更狠的「ninther」 (三段各自三值取中,再取中)是常用库的做法20。
- 小区间切换:分段短于 CUTOFF(如 7)就换插入排序——递归开销不值当21。
- 双 pivot / 三路划分:两个 pivot 把数组切三段(小于/之间/大于); 重复键多时优势大。习题 6.10 的三路版(荷兰国旗问题)让等于 pivot 的 元素整块免排——重复键是快排隐藏的性能杀手22。
归并排序站在快排对面:稳定、保证 O(n log n) 最坏,代价是 O(n) 额外空间 和复制开销。书末点出 TimSort(归并+插入+利用已有有序段的混合体)是 Java、JavaScript(V8)的实际排序实现,「我们学过的所有零件都在里面」23。
3.5 不比较三兄弟:用键的值换 O(n)
- 位图排序:布尔数组当下标用,扫一遍置位、按位输出——O(n), 但三条硬限制:纯数字、范围小、无重复(重复直接抛错)24。
- 计数排序:位图的计数版,计数表 + 落点表两步,允许重复, 还能扩展成键+数据(把数据跟着落点搬)。依然是 O(n),依然要求范围可控6。
- 基数排序:最古老(赫尔瑞斯打孔卡,IBM 源头),逐位分桶: 先按个位分 10 桶收回,再按十位……每趟必须是稳定排序,否则高位白排 (回链稳定性一节)。O(n×位数),键值范围再大也不怕——按位处理, 范围从「键的最大值」变成了「键的位数」,这是它对前两者的真正解放25。 限制在习题 6.12/6.14 说破:负数会崩、小数被截断、字符串要每符号一桶。
3.6 故意低效的五种:认清「差」长什么样
章末一节反例博物馆,每种都有一个性能「亮点」26:
| 算法 | 复杂度 | 笑点/要点 |
|---|---|---|
| Stooge 排序 | O(n^2.71) | 递归排前 2/3、后 2/3、再前 2/3;比冒泡还差 |
| Slow 排序 | 超多项式 | 「multiply and surrender」(乘而降),作者的恶意之作 |
| 排列排序 | O(n!) | 不停生成下一个全排列直到有序 |
| Bogosort | 期望 n! | 乱序再查,52 张牌成功率约 1/52!;概率为 1 终会排好,但时间无界 |
| 睡眠排序 | 依赖最大值 | 键为 K 就等 K 秒再输出;JS 专供,数据一大就崩 |
这节的教学价值在于:把「复杂度失控」的几种典型形状(指数、阶乘、概率性) 一次性展示,读者日后看到似曾相识的结构能立刻警觉。
4. 作者的判断与证据
- **「多数情况用 JS 自带 sort」**是实用主义判断,紧跟一句「本章仍要讲清原理」 ——两者不矛盾:选型靠库,理解靠实现16。
- 比较下界的论证是严格的(信息论 + 斯特林),书中明确标注「不推导」, 只给直觉版二十个问题17。
- 快排增强集的取舍是经验共识:随机/三值取中/小区间切换/ninther, 与工业实现(Java 双 pivot、V8 TimSort)逐一对应——本章代码与真实引擎 之间的距离被明说23。
- 不比较排序的限制逐条明写(重复、范围、负数、小数),没有掩盖适用面窄的事实24。
判断(我们的,不是书里的): 本章真正的主线不是「学会十种排序」, 而是选型思维的两连问:第一问「键允许不比较吗」(范围小→位图/计数, 定长可分解→基数),第二问「n 多大、输入有多乱」(小→插入;乱→快排; 要稳定或最坏保证→归并/TimSort;最坏情况就是平均情况的近有序输入→插入/希尔)。 十种算法是这两问的决策树,不是清单。 如果错,会错在: 决策树缺了「外部排序」和「并行排序」两个真实分支—— 书里把外部排序推给系统工具是诚实的,但对「数据装不下内存」这一常见现实, 读者只得到了「别自己写」而没有「那该怎么办」。
5. 边界与局限
- 堆排序缺席(除了注释提它属第 14 章)——「全部排序算法」的图景要到第 14 章才完整。
- 外部排序一笔带过,并行/分布式排序没有。
- TimSort 只讲思想不给实现(近千行的实现,书里明说跳过了)。
- 稳定性的强转法(扩键)有 O(n) 空间代价,书里未点破。
- 习题 6.13 那个
Array(10).fill([])的坑(十个桶是同一个数组)是 JS 专属, 值得所有读者亲手试一次27。
6. 可带走的
- 排序定义两条:非降序 + 输出是输入的排列(空数组不是排序)。
- 六维度:内外、原地、在线、稳定、自适应;
.sort()不传函数按字符串排,数字必须(a,b)=>a-b。 - 比较排序下界 O(n log n)(二十个问题);不比才有 O(n)。
- O(n²) 四兄弟:冒泡/鸡尾酒/选择/插入;插入是小数组与近有序输入的默认赢家。
- 梳排序与希尔的「间距跳跃」思想;Knuth 序列 1,4,13,40…;希尔约 O(n^1.5) 且不稳定。
- 快排三个增强:随机或三值取中 pivot、小区间切插入、双 pivot/三路划分(重复键免排)。
- 归并:稳定 + 最坏 O(n log n),代价 O(n) 空间;TimSort = 归并+插入+利用有序段,是 V8 的真身。
- 不比较三兄弟的限制清单:位图(无重复)计数(范围小)基数(逐位、要稳定、负数/小数会崩)。
- 反例博物馆:复杂度失控的四种形状(高次多项式/超多项式/阶乘/概率无界)。
- 测试排序的土办法:与内置排序对拍,
JSON.stringify比字符串(习题 6.3)。
7. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 排序定义与错例 | The Sorting Problem | text/17-fm-the-sorting-problem.txt:4(搜「permutation」) |
| 内外/原地/在线/稳定性 | The Sorting Problem | text/17-fm-the-sorting-problem.txt:19(搜「External」) · text/17-fm-the-sorting-problem.txt:42(搜「In-Place」) · text/17-fm-the-sorting-problem.txt:55(搜「online」) · text/17-fm-the-sorting-problem.txt:71(搜「stable」) |
| 强转稳定(扩键) | The Sorting Problem | text/17-fm-the-sorting-problem.txt:88(搜「extended key」) |
| JS sort 与比较器 | The Sorting Problem | text/17-fm-the-sorting-problem.txt:109(搜「toSorted」) · text/17-fm-the-sorting-problem.txt:114(搜「12 22 4」) |
| 比较下界(二十个问题) | The Sorting Problem | text/17-fm-the-sorting-problem.txt:180(搜「20 questions」) |
| 冒泡与交换检查 | Sorting with Comparisons | text/18-fm-sorting-with-comparisons.txt:23(搜「bubble up」) · text/18-fm-sorting-with-comparisons.txt:54(搜「n(n」) |
| 鸡尾酒/选择/插入 | Sorting with Comparisons | text/18-fm-sorting-with-comparisons.txt:64(搜「shuttle」) · text/18-fm-sorting-with-comparisons.txt:140(搜「selectionSort」) · text/18-fm-sorting-with-comparisons.txt:183(搜「insertionSort」) |
| 梳排序(兔子乌龟) | Sorting with Comparisons | text/18-fm-sorting-with-comparisons.txt:234(搜「rabbits」) · text/18-fm-sorting-with-comparisons.txt:244(搜「SHRINK_FACTOR」) |
| 希尔(Knuth 序列) | Sorting with Comparisons | text/18-fm-sorting-with-comparisons.txt:286(搜「shellSort」) |
| 快排/三值取中/混合/双轴 | Sorting with Comparisons | text/18-fm-sorting-with-comparisons.txt:339(搜「quickSort」) · text/18-fm-sorting-with-comparisons.txt:391(搜「middle」) · text/18-fm-sorting-with-comparisons.txt:417(搜「CUTOFF」) · text/18-fm-sorting-with-comparisons.txt:456(搜「dualPivot」) |
| 归并与 TimSort | Sorting with Comparisons | text/18-fm-sorting-with-comparisons.txt:552(搜「mergesort」) · text/18-fm-sorting-with-comparisons.txt:580(搜「Tim sort」) |
| 位图/计数/基数 | Sorting Without Comparisons | text/19-fm-sorting-without-comparisons.txt:15(搜「suppositions」) · text/19-fm-sorting-without-comparisons.txt:83(搜「countingSort」) · text/19-fm-sorting-without-comparisons.txt:113(搜「Hollerith」) |
| 低效五种 | Inefficient Sorting Algorithms | text/20-fm-inefficient-sorting-algorithms.txt:12(搜「Stooge」) · text/20-fm-inefficient-sorting-algorithms.txt:42(搜「bogus」) · text/20-fm-inefficient-sorting-algorithms.txt:55(搜「sleepSort」) |
| 习题 6.1–6.14 | Questions | text/22-fm-questions.txt:4(搜「Forced Reversal」) |
| 答案(三路划分/XOR/fill 坑) | Chapter 6 | text/69-ch06-chapter-6.txt:106(搜「quickSort」) · text/69-ch06-chapter-6.txt:36(搜「XOR」) · text/69-ch06-chapter-6.txt:159(搜「reference to the same array」) |
Footnotes
-
出处:「Sorting with Comparisons」第 23–54 段(
text/18-fm-sorting-with-comparisons.txt:23,搜「bubble up」)。原文:每趟把最大值换到右端;比较总数 (n−1)+(n−2)+…+1 = n(n−1)/2,故 O(n²)。 ↩ -
出处:「Chapter 6」第 61–75 段(
text/69-ch06-chapter-6.txt:63,搜「swaps」)。答案原文:每趟设swaps = false,有交换置 true,趟末if (!swaps) break;——近有序输入提前收工。 ↩ -
出处:「Sorting with Comparisons」第 168–214 段(
text/18-fm-sorting-with-comparisons.txt:168,搜「playing cards」)。原文:插入排序像理牌,前段已有序、新牌插到位;优化版先把新元素存 temp 再右移,一趟一次写入。 ↩ -
出处:「Sorting with Comparisons」第 339–362 段(
text/18-fm-sorting-with-comparisons.txt:339,搜「quickSort」)。原文:选最右为 pivot,扫一趟把小的换左侧,pivot 落位 p,递归两段;「平均 O(n log n)」;已排序输入「划分总是只剩一个子数组,相当于选择/冒泡,性能掉到 O(n²)」。 ↩ -
出处:「Sorting with Comparisons」第 442–500 段(
text/18-fm-sorting-with-comparisons.txt:456,搜「dualPivot」)。原文:双 pivot 把数组分三段;「通常更快——Java 把它用作原生类型数组的默认排序」;书上给了维护五段不变式的完整划分代码。 ↩ -
出处:「Sorting Without Comparisons」第 83–103 段(
text/19-fm-sorting-without-comparisons.txt:83,搜「countingSort」)。原文:计数表 + 落点表;「最小键(47)的输出从位置 0 起,下一个键因有两个 47 而从位置 2 起」;每个元素落位后对应落点 +1。 ↩ ↩2 -
出处:「The Sorting Problem」第 4 段(
text/17-fm-the-sorting-problem.txt:4,搜「permutation」)。原文:排序算法「重排列表使键非降序,且输出列表是输入的一个排列,保留所有原记录」。 ↩ -
出处:「The Sorting Problem」第 7 段(
text/17-fm-the-sorting-problem.txt:7,搜「wrongWayToSort」)。原文给出const wrongWayToSort = (inputData) => [];作为「忘记第二条」的反例。 ↩ -
出处:「The Sorting Problem」第 19–22 段(
text/17-fm-the-sorting-problem.txt:19,搜「External」)。原文:外部排序分段落盘再归并;「对这种大排序任务,你最好使用标准系统 sort 工具,它还可能用并行线程、多 CPU 优化」。 ↩ -
出处:「The Sorting Problem」第 42 段(
text/17-fm-the-sorting-problem.txt:42,搜「In-Place」)。原文:快排内部用 O(log n) 栈也算原地;归并需要 O(n) 额外空间,属 out-of-place。 ↩ -
出处:「The Sorting Problem」第 55–61 段(
text/17-fm-the-sorting-problem.txt:55,搜「online」)。原文:在线算法边收边排、保持时刻有序;「在线算法不知道整个输入,必须做出日后可能证明是次优的决定——与贪心算法同样的处境」。 ↩ -
出处:「The Sorting Problem」第 71–85 段(
text/17-fm-the-sorting-problem.txt:71,搜「stable」)。原文:稳定排序保持相等键的相对顺序;例子:联系人先按名字排、再按星标排,稳定则名字序保住;「正是稳定性让 Joliet 排在 Romeo 前面」。 ↩ -
出处:「The Sorting Problem」第 88 段(
text/17-fm-the-sorting-problem.txt:88,搜「extended key」)。原文:任何排序都能强转稳定——把键扩成「原键 + 原位置」,按扩展键排序,相等键自动保持原相对顺序,排完丢掉附加字段。 ↩ -
出处:「The Sorting Problem」第 32 段(
text/17-fm-the-sorting-problem.txt:32,搜「adaptive」)。原文:自适应算法利用输入已有序性;希尔是,快排「可算反自适应」(最坏恰在输入有序时)。 ↩ -
出处:「The Sorting Problem」第 109–120 段(
text/17-fm-the-sorting-problem.txt:109,搜「toSorted」)。原文:不传比较函数时转字符串按字典序排,[22, 9, 60, 12, 4, 56].sort()得[12, 22, 4, 56, 60, 9];传(a, b) => a - b得正确数字序。 ↩ -
出处:「The Sorting Problem」第 106 段(
text/17-fm-the-sorting-problem.txt:106,搜「most effective」)。原文:「尽管本章后面会考虑更多(可能更好)的排序算法,在许多情况下用 JavaScript 自己的 sort 可能最有效。」 ↩ ↩2 -
出处:「The Sorting Problem」第 180–186 段(
text/17-fm-the-sorting-problem.txt:180,搜「20 questions」)。原文:20 个是非题能从 2²⁰=1,048,576 个可能中锁定;排序要区分 n! 种排列,需 log(n!) 次比较;由斯特林近似 log(n!)=O(n log n),故「任何基于比较的算法至少 O(n log n)」;「若不实际比较,一切赌注作废」。 ↩ ↩2 -
出处:「Sorting with Comparisons」第 234–262 段(
text/18-fm-sorting-with-comparisons.txt:234,搜「rabbits」)。原文:大值是兔子(快速右移),小值是乌龟(一趟一格);间距每趟除以 1.3,收到 1 退回冒泡;最坏 O(n²),最好 O(n log n)。 ↩ -
出处:「Sorting with Comparisons」第 286–305 段(
text/18-fm-sorting-with-comparisons.txt:286,搜「shellSort」)。原文:Knuth(1973)序列 1,4,13,40,…(每项 3 倍+1),降序应用;末趟是插入排序但面对近乎有序输入;「得 O(n^1.5) 算法」。 ↩ -
出处:「Sorting with Comparisons」第 378–401 段(
text/18-fm-sorting-with-comparisons.txt:378,搜「iPivot」)。原文:随机取 pivot「几乎解决了近有序数组的最坏行为,但仍有极低概率一直取到最值」;三值取中:左中右排序后中位数落最右;更强有 ninther。 ↩ -
出处:「Sorting with Comparisons」第 414–432 段(
text/18-fm-sorting-with-comparisons.txt:417,搜「CUTOFF」)。原文:分段小于 CUTOFF=7 换插入排序;「粗体那几行就是全部改动」。 ↩ -
出处:「Chapter 6」第 106–141 段(
text/69-ch06-chapter-6.txt:117,搜「[arr[p]」)。答案原文:pivot 归位后,从 p 向左把等于 pivot 的元素换到左端(pl),从 p 向右换到右端(pr);[pl, pr]全是 pivot,递归只排两侧。 ↩ -
出处:「Sorting with Comparisons」第 580 段(
text/18-fm-sorting-with-comparisons.txt:580,搜「Tim sort」)。原文:TimSort 稳定自适应,利用已有有序段(run),「Java 用它,JavaScript 的 V8 引擎也用它」;实现近 1000 行,本书不展开,「你已经学齐了构成 TimSort 的所有零件」。 ↩ ↩2 -
出处:「Sorting Without Comparisons」第 15–59 段(
text/19-fm-sorting-without-comparisons.txt:15,搜「suppositions」)。原文:三条前提——只排数字、范围小、无重复;重复时直接抛错;「不能允许重复键是个严重限制」。 ↩ ↩2 -
出处:「Sorting Without Comparisons」第 121–133 段(
text/19-fm-sorting-without-comparisons.txt:113,搜「Hollerith」)。原文:分类机按列分桶,从第 6 列收到第 1 列;「收回卡片时发现已按两列有序(回到稳定性一节理解为什么)」;详细实现留到第 10 章用列表模拟桶。 ↩ -
出处:「Inefficient Sorting Algorithms」第 12、22、32、42、52–56 段(
text/20-fm-inefficient-sorting-algorithms.txt:12,搜「Stooge」;text/20-fm-inefficient-sorting-algorithms.txt:42,搜「bogus」)。原文依次:Stooge O(n^2.71);Slow 排序「multiply and surrender」,C(n)=2C(n/2)+C(n−1)+1;排列排序平均试 n!/2 个;Bogosort 52 张牌约 1/52!;睡眠排序「数据足够大时会崩(太多挂起的 timeout)或失败」。 ↩ -
出处:「Chapter 6」第 159 段(
text/69-ch06-chapter-6.txt:159,搜「reference to the same array」)。答案原文:Array(10).fill([])会让所有桶指向同一个数组;Array(10).map(...)则因.map跳过空位什么都不做。 ↩