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

排序算法(快排、归并、计数、基数排序)

排序

排序概览

排序方法时间复杂度(平均)时间复杂度(最坏)稳定性
快速排序nlognn方不稳定
归并排序nlognnlogn稳定
计数排序n+kn+k稳定
基数排序n kn k稳定
堆排序nlognnlogn不稳定
选择排序n方n方不稳定
冒泡排序n方n方稳定
插入排序n方n方稳定

一.快速排序

  1. 排序思想

    • 排序区间为[l, r]
      • 如果区间长度小于等于1则直接退出, 否则选一个区间中随机的数字xl位元素交换作为比较元素
      • 将大于x的数字放在左边, 小于的放在右边,等于的也要换边!!
      • 此时x的位置已经固定, 对两边区域的分别递归
    • 一开始的区间为[1, n]
    • 两个指针分别从lr开始向中间扫描, 直到相遇结束一次扫描
  2. 代码实现

    void quicksort(int l,int r){ if(l >= r) return; swap(a[l], a[l + rand() % (r - l + 1)]); int x = a[l]; int i = l, j = r; while(i < j){ while(i < j && a[j] > x) j--; if(i < j) a[i++] = a[j]; while(i < j && a[i] < x) i++; if(i < j) a[j--] = a[i]; } a[i] = x; quicksort(l, i - 1); quicksort(i + 1, r); }
  3. 补充

    • 实际打比赛可用sort()函数, 可以直接快排
    • 对于多关键字排序可以重构比较符号
    struct Node{ int x, y; bool operator < (const Node &A) const{ if(x != A.x) return x < A.x; return y < A.y; } } a[N + 1];
    • 找第k小的数用快排, 每一轮只要比较ik, 然后排一半即可

二.归并排序

  1. 排序思想
    • 排序区间为[l, r]
      • 如果区间长度为1则直接退出, 否则将区间分为[l, m][m+1, r]俩部分, 其中m = ( l + r ) / 2
      • 递归两个子区间进行排序
      • 将两个已经排好的子区间合并
    • 一开始只要对区间[1, n]排序即可
  2. 代码实现
    void mergesort(int l,int r){ if(l == r) return; int m = (l + r) / 2; mergesort(l, m); mergesott(m + 1, r); int p1 = l, p2 = m + 1, tot = 0; while(p1 <= m && p2 <= r){ if(a[p1] <= a[p2]) c[++tot] = a[p1++]; else c[++tot] = a[p2++]; } while(p1 <= m) c[++tot] = a[p1++]; while(p2 <= r) c[++tot] = a[p2++]; for(int i = 1; i<= tot; i++) a[i + l - 1] = c[i]; }

三.计数排序

  1. 排序思想

    • 统计每个数据出现了几次
    • 统计完每个元素后, 求一遍前缀和, 就知道每个数字在排序完后的序列中出现的位置
    • 把数字填入对应的位置即可
  2. 代码实现

    int n, m, a[N + 1], c[M + 1], r[N + 1]; inline void countingsort(){ memset(c, 0, sizeof(c)); for(int i = 1; i <= n; i++) ++c[a[i]]; for(int i = 1; i <= m; i++){ for(int j = 1; j <= c[i]; j++) printf("%d", r[i]); } printf("\n"); for(int i = 2; i <= m; i++) c[i] += c[i-1]; for(int i = n; i; --i) r[i] = c[a[i]]--; for(int i = 1; i<= n; i++) printf("%d", r[i]); printf("\n"); }
  3. 补充

    • 适用于值域范围较小的数字排列

四.基数排序

  1. 排序思想

    • 拆分成m个关键字, 从后往前对这些关键字排序, 每次排序会使用上一次的排序结果
    • 每一次是用计数排序来实现
    • 假设已经排完了第i个及以后的关键字, 现在要排第i - 1个关键字,这里是一个双关键字排序, 第一关键字是第i - 1个关键字, 第二关键字是第i个及以后的关键字的rank
    • 我们只需要把数字按照第i个及以后的关键字从小到大排序放在数组里, 再进行一次计数排序即可( 因为计数排序是稳定的 )
  2. 代码实现

    int n, m, a[N + 1], sa[N + 1], v[N + 1], r[N + 1], c[M + 1]; inline void countingsort(){ memset(c, 0, sizeof(c)); for(int i = 1; i <= n; i++) ++c[a[i]]; for(int i = 2; i <= m; i++) c[i] += c[i-1]; for(int i = n; i; --i) r[sa[i]] = c[v[sa[i]]]--; for(int i = 1; i<= n; i++) sa[r[i]] = i; } inline void radisort(){ for(int i = 1; i <= n; i++) sa[i] = i; int x = 1; for(int i = 1; i <= m; i++, x*=10){ for(int j = 1; j <=n; j++) v[j] = a[j] / x % 10; countingsort(); } }
  3. 补充

    • 基数排序经常被用于字符串的排序, 比如说后缀数组的核心就是基数排序
http://www.jsqmd.com/news/1244998/

相关文章:

  • 今天不学会这6种金句植入节奏,你的AI内容将永远困在流量洼地
  • C++嵌入式实时任务微秒级调度实践
  • 2026年7月最新欧米茄香港售后地址|网点电话与客服热线同步 - 欧米茄官方服务中心
  • AI编程落地避坑清单:23个真实项目踩过的雷,90%团队在第4步就失败了
  • ADC 分压采样电路原理与参数选型
  • 尼康D7500套机评测:APS-C画幅单反的平衡之道与实战指南
  • Claude Code:AI编程助手的革命性进化与实践指南
  • 虚拟机性能优化实战:从卡顿到流畅的完整方案
  • 劳力士重庆售后热线与地址:2026年7月最新客户服务指南 - 劳力士服务中心
  • 基于LLM的自然语言转SQL查询框架设计与实现
  • 企业API限流困境与多Key架构解决方案
  • Two Sigma OA 2026 真题复盘|105分钟3题完整记录(已通过)
  • SolidWorks设计树显示优化技术解析
  • AI小样本学习:从元学习到基础模型时代的Few-Shot实战
  • 嵌入式Bootloader核心模块与通信接口固件更新实战解析
  • TM4C129x Hibernation模块三大唤醒机制深度解析与实战配置
  • 2026年美制螺栓厂家推荐,哪家才是你的最优解? - 品牌排行榜
  • 深入解析LM3S2965引脚功能:从数据手册到硬件设计的实战指南
  • SECDED ECC原理与FMC诊断模式在功能安全系统中的应用
  • 注意力机制演进与工程实践:从MHA到GQA
  • 嵌入式低功耗设计:深入解析PCEMAC与PR寄存器的电源与时钟管理
  • 开源项目价值判断:从信任构建到可持续商业化的核心路径
  • 劳力士保养价格查询|服务电话及地址权威信息公告(2026年7月最新) - 劳力士官方服务中心
  • 伯爵中国售后服务中心地址及服务电话实地考察报告+多信源验证(2026年7月最新) - 亨得利官方服务中心
  • Unity相机后期处理实战:从Volume系统到移动端优化的完整指南
  • 知识城旧改局改装修公司哪家好:派福装饰品质担当 - MXyuyu
  • 深入解析ARM Cortex-M GPIO寄存器:从原理到实战配置
  • TI C2000 eCAP模块深度解析:从高精度捕获到无毛刺PWM生成
  • OpenAI Codex上下文窗口缩减:技术原理与工程实践应对策略
  • 深入解析EPI时序扩展寄存器:ARM Cortex-M外部存储接口稳定性的关键