ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

freeCodeCamp 课程设计解析:用递归分治实现快速排序(Quick Sort)

freeCodeCamp 课程设计解析:用递归分治实现快速排序(Quick Sort) freeCodeCamp 课程设计解析用递归分治实现快速排序Quick Sort【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本文基于 freeCodeCamp 课程大纲中的 Implement Quick Sort 挑战文档展开系统讲解快速排序的分治思想、pivot 分区策略与递归收敛过程并逐条剖析该挑战的四组测试断言、种子代码与官方参考实现帮助你掌握一套不依赖内置.sort()的完整排序算法实现方案同时了解这道题在 freeCodeCamp 课程体系中的定位与演进。挑战背景快速排序在 freeCodeCamp 课程体系中的位置本挑战的源文档是 Implement Quick Sort挑战 ID 为587d825a367417b2b2512c89属于 JavaScript Algorithms and Data Structures 方向的核心练习题。从课程结构配置看这道题被组织在algorithms板块中见 algorithms.json其挑战顺序为Find the Symmetric DifferenceInventory UpdateNo Repeats PleasePairwiseImplement Bubble SortImplement Selection SortImplement Insertion SortImplement Quick Sort本文主题Implement Merge SortImplement Binary Search可以看到快速排序被安排在三类基础排序冒泡、选择、插入之后、归并排序之前形成从 O(n²) 的直观算法逐步过渡到 O(n log n) 高效算法的递进学习路径。该板块整体隶属于 Coding Interview Prep 超单元见 coding-interview-prep.json面向面试算法准备场景。值得注意的是同一个挑战 ID 还被复用于新版 JavaScript 课程体系JS v9中的多文件编辑器实验题lab-quicksort-js见 lab-quicksort-js.json 与 javascript-v9.json。在 JS v9 的algorithms模块中它排在lab-insertion-sort之后、review-searching-and-sorting-algorithms-js与 quiz 之前即作为排序算法系列的收官实验题出现。这个复用在后文会进一步展开。快速排序核心思想分治、分区与递归收敛原挑战文档对快速排序给出了如下的标准定义快速排序是一种高效的、递归的分治divide-and-conquer排序方法。其过程是在原始数组中选取一个 pivot枢轴值然后将数组分区为两个子数组——一个存放小于 pivot 的值一个存放大于 pivot 的值随后对这两个子数组递归调用快速排序算法并合并两者的结果这一过程持续进行直到达到空数组或单元素数组的基准情形base case并直接返回递归调用逐层展开unwinding后最终得到有序数组。拆解这句话可以得到快速排序的四个关键要素分治Divide and Conquer把排序整个数组的问题分解为排序两个更小的子问题这是递归算法成立的前提Pivot 选择从原数组中取一个值作为枢轴。文档明确指出虽然 pivot 的选择很重要但对本练习而言任意 pivot 均可为简化实现可以直接取首元素或末元素分区Partition一次遍历把元素划到小于 pivot与大于 pivot两侧基准情形空数组或只有一个元素的数组天然有序直接返回递归在此终止。关于性能文档给出的结论是快速排序平均性能为O(n log n)且实现相对容易这两个属性使其成为一种流行且实用的排序方法。可以推断文档中特意强调pivot 选择很重要对应的正是快速排序的经典退化风险若每次选中的 pivot 恰好是子数组的最大值或最小值例如对已有序数组固定取首元素分区将极度不平衡递归退化为 O(n) 深度的链式调用平均 O(n log n) 便无法保证。这也是为什么工业实现常采用三数取中、随机化 pivot 等策略。题目要求与约束原文档的 Instructions 部分给出了明确的实现规格编写函数quickSort接收一个整数数组作为输入返回这些整数从小到大排序后的数组。pivot 的选择虽重要但此处任意 pivot 均可为简单起见可使用首元素或末元素。种子代码seed非常简洁只留出了待填写的函数体function quickSort(array) { // Only change code below this line return array; // Only change code above this line }也就是说题目要求在不修改函数签名的前提下在quickSort内部完成完整的排序逻辑且不能借助Array.prototype.sort这一点由后文的测试强制约束。逐条解析四组测试断言挑战文档的--hints--部分包含四组测试它们共同界定了正确实现的完整验收标准。逐条分析如下1.quickSort必须是一个函数assert(typeof quickSort function);类型守卫防止提交者用变量或直接赋值的方式绕开函数式实现。2. 返回值必须是升序有序数组function isSorted(a){ for(let i 0; i a.length - 1; i) if(a[i] a[i 1]) return false; return true; } assert.isTrue( isSorted( quickSort([ 1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92 ]) ) );这里自定义了isSorted校验器通过相邻元素两两比较a[i] a[i 1]即判负验证非降序性质。测试输入是一个 17 个元素的乱序数组且刻意包含重复值1、2、43、123各出现两次——这对实现是一个隐含挑战如果分区只考虑和两个分支而丢弃等于 pivot 的元素或者把重复元素错误地丢弃测试就会失败。3. 结果数组与原数组仅顺序不同成员守恒assert.sameMembers( quickSort([ 1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92 ]), [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92] );assert.sameMembers要求结果数组与原始数组拥有完全相同的元素集合含重复计数不允许丢失或新增任何元素。结合测试 2有序 成员守恒两者同时成立等价于这是一个正确的排序。4. 禁止使用内置.sort()方法function isBuiltInSortUsed(){ let sortUsed false; const temp Array.prototype.sort; Array.prototype.sort () sortUsed true; try { quickSort([0, 1]); } finally { Array.prototype.sort temp; } return sortUsed; } assert.isFalse(isBuiltInSortUsed());这是四组测试中最有教学价值的一组。它采用了典型的猴子补丁monkey patching手法先把原始的Array.prototype.sort备份到temp用探针函数替换它一旦被调用就置位sortUsed在try/finally中调用被测的quickSort([0, 1])并在finally中无论是否抛错都恢复原方法保证测试环境不被污染最终断言探针从未被触发。这个设计把必须自己实现排序从口头约束变成了可执行的运行时检测也提醒实现者即使只调用一次.sort()哪怕是隐藏在某处都会被捕获。官方参考实现三路分区的完整解析文档--solutions--部分给出的官方解法源文档如下function quickSort(array) { if (array.length 0) { return []; } else { const pivotValue array[0]; // Sort elements into three piles let lesser []; let equal []; let greater []; for (let e of array) { if (e pivotValue) { lesser.push(e); } else if (e pivotValue) { greater.push(e); } else { equal.push(e); } } return [...quickSort(lesser), ...equal, ...quickSort(greater)]; } }可以把它拆解为四个步骤基准情形array.length 0时直接返回[]。这是递归终止条件——因为每次递归处理的子数组都严格小于原数组pivot 本身被移入equal堆不再参与递归递归必然终止。选 pivotconst pivotValue array[0]直接取首元素正是文档 Instructions 中为简化可取首或末元素的落地。三路分区three-way partition单次for...of遍历把全部元素分入lesser/equal/greater三个堆piles。注意它没有采用经典的两路分区 原地交换写法而是构建新数组。从源码结构看这种写法有两个直接收益不修改输入数组题目未要求原地排序构建新数组天然避免了副作用equal堆专门收集所有等于 pivot 的元素含 pivot 自身从而天然、安全地处理了测试数组中大量存在的重复值——这些元素一次分区后便永久归位不再进入递归。递归合并[...quickSort(lesser), ...equal, ...quickSort(greater)]一行完成递归左半 已归位的等值元素 递归右半的拼接。equal堆放在中间且不再递归正是分治合并combine步骤的具体形态。以输入[3, 1, 2]走一遍pivot 为3lesser [1, 2]、equal [3]、greater []返回[...quickSort([1,2]), 3, ...quickSort([])]继续递归[1,2]得[1, 2]最终[1, 2, 3]。递归的展开—收敛过程与文档中 The unwinding of the recursive calls return us the sorted array 的描述完全对应。复杂度视角文档给出的结论是平均 O(n log n)。结合上述实现可以进一步说明分区阶段每层对每个元素做一次常数次比较与一次push是 O(n)当 pivot 大致落在中间时递归深度约为 log(n)故总量为 O(n log n) 次比较。可以推断由于本实现固定取首元素且不做随机化面对已有序/逆序输入时递归深度会退化到 n 级但在课程练习语境下这一点被题目any pivot will do的说明明确豁免学习重点放在分治骨架本身而非 pivot 优化策略。同一挑战的实验室变体从练习题到 Lab原挑战challengeType: 1单文件编辑器在 JS v9 课程中以challengeType: 26的实验室lab形式复用其多文件版文档位于 lab-quicksort-js/587d825a367417b2b2512c89.md。两个版本的核心描述基本一致同样强调分治、pivot 分区与平均 O(n log n)但实验室版本有三处值得注意的差异函数名不同Lab 版要求实现的是quicksort全小写而 algorithms 板块的练习题要求quickSort驼峰——迁移代码时需注意命名测试断言更强Lab 版用assert.sameOrderedMembers直接对照精确的期望输出[1, 1, 2, 2, 4, 8, 32, 43, 43, 55, 63, 92, 123, 123, 234, 345, 5643]比练习题版的自定义isSortedsameMembers组合更严格两者都保留了同一段猴子补丁式的.sort()禁用检测User Stories 新增显式约束Lab 版列出三条用户故事其中第三条 Thequicksortfunction should recursively call itself to sort the array 明确要求实现必须递归调用自身把分治从隐含要求变成了验收标准。此外lab-quicksort-js是 JS v9algorithms模块倒数第三个板块其后是 review 与 quiz承担排序算法系列收口的角色同一 ID 的变体还出现在 Python 侧的lab-quicksort板块见 lab-quicksort.json说明 freeCodeCamp 把快速排序视为跨语言JavaScript / Python共同的必考算法实验。课程体系内与本题强相关的配套视频资源还包括 quicksort-video.md 与 implementing-quicksort-video.md。小结这篇课程文档浓缩了实现快速排序所需的完整知识闭环算法骨架pivot 分区 → 递归子数组 → 空/单元素基准情形 → 展开合并平均 O(n log n)实现要点官方解法采用三路分区lesser/equal/greater 展开运算符拼接天然处理重复值且不改写入参pivot 取首元素即可满足题目要求验收边界四组测试分别覆盖是函数、有序、成员守恒、禁用.sort()其中猴子补丁式检测是运行时验证未走捷径的典范写法体系定位该挑战在algorithms板块中承接选择/插入排序、先于归并排序并以 Lab 变体在 JS v9 与 Python 课程中复用是 freeCodeCamp 面试准备与新版课程共用的核心算法题。掌握本文的分区逻辑与测试约束后你可以直接以官方解法为基线完成提交也可以尝试把 pivot 换成末元素或随机元素、把三路分区改写为原地交换版本来进一步验证自己对递归收敛过程的理解。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表