当前位置: 首页 > news >正文

S14排序算法--基数排序

基数排序是一种非比较型排序算法,核心思想是「按位分组排序」—— 无需直接比较元素大小,而是按数字的每一位(个位、十位、百位...)或字符的 ASCII 码

其优势是时间复杂度稳定,适合处理大规模数字 / 字符串排序;缺点是依赖数据的 “位结构”,且需要额外空间存储桶或计数数组。

算法原理

  1. 位处理顺序

    • 最低位优先(LSD):先按个位排序,再按十位、百位...(最常用,实现简单)。

    • 最高位优先(MSD):先按百位排序,再按十位、个位...(适合部分有序数据,需递归处理)。

  2. 底层排序:每一位的分组排序依赖「计数排序」或「桶排序」(必须是稳定排序,否则会破坏前一位的排序结果)。

  3. 核心逻辑:每处理一位,元素会按该位的大小初步有序;所有位处理完毕后,整个数组完全有序。

核心思路(以 LSD 为例,升序排序)

原始数组:[18, 94, 215, 789, 17, 934, 71, 85, 70, 147]核心规则:按「个位→十位→百位」逐位排序,每轮用计数排序(稳定排序)分组,最终实现整体升序。

预处理:确定关键参数

  1. 数组长度 n=10
  2. 最大元素:789(3 位),因此需处理 3 轮(d=0 个位、d=1 十位、d=2 百位);
  3. 基数 k=10(数字 0~9),每轮用大小为 10 的计数数组。

一、第 1 轮排序:按个位(d=0)

步骤 1:获取各位数字

原始数组元素 → 个位数字:18 (8)、94 (4)、215 (5)、789 (9)、17 (7)、934 (4)、71 (1)、85 (5)、70 (0)、147 (7)

步骤 2:计数数组统计次数

初始化计数数组 count[10] = {0},统计每个个位数字的出现次数:

  • 0:1 次(70)、1:1 次(71)、4:2 次(94、934)、5:2 次(215、85)、7:2 次(17、147)、8:1 次(18)、9:1 次(789)
  • 计数数组结果:count = [1, 1, 0, 0, 2, 2, 0, 2, 1, 1]

步骤 3:调整计数数组(确定最终位置,保证稳定性)

计数数组累加,存储每个数字的最终结束位置:

  • count[i] = count[i] + count[i-1](从 i=1 开始)
  • 调整后:count = [1, 2, 2, 2, 4, 6, 6, 8, 9, 10]

步骤 4:从后向前填充临时数组(维持稳定性)

临时数组 output[10],按 “原数组逆序 + 计数数组定位” 填充:

原数组索引元素个位数字计数数组对应值output 索引output 数组(填充后)
91477count[7]=87[70, 71, 94, 934, 215, 85, 17, 147, 18, 789]
8700count[0]=10
7855count[5]=65
6711count[1]=21
59344count[4]=43
4177count[7]=76
37899count[9]=109
22155count[5]=54
1944count[4]=32
0188count[8]=98

步骤 5:复制回原数组

第 1 轮后数组(个位有序):[70, 71, 94, 934, 215, 85, 17, 147, 18, 789]

二、第 2 轮排序:按十位(d=1)

步骤 1:获取各位数字

当前数组元素 → 十位数字:70 (7)、71 (7)、94 (9)、934 (3)、215 (1)、85 (8)、17 (1)、147 (4)、18 (1)、789 (8)

步骤 2:计数数组统计次数

count[10] = {0},统计十位数字出现次数:

  • 1:3 次(215、17、18)、3:1 次(934)、4:1 次(147)、7:2 次(70、71)、8:2 次(85、789)、9:1 次(94)
  • 计数数组结果:count = [0, 3, 0, 1, 1, 0, 0, 2, 2, 1]

步骤 3:调整计数数组

调整后:count = [0, 3, 3, 4, 5, 5, 5, 7, 9, 10]

步骤 4:从后向前填充临时数组

临时数组 output[10] 填充结果:[17, 18, 215, 934, 147, 70, 71, 85, 789, 94]

步骤 5:复制回原数组

第 2 轮后数组(十位有序):[17, 18,215 ,934, 147, 70, 71, 85, 789, 94]

三、第 3 轮排序:按百位(d=2)

步骤 1:获取各位数字

当前数组元素 → 百位数字:17 (0)、18 (0)、215 (2)、934 (9)、147 (1)、70 (0)、71 (0)、85 (0)、789 (7)、94 (0)

步骤 2:计数数组统计次数

count[10] = {0},统计百位数字出现次数:

  • 0:6 次(17、18、70、71、85、94)、1:1 次(147)、2:1 次(215)、7:1 次(789)、9:1 次(934)
  • 计数数组结果:count = [6, 1, 1, 0, 0, 0, 0, 1, 0, 1]

步骤 3:调整计数数组

调整后:count = [6, 7, 8, 8, 8, 8, 8, 9, 9, 10]

步骤 4:从后向前填充临时数组

临时数组 output[10] 填充结果:[17, 18, 70, 71, 85, 94, 147, 215, 789, 934]

步骤 5:复制回原数组

