1. 计数排序的基本概念与核心思想计数排序Counting Sort是一种非比较型的整数排序算法它通过统计每个元素的出现次数来确定元素在输出序列中的位置。与基于比较的排序算法如快速排序、归并排序不同计数排序不通过元素间的比较来决定顺序这使得它能够突破O(nlogn)的时间复杂度下限在最理想情况下达到线性时间复杂度O(n)。计数排序的核心思想可以用一个简单的例子来说明假设我们需要对一组年龄在0-100岁之间的人进行排序。我们可以创建一个大小为101的数组索引0-100然后遍历所有人统计每个年龄出现的次数。例如如果有3个人是25岁那么数组索引25的位置就存储数字3。最后我们只需要按照数组索引顺序输出相应次数的年龄值即可得到有序序列。注意计数排序之所以能够实现线性时间复杂度是因为它利用了输入数据的特定性质——所有待排序元素都是整数且范围有限。这个特性使得我们可以直接使用元素值作为数组索引避免了比较操作。2. 计数排序的完整算法步骤2.1 统计频率阶段首先我们需要确定待排序数组中元素的最大值max_val这将决定计数数组的大小。计数数组count的大小应为max_val1因为需要包含0到max_val的所有可能值。max_val max(arr) count [0] * (max_val 1)然后我们遍历原始数组统计每个元素出现的次数for num in arr: count[num] 12.2 累加频率阶段接下来我们需要将计数数组中的值进行累加使得count[i]表示小于等于i的元素总数。这一步为后续确定每个元素的最终位置做准备for i in range(1, len(count)): count[i] count[i-1]2.3 构建有序数组阶段为了保持排序的稳定性相同元素的相对顺序不变我们需要反向遍历原始数组output [0] * len(arr) for num in reversed(arr): output[count[num]-1] num count[num] - 1这个阶段的关键点在于反向遍历保证了相同元素的相对顺序不变count[num]-1给出了当前元素在输出数组中的正确位置每次放置一个元素后相应计数减1为下一个相同元素预留位置3. 计数排序的时间与空间复杂度分析3.1 时间复杂度分解计数排序的时间复杂度可以分为三个部分找出最大值O(n) - 需要遍历整个数组统计频率O(n) - 再次遍历整个数组累加频率O(k) - 遍历计数数组k是数据范围构建输出数组O(n) - 第三次遍历原始数组因此总时间复杂度为O(n k)。当kO(n)时时间复杂度为线性O(n)。3.2 空间复杂度分析计数排序需要额外的空间来存储计数数组O(k)空间输出数组O(n)空间因此总空间复杂度为O(n k)。当k远大于n时这会成为显著的缺点。实际应用提示在内存受限的环境中如果k值很大例如超过百万即使n很小计数排序也可能不适用。这种情况下可以考虑基数排序它通过多次计数排序来处理大范围数据。4. 计数排序的稳定性与实现细节4.1 为什么需要稳定性稳定性在排序算法中是一个重要特性它保证了具有相同关键字的元素在排序前后的相对位置不变。这在多关键字排序中尤为重要。例如当我们需要先按年龄排序再按姓名排序时保持稳定性可以确保相同年龄的人在姓名排序后仍然保持原来的相对顺序。4.2 实现稳定性的关键计数排序通过以下方式保证稳定性反向遍历原始数组这样后出现的相同元素会被放在输出数组中更靠前的位置递减计数每次放置元素后减少相应计数确保下一个相同元素被放在前一个位置考虑以下例子 原始数组[(a,2), (b,1), (c,2)] 稳定排序后应为[(b,1), (a,2), (c,2)]如果不反向遍历可能会得到[(b,1), (c,2), (a,2)]这就不稳定了。4.3 边界情况处理在实际实现中还需要考虑一些边界情况空数组输入直接返回空数组所有元素相同算法仍然有效包含负数需要调整计数数组的索引方式后面会详细讨论5. 计数排序的变体与优化5.1 处理负数的情况标准计数排序假设所有输入都是非负整数。要处理包含负数的情况我们需要做一些调整def counting_sort_with_negatives(arr): min_val min(arr) max_val max(arr) count [0] * (max_val - min_val 1) # 统计频率 for num in arr: count[num - min_val] 1 # 累加频率 for i in range(1, len(count)): count[i] count[i-1] # 构建输出数组 output [0] * len(arr) for num in reversed(arr): output[count[num - min_val] - 1] num count[num - min_val] - 1 return output这个变体的关键点是将所有元素平移min_val个单位使得最小的元素对应计数数组的索引0。5.2 节省空间的实现当只需要排序而不需要稳定性时可以简化实现并节省空间def simplified_counting_sort(arr): if not arr: return [] max_val max(arr) count [0] * (max_val 1) for num in arr: count[num] 1 output [] for num in range(len(count)): output.extend([num] * count[num]) return output这种实现更简单但不稳定且需要额外的O(n)空间构建输出列表。6. 计数排序的实际应用场景6.1 理想应用场景计数排序在以下情况下表现优异数据范围k较小例如0-100的考试成绩需要稳定排序的整数数据作为基数排序的子程序数据量较大但范围有限的场景如像素值排序6.2 不适用场景计数排序在以下情况下不适用或效率低下数据范围k非常大如排序10个1到1亿之间的数非整数数据如浮点数或字符串内存受限的环境6.3 与其他排序算法的比较算法平均时间复杂度最坏时间复杂度空间复杂度稳定性适用场景计数排序O(nk)O(nk)O(nk)是小范围整数快速排序O(nlogn)O(n²)O(logn)通常否通用排序归并排序O(nlogn)O(nlogn)O(n)是稳定排序,大数据量堆排序O(nlogn)O(nlogn)O(1)否内存受限环境7. 计数排序的代码实现与测试7.1 Python完整实现def counting_sort(arr): if len(arr) 0: return arr max_val max(arr) min_val min(arr) # 初始化计数数组 count [0] * (max_val - min_val 1) # 统计频率 for num in arr: count[num - min_val] 1 # 累加频率 for i in range(1, len(count)): count[i] count[i-1] # 构建输出数组 output [0] * len(arr) for num in reversed(arr): output[count[num - min_val] - 1] num count[num - min_val] - 1 return output # 测试用例 test_cases [ [], [1], [1,1,1,1], [4,2,2,8,3,3,1], [10,3,7,5,8,2,4,6,1,9], [-5,3,-2,0,1,-3,4,-1,2], [10000,9999,10000,9998,10001] ] for i, test in enumerate(test_cases): print(fTest case {i1}: {test}) print(fSorted: {counting_sort(test)}) print()7.2 测试结果分析好的测试应该覆盖以下情况空数组单元素数组所有元素相同包含重复元素正数和负数混合大范围数据通过全面测试可以验证算法的正确性和鲁棒性。在实际开发中还应该添加单元测试来确保每次修改不会引入回归错误。8. 计数排序的常见问题与调试技巧8.1 常见错误数组索引越界忘记计数数组大小应为max_val1处理负数时没有正确平移索引不稳定排序正向遍历原始数组而非反向遍历没有正确处理相同元素的顺序性能问题当k很大时计数数组占用过多内存多次遍历数组导致常数因子较大8.2 调试技巧打印中间结果统计频率后的计数数组累加频率后的计数数组每次放置元素后的输出数组使用小测试用例手工计算预期结果逐步验证算法每一步的正确性边界测试空数组单元素数组全相同元素数组包含最小/最大可能值的数组9. 计数排序的进阶应用9.1 作为基数排序的子程序计数排序的稳定性使其成为基数排序的理想子程序。在基数排序中我们从最低位开始对每一位使用计数排序。例如对三位数排序按个位数计数排序按十位数计数排序保持个位数顺序按百位数计数排序保持前两位顺序这样就能得到完全有序的数组。9.2 统计频率分布计数排序的统计阶段实际上已经计算了数据的频率分布。这在数据分析中很有用例如def frequency_distribution(arr): if not arr: return {} min_val min(arr) max_val max(arr) count [0] * (max_val - min_val 1) for num in arr: count[num - min_val] 1 return {i min_val: cnt for i, cnt in enumerate(count) if cnt 0}9.3 数据压缩对于包含大量重复值的数据计数排序的思想可以用于简单的数据压缩。例如存储值和对应的计数而不是存储每个元素原始数据[1,1,1,2,2,3,3,3,3] 压缩后[(1,3), (2,2), (3,4)]10. 从计数排序中学到的算法设计思想计数排序展示了几个重要的算法设计思想利用问题约束通过利用整数和有限范围的约束突破了比较排序的下限空间换时间使用额外空间来换取更好的时间复杂度稳定性设计通过反向遍历和递减计数实现稳定排序分阶段处理将算法分解为统计、累加和构建三个阶段每个阶段解决一个子问题这些思想在其他算法设计中也很常见例如桶排序、基数排序和哈希表实现等。
企业数字化 ERP 产品动态
相关推荐
智能体工具调用系统设计与优化实战指南 1. 项目概述在智能体开发领域,工具调用系统是构建高效Agent的核心模块。这个实战指南将深入探讨如何设计和实现一个可靠的Agent工具调用系统,帮助开发者掌握从基础架构到高级优化的全流程技术要点。作为从业者,我经历过多个Agent项目的开发&a… · 2026/11/2 21:41:24
PagedAttention:大模型KV Cache内存管理革新 1. PagedAttention机制概述在大型语言模型推理过程中,KV Cache(键值缓存)的内存管理一直是制约推理效率的瓶颈。传统KV Cache管理方式会导致显存碎片化严重,特别是在处理长序列或并发请求时,GPU显存利用率往往不足50%。… · 2026/11/2 21:41:24
Selenium+Pytest+Allure自动化测试实战指南 1. 项目概述:SeleniumPytestAllure测试组合的价值在Web应用开发中,UI自动化测试是保证产品质量的重要环节。这套技术组合中,Selenium负责浏览器自动化操作,Pytest作为测试执行框架,Allure则提供可视化报告,… · 2026/11/2 21:41:24
联邦学习最新进展与落地实践:破解数据孤岛与隐私保护 1. 联邦学习为什么突然成了AI圈的“显学”在IJCAI的多次会议上,杨强反复强调一个判断:AI落地最大的障碍不是模型不够强,而是数据走不出各自的“围墙”。这一点我深有体会。过去几年跟银行、医院、制造企业打交道,大家遇到的第一个… · 2026/11/2 22:18:44
前端打包编译全流程解析:从入口扫描到产物生成 1. 前端打包编译不是黑箱,是可拆解、可调试、可优化的确定性流程“前端打包和编译”这八个字,对刚入行的开发者像一道雾里看花的门槛——写完React组件,npm run build一敲,几秒后生成一个 dist 文件夹,里面全是带哈希的… · 2026/11/2 22:18:44
ZCode深度解析:以代码为中心的智能体运行平台 1. ZCode是什么?先别急着下结论说实话,第一次看到"ZCode 开源了"这几个字的时候,我和大部分人的反应一样——ZCode?这是什么?是编辑器?是框架?还是某个大厂憋了很久的IDE大招… · 2026/11/2 22:18:44
自然语言处理(NLP)为何是人工智能的核心?应用场景与优势解析 "现在做人工智能的,十个里有八个在聊大模型,但聊到最后往往绕回同一个底层技术——NLP,也就是自然语言处理。"这是我前阵子带一个AI项目时最深的体会。项目本身是做智能客服,客户一开始只看准确率指标,觉得&… · 2026/11/2 22:18:44
快消企业内训PPT拆解:从索引表到可复用课件的四步法 简介:这份康师傅培训资料以PPT形式梳理快消品企业的经营与管理实践,面向市场营销、产品运营、供应链及人力资源管理方向的学习者与从业者,可用于课堂案例分析、企业内训备课或建立行业认知框架。压缩包内仅含1个PPT文件,大小约1.2… · 2026/11/2 22:18:44
健康饮水技术解析:从净水原理到场景化解决方案 1. 养水堂产品矩阵概述:健康饮水解决方案的全面布局 养水堂作为国内健康饮水领域的专业品牌,其产品矩阵构建逻辑始终围绕"场景化需求"这一核心理念展开。不同于传统净水设备厂商的单品思维,养水堂通过系统化的产品组合设计… · 2026/11/2 22:16:43
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
雷达信号调制技术解析:从LFM到伪线性调频原理与应用 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
基于MAX14431与TM4C123的工业SPI隔离电路设计全攻略 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
PLFM_RADAR:相位线性调频雷达信号处理框架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18