教程文档知识库【免费下载链接】AlgoNote⛽️「算法通关手册」从零开始的「算法与数据结构」学习教程200 道「算法面试热门题目」1000 道「LeetCode 题目解析」持续更新中项目地址https://gitcode.com/gh_mirrors/le/AlgoNote点击查看免费下载基数排序Radix Sort是 AlgoNote「算法通关手册」数组排序章节中的一种非比较排序算法它通过按位分配 按序收集的方式将排序时间复杂度降低到与数据范围无关的 $O(n \times k)$。本篇文章以 docs/01_array/01_12_array_radix_sort.md 为主体结合仓库中的 Python 实现源码 与 链表变体实现系统讲解基数排序的算法思想、执行步骤、代码实现、复杂度分析与适用场景并串联 LeetCode 排序数组题解 与 最大间距题解 两个实战案例。读完本篇你将掌握基数排序最低位优先法的完整实现细节理解其稳定排序与线性复杂度的来源并能在固定位数整数数据场景中正确选型。1. 基数排序算法思想基数排序Radix Sort基本思想按照数字的每一位进行排序从最低位到最高位逐位比较。与冒泡、快速、归并等基于比较元素大小的排序算法不同基数排序属于非比较排序它与计数排序、桶排序同属线性时间排序家族见 docs/01_array/01_02_array_sort.md 的排序算法分类。基数排序的核心洞察是既然一个整数可以按位拆分成多个独立维度那么就可以放弃元素之间的两两比较改为对每一位分别进行一次稳定的分桶排序多轮分桶叠加后即可得到全局有序序列。从仓库的 数组实现源码 可以直观看到算法的全部逻辑只围绕两个操作展开按位取数字num // (10 ** i) % 10提取第 $i$ 位$i0$ 为个位上的数字分桶收集以该位数字为下标写入buckets[10]再按桶序依次取出回填。整个过程中没有任何、比较操作这正是基数排序被归为非比较排序的代码层证据。2. 基数排序算法步骤基数排序算法可以采用「最低位优先法Least Significant Digit FirstLSD」或者「最高位优先法Most Significant Digit FirstMSD」。最常用的是「最低位优先法」。下面我们以最低位优先法为例讲解一下算法步骤确定最大位数遍历数组元素找到数组中最大值的位数 $k$它决定了需要进行多少轮分桶—收集。从最低位个位开始到最高位为止逐位对每一位进行排序创建 10 个桶每个桶分别代表 $0 \sim 9$ 中的一个数字按照每个元素当前位上的数字将元素放入对应桶中清空原始数组然后按照桶的顺序依次取出对应元素重新加入到数组中。之所以必须从最低位开始是因为低位的排序结果会在后续高位的排序中被保留下来前提是每轮分桶都保持稳定最终实现低位优先、高位定序的完整排序效果。2.1 完整示例演示我们以 $[692, 924, 969, 503, 871, 704, 542, 436]$ 为例演示基数排序的算法步骤。第一轮按个位$10^0$分桶个位数字桶内元素收集结果0空—18718712692, 542692, 54235035034924, 704924, 7045空—64364367空—8空—9969969收集后数组变为$[871, 692, 542, 503, 924, 704, 436, 969]$。第二轮按十位$10^1$分桶对上一轮结果继续分桶收集后数组变为$[503, 704, 924, 436, 542, 969, 871, 692]$。第三轮按百位$10^2$分桶对上一轮结果继续分桶收集后数组变为$[436, 503, 542, 692, 704, 871, 924, 969]$此时数组已完全升序。从演示可以看出每一轮收集完成后数组在该位及更低位的维度上就已经是有序的三轮叠加后整体有序。这一过程的每一步都可以在仓库源码 codes/python/01_array/array_sort_radix_sort.py 的 11~18 行中找到对应实现。3. 基数排序代码实现3.1 数组版本最低位优先法仓库中 数组基数排序源码 与教程文档 01_12_array_radix_sort.md 中的代码完全一致完整实现如下class Solution: def radixSort(self, nums: [int]) - [int]: # 桶的大小为所有元素的最大位数 size len(str(max(nums))) # 从最低位个位开始逐位遍历每一位 for i in range(size): # 定义长度为 10 的桶数组 buckets每个桶分别代表 0 ~ 9 中的 1 个数字。 buckets [[] for _ in range(10)] # 遍历数组元素按照每个元素当前位上的数字将元素放入对应数字的桶中。 for num in nums: buckets[num // (10 ** i) % 10].append(num) # 清空原始数组 nums.clear() # 按照桶的顺序依次取出对应元素重新加入到原始数组中。 for bucket in buckets: for num in bucket: nums.append(num) # 完成排序返回结果数组 return nums def sortArray(self, nums: [int]) - [int]: return self.radixSort(nums)逐行拆解关键点第 3 行size len(str(max(nums)))通过字符串化求最大值的位数。例如max(nums) 969时str(969)长度为 3于是执行 3 轮分桶。这里隐含一个前提——所有元素必须为非负整数否则str(max(nums))会因负号、小数点破坏位数的语义。第 7 行buckets [[] for _ in range(10)]固定创建 10 个桶对应十进制数字 $0 \sim 9$。若数据为十六进制可扩展为 16 个桶源码结构完全支持。第 11 行buckets[num // (10 ** i) % 10].append(num)是核心取位表达式。以num 692, i 1为例692 // 10 6969 % 10 9即十位数字为 9。第 14 行nums.clear()清空原数组为收集腾出位置避免 append 时与旧元素混淆。第 16~18 行按桶下标 $0 \to 9$ 顺序取出全部元素回填同一桶内保持原相对顺序这是基数排序稳定性的实现来源。3.2 可运行验证仓库源码文件末尾附带了可直接运行的自测用例print(Solution().sortArray([692, 924, 969, 503, 871, 704, 542, 436]))在仓库根目录执行即可验证python codes/python/01_array/array_sort_radix_sort.py输出结果应为[436, 503, 542, 692, 704, 871, 924, 969]与 2.1 节手推的最终结果一致。3.3 链表变体从数组到链表的迁移基数排序只关心键的位数、不依赖随机访问的特性使其天然适配链表结构。仓库提供了 链表基数排序实现配套讲解见 docs/02_linked_list/02_10_linked_list_radix_sort.md。其与数组版本的核心差异在于求最大位数改为遍历链表通过while cur:逐节点比较len(str(cur.val))得到size收集阶段重建链表用dummy_head ListNode(-1)哨兵节点串联各桶元素最后head dummy_head.next更新头指针分桶阶段同样复用buckets[cur.val // (10 ** i) % 10]取位表达式算法内核与数组版完全一致。这种同一算法、两种容器的写法也体现了 AlgoNote 仓库先数组、后链表的教学组织方式。4. 基数排序算法分析基数排序的复杂度指标如下指标复杂度说明最佳时间复杂度$O(n \times k)$所有数字位数相同$k$ 为最大位数最坏时间复杂度$O(n \times k)$所有数字位数相同$k$ 为最大位数平均时间复杂度$O(n \times k)$基数排序的时间复杂度与数据状态无关空间复杂度$O(n k)$需要 $n$ 个元素的存储空间和 $k$ 个桶稳定性稳定桶排序保证相等元素的相对位置不变对上述指标做进一步解读时间复杂度与数据状态无关无论数据是正序、逆序还是随机每一轮都必须完整遍历 $n$ 个元素完成分桶与收集共 $k$ 轮因此最好、最坏、平均复杂度均为 $O(n \times k)$不存在快速排序那样的退化风险。空间复杂度构成$O(n)$ 用于存放元素分桶时元素被复制到桶中再回填$O(k)$ 对应 10 个桶数组本身。由于 $k$ 通常很小十进制整数位数实际空间开销接近 $O(n)$。稳定性来源每轮分桶时元素按原数组顺序依次 append 进桶收集时又按桶序依次取出相等元素指当前位数字相同的相对次序在轮与轮之间被原样保留因此整体稳定。适用场景整数排序位数不多$k$ 较小数据范围大但位数固定例如 $32$ 位有符号整数范围内的大数排序电话号码、身份证号等固定位数数据。需要补充的局限性经典实现只直接支持非负整数若处理负数需先整体偏移为非负如统一加上最小值绝对值或对正负部分分别排序若处理浮点数/字符串则需要将键映射为可逐位比较的固定长度编码这解释了文档中只适用于整数排序的结论。5. 与其他排序算法的横向对比结合 docs/01_array/01_02_array_sort.md 的排序算法分类体系可将基数排序放到完整谱系中定位对比维度基数排序比较类排序快排/归并/堆计数排序桶排序是否比较元素否是否否时间复杂度$O(n \times k)$$O(n \log n)$ 起$O(n m)$$O(n)$平均依赖数据范围依赖位数 $k$不依赖依赖值域 $m$依赖桶划分质量稳定性稳定快排、堆排不稳定稳定稳定典型场景固定位数整数通用排序值域紧凑的小整数均匀分布数据其中计数排序的复杂度 $O(n m)$ 直接受值域 $m$ 影响当 $m$ 极大时不可用而基数排序通过按位拆分把大值域问题转化为 $k$ 轮小分桶问题这正是其在数据范围大但位数固定场景下优于计数排序的根本原因。6. 实战演练在 LeetCode 中运用基数排序教程文档末尾给出了三道配套练习题目仓库中均有完整题解可用于检验对基数排序的掌握程度。6.1 0912. 排序数组中等难度标签包含数组、分治、桶排序、计数排序、基数排序、排序。题目要求在 $1 \le nums.length \le 5 \times 10^4$、$-5 \times 10^4 \le nums[i] \le 5 \times 10^4$ 的范围内完成升序排序。由于数据允许负数直接套用经典基数排序会遇到负数取位问题需结合偏移处理——这也正好检验读者是否真正理解了取位表达式的适用前提。6.2 0164. 最大间距困难难度标签包含数组、桶排序、基数排序、排序是基数排序线性复杂度的典型实战案例。题解要求在线性时间复杂度和空间复杂度的条件下找出排序后相邻元素的最大差值其解题思路分两步用基数排序在 $O(n)$ 内完成数组排序利用题目所有元素都是非负整数、数值在 32 位有符号整数范围内的约束规避了负数处理问题线性遍历计算相邻差值并取最大值。题解中的radixSort实现与仓库数组源码 codes/python/01_array/array_sort_radix_sort.py 逐行一致并以max(arr[i] - arr[i - 1] for i in range(1, len(arr)))收尾最终整体复杂度为 $O(n)$。这道题完美诠释了数据范围大但位数固定时选基数排序的适用场景。6.3 0561. 数组拆分简单难度标签包含贪心、数组、计数排序、排序可作排序算法含计数排序的入门巩固题。更多排序类题目可在 docs/00_preface/00_06_categories_list.md 的数组排序算法题目表格中按需筛选。7. 总结基数排序是一种非比较排序算法通过按位分配和收集实现排序。优点时间复杂度与数据范围无关稳定排序适合固定位数数据缺点空间复杂度较高只适用于整数排序。一句话记忆基数排序用位换比较——它把对 $n$ 个元素的复杂比较转化为对 $k$ 位数字的 $k$ 轮简单分桶从而在固定位数整数场景下获得稳定的线性时间复杂度。与计数排序相比它不受值域上限约束与快速排序等比较排序相比它没有最坏退化风险但代价是 $O(n k)$ 的额外空间。在实际工程中请务必确认数据满足非负整数、位数固定且 $k$ 较小的前提再决定是否选用若数据含负数或浮点数需先做偏移或编码转换这正是 最大间距题解 特意强调所有元素都是非负整数的原因。掌握这一选型判断你就能像仓库中 数组实现 与 链表实现 展示的那样让同一套分桶思想在不同数据结构上自由迁移。赞分享教程文档知识库【免费下载链接】AlgoNote⛽️「算法通关手册」从零开始的「算法与数据结构」学习教程200 道「算法面试热门题目」1000 道「LeetCode 题目解析」持续更新中项目地址https://gitcode.com/gh_mirrors/le/AlgoNote点击查看免费下载相关推荐《Hello 算法》基数排序详解从计数排序的局限到 O(nk) 的按位排序实战《Hello 算法》基数排序详解从计数排序的局限到 O nk 的按位排序实战 基数排序radix sort是《Hello 算法》排序章节中一类以空间换时教程文档示例工程教育LeetCode-Py桶排序与基数排序非比较排序算法的应用技巧LeetCode Py桶排序与基数排序非比较排序算法的应用技巧 在处理大规模数据排序时传统比较排序算法如快速排序、归并排序往往受限于O n log n教程文档知识库Armbian 安装 Amlogic S905L2-B 盒子从镜像选择到首次联网的完整避坑流程Armbian 安装 Amlogic S905L2 B 盒子从镜像选择到首次联网的完整避坑流程 把你的 S905L2 B 电视盒刷上 Armbian替换掉原嵌入式开发工具构建工具操作系统上一篇Blender 3MF插件终极指南3D打印模型导入导出完整教程 下一篇终极VBA JSON解析指南5分钟实现Office数据自由交换创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考