第 3 轮后数组(百位有序):[17, 18, 70, 71, 85, 94, 147, 215, 789, 934]

四、最终排序结果

[17, 18, 70, 71, 85, 94, 147, 215, 789, 934]

C 语言实现(LSD 基数排序,基于计数排序)

选择「计数排序」作为底层排序(稳定、高效、空间开销小),支持非负整数排序(可扩展至负数、字符串)。

1. 核心辅助函数:获取数字的某一位

int getmax(int arr[], int len) {int r = arr[0];for (int i = 1; i < len; i++) {if (r < arr[i]) {r = arr[i];}}return r;
}

2. 核心辅助函数:计数排序(按某一位排序)

辅助队列实现:

void Count_Sort(int arr[], int len, int epfd) {queue<int> bucket[10];int* out = (int*)malloc(len * sizeof(int));for (int i = 0; i < len; i++) {int index = (arr[i] / epfd) % 10;bucket[index].push(arr[i]);}int r = 0;for (int i = 0; i < 10; i++) {while (!bucket[i].empty()) {arr[r++] = bucket[i].front();bucket[i].pop();}}
}

不借助队列:

void Count_Sort1(int arr[], int len, int epfd) {int* out = (int*)malloc(len * sizeof(int));int count[10] = { 0 };// 步骤1:统计当前位各数字的出现次数for (int i = 0; i < len; i++) {count[(arr[i] / epfd) % 10]++;}// 步骤2:修改计数数组,使其存储最终位置(保证稳定性)for (int i = 1; i < 10; i++) {count[i] += count[i - 1];}// 步骤3:从后向前遍历原数组,按当前位放入临时数组(维持稳定性)for (int i = len - 1; i >= 0; i--) {int index = (arr[i] / epfd) % 10;out[count[index] - 1] = arr[i];count[index]--;}// 步骤4:将临时数组复制回原数组for (int i = 0; i < len; i++) {arr[i] = out[i];}free(out);out = NULL;
}

3.基数排序主函数

void Radix_Sort(int arr[], int len) {int max = getmax(arr, len);for (int epfd = 1; max / epfd > 0; epfd *= 10) {Count_Sort(arr, len, epfd);}
}

复杂度分析与优缺点

1. 复杂度

时间复杂度空间复杂度稳定性
O(d×(n+k))O(n+k)稳定
  • 说明:

    • d:最大元素的位数(如 999→d=3);

    • n:数组长度;

    • k:每一位的基数(数字为 10,字符为 256)。

  • 实际场景中,d 通常是常数(如整数最多 10 位),因此时间复杂度可近似为 O (n),效率极高。

2. 优缺点

核心优点核心缺点
非比较排序,效率高(近似 O (n))依赖数据结构(仅支持数字、字符串等有 “位” 的数据)
稳定排序(适合多字段排序)需要额外空间(临时数组 + 计数数组)
大规模数据排序性能优异不适合小数、负数(需额外处理符号和小数点)

总结

基数排序的核心是「按位分桶 + 稳定排序」,通过非比较的方式避开了 O (n log n) 的下界,在大规模数字 / 字符串排序中性能优异。其关键是保证底层排序的稳定性,否则会破坏前一位的排序结果。

http://www.dtcms.com/a/585783.html

相关文章:

  • 人工智能之数学基础:连续型随机变量的期望
  • 江苏省住房和城乡建设厅网站首页东莞微联建站
  • SVG 简介
  • PostgreSQL 高可用实战:流复制主从集群(0 数据丢失 + 故障无缝切换)
  • antd Form表单实践模板(Form.useForm)
  • 数据结构与算法概述
  • n8n + Pinecone + ModelScope:知识库向量查询工作流实战
  • C++ 面向对象三大特性之一---多态
  • 合肥企业网站建设网站图片怎样做seo优化
  • 短剧小程序 2025 核心痛点分析:内容、技术与合规的三重困境
  • 河南省住房和城乡建设厅网站查证网站前台右侧怎么做二维码
  • 从原理到实操:ddraw.dll是什么?为何游戏启动时频繁提示“找不到ddraw.dll”?解决思路全解析
  • 计算机网络自顶向下方法39——网络层 中间盒 互联网架构原则(IP沙漏 端到端原则)
  • 广州有做虚拟货币网站视频创作用什么软件
  • wap网站和app开发正邦集团招聘
  • RV1126 NO.43:OPENCV形态学基础之二:腐蚀
  • 算法学习 24 使用集合解决问题
  • Java基础——集合进阶3
  • Ascend C 编程模型揭秘:深入理解核函数与任务并行机制
  • 算法题——002
  • 佛山微信网站开发易语言网站开发教程
  • 从零搭建PyTorch计算机视觉模型
  • 培训课程网站建设淮阳 网站建设
  • 服务器为何成为网络攻击的“重灾区“?
  • Linux rcu机制
  • ES 总结
  • j集团公司的网站建设石家庄百度推广优化排名
  • k8s-node-NotReady后如何保证服务可用
  • 5-GGML:看一下CUDA加法算子!
  • 做网站优化需要做哪些事项wordpress圆圈特效