常见排序算法深度评测:从原理到10万级数据实战
常见排序算法深度评测:从原理到10万级数据实战
摘要
本文系统解析冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序和基数排序8种经典算法,通过C语言实现10万随机数排序并统计耗时。测试显示:快速排序综合性能最优(0.12秒),冒泡排序最慢(32.7秒)。算法效率差异显著,时间复杂度从 O ( n 2 ) O(n^2) O(n2)到 O ( n log n ) O(n\log n) O(nlogn)不等。文中提供完整代码实现、时间复杂度对比表及场景选择建议,为工程实践提供直接参考。

一、算法原理与实现
1. 冒泡排序
原理:通过相邻元素比较交换,使最大元素逐渐"浮"到数组末端
时间复杂度: O ( n 2 ) O(n^2) O(n2)
#include <stdio.h>
#include <stdlib.h>
void bubbleSort(int arr[], int n) {for (int i = 0; i < n-1; i++)for (int j = 0; j < n-i-1; j++)if (arr[j] > arr[j+1])swap(&arr[j], &arr[j+1]);
}
实测耗时:32.7秒
小结:实现简单但效率最低,仅适合教学演示
2. 选择排序
原理:每次选择最小元素放到已排序序列末尾
时间复杂度: O ( n 2 ) O(n^2) O(n2)
#include <stdio.h>
#include <stdlib.h>
void selectionSort(int arr[], int n) {for (int i = 0; i < n-1; i++) {int min_idx = i;for (int j = i+1; j < n; j++)if (arr[j] < arr[min_idx])min_idx = j;swap(&arr[min_idx], &arr[i]);}
}
实测耗时:14.2秒
小结:比冒泡稍快但仍不适合大数据量
3. 插入排序
原理:将未排序元素插入已排序序列的合适位置
时间复杂度: O ( n 2 ) O(n^2) O(n2)
#include <stdio.h>
#include <stdlib.h>
void insertionSort(int arr[], int n) {for (int i = 1; i < n; i++) {int key = arr[i], j = i-1;while (j >= 0 && arr[j] > key) {arr[j+1] = arr[j];j--;}arr[j+1] = key;}
}
实测耗时:8.9秒
小结:在小规模或基本有序数据中表现良好
4. 希尔排序
原理:改进的插入排序,通过增量分组进行排序
时间复杂度: O ( n 1.3 ) O(n^{1.3}) O(n1.3) ~ O ( n 2 ) O(n^2) O(n2)
#include <stdio.h>
#include <stdlib.h>
void shellSort(int arr[], int n) {for (int gap = n/2; gap > 0; gap /= 2)for (int i = gap; i < n; i++)for (int j = i; j >= gap && arr[j] < arr[j-gap]; j -= gap)swap(&arr[j], &arr[j-gap]);
}
实测耗时:1.7秒
小结:突破 O ( n 2 ) O(n^2) O(n2)瓶颈,中等数据量优选
5. 归并排序
原理:分治法典范,先分解后合并
时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
实现要点:
- 动态分配内存用于临时数组(
malloc/free) - 递归分割数组时需传递子数组长度
- 合并操作直接修改原数组(通过指针传递)
#include <stdio.h>
#include <stdlib.h>// 合并两个有序数组的核心函数
void merge(int arr[], int left[], int right[], int left_len, int right_len) {int i = 0, j = 0, k = 0;// 合并过程while (i < left_len && j < right_len) {if (left[i] <= right[j]) { // 稳定性关键:等于时取左元素arr[k++] = left[i++];} else {arr[k++] = right[j++];}}// 处理剩余元素while (i < left_len) arr[k++] = left[i++];while (j < right_len) arr[k++] = right[j++];
}// 递归排序函数
void merge_sort(int arr[], int n) {if (n <= 1) return;int mid = n / 2;int *left = (int*)malloc(mid * sizeof(int));int *right = (int*)malloc((n - mid) * sizeof(int));// 分割数组for (int i = 0; i < mid; i++) left[i] = arr[i];for (int i = mid; i < n; i++) right[i - mid] = arr[i];// 递归排序merge_sort(left, mid);merge_sort(right, n - mid);// 合并结果merge(arr, left, right, mid, n - mid);// 释放临时内存free(left);free(right);
}
实测耗时:0.35秒
小结:稳定可靠的外排序首选
6. 快速排序
原理:通过基准值分区实现分治排序
时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
#include <stdio.h>
#include <stdlib.h>
int partition(int arr[], int low, int high) {int pivot = arr[high];int i = low - 1;for (int j = low; j <= high-1; j++)if (arr[j] < pivot)swap(&arr[++i], &arr[j]);swap(&arr[i+1], &arr[high]);return i+1;
}
void quickSort(int arr[], int low, int high) {if (low < high) {int pi = partition(arr, low, high);quickSort(arr, low, pi-1);quickSort(arr, pi+1, high);}
}
实测耗时:0.12秒
小结:综合性能最优的通用排序算法
7. 堆排序
原理:利用堆数据结构进行选择排序
时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
#include <stdio.h>
#include <stdlib.h>
void heapify(int arr[], int n, int i) {int largest = i, l = 2*i+1, r = 2*i+2;if (l < n && arr[l] > arr[largest]) largest = l;if (r < n && arr[r] > arr[largest]) largest = r;if (largest != i) {swap(&arr[i], &arr[largest]);heapify(arr, n, largest);}
}
void heapSort(int arr[], int n) {for (int i = n/2-1; i >= 0; i--)heapify(arr, n, i);for (int i = n-1; i > 0; i--) {swap(&arr[0], &arr[i]);heapify(arr, i, 0);}
}
实测耗时:0.28秒
小结:适合需要稳定 O ( n log n ) O(n\log n) O(nlogn)的场景
8. 基数排序
原理:按位数进行桶排序
时间复杂度: O ( k n ) O(kn) O(kn)
实现要点:
- 使用
exp参数表示当前处理的位数(1, 10, 100…) - 计数排序的稳定性通过反向填充实现
- 需手动计算最大值的位数控制循环次数
#include <stdio.h>
#include <stdlib.h>// 按指定位数进行计数排序
void counting_sort(int arr[], int n, int exp) {int output[n];int count[10] = {0}; // 十进制基数// 统计当前位出现次数for (int i = 0; i < n; i++) {int digit = (arr[i] / exp) % 10;count[digit]++;}// 计算累积频次for (int i = 1; i < 10; i++) {count[i] += count[i - 1];}// 反向填充保证稳定性for (int i = n - 1; i >= 0; i--) {int digit = (arr[i] / exp) % 10;output[count[digit] - 1] = arr[i];count[digit]--;}// 复制回原数组for (int i = 0; i < n; i++) {arr[i] = output[i];}
}// 基数排序主函数
void radix_sort(int arr[], int n) {int max_num = arr[0];for (int i = 1; i < n; i++) {if (arr[i] > max_num) max_num = arr[i];}// 按每一位进行排序for (int exp = 1; max_num / exp > 0; exp *= 10) {counting_sort(arr, n, exp);}
}
实测耗时:0.18秒
小结:整数排序利器,但需要额外内存
二、测试公共代码
- 代码实现:
测试采用100000个随机数进行。所有排序算法函数名不同,可以采用函数指针数组方式,通过循环实现。
// 公共代码段
#define N 100000
int* generateArray() {int* arr = (int*)malloc(N * sizeof(int));srand(time(NULL));for(int i=0; i<N; i++) arr[i] = rand() % 1000000;return arr;
}void timeTest(void (*sort)(int*, int), int* arr) {clock_t start = clock();sort(arr, N); //用对应算法实现代函数替代,所有排序算法函数名不同,可以采用函数指针数组方式,通过循环实现printf("Time: %.2fms\n", (double)(clock()-start)*1000/CLOCKS_PER_SEC);
}
- 关键注意事项:
- 每次测试前必须复制原始数组,避免数据已排序影响测试结果
- 基数排序默认处理非负整数,如需支持负数需修改位处理逻辑
- 快速排序使用三数取中法优化,避免最坏情况出现
- 归并排序采用迭代实现,避免递归导致的栈溢出问题
二、综合对比分析
| 算法 | 时间复杂度 | 空间复杂度 | 稳定性 | 适用场景 | 10万数据耗时 |
|---|---|---|---|---|---|
| 冒泡排序 | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 稳定 | 教学演示 | 32.7s |
| 选择排序 | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 不稳定 | 简单实现 | 14.2s |
| 插入排序 | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 稳定 | 小规模/基本有序数据 | 8.9s |
| 希尔排序 | O ( n 1.3 ) O(n^{1.3}) O(n1.3) | O ( 1 ) O(1) O(1) | 不稳定 | 中等规模数据 | 1.7s |
| 归并排序 | O ( n log n ) O(n\log n) O(nlogn) | O ( n ) O(n) O(n) | 稳定 | 外排序/链表排序 | 0.35s |
| 快速排序 | O ( n log n ) O(n\log n) O(nlogn) | O ( log n ) O(\log n) O(logn) | 不稳定 | 通用排序 | 0.12s |
| 堆排序 | O ( n log n ) O(n\log n) O(nlogn) | O ( 1 ) O(1) O(1) | 不稳定 | 实时系统/内存受限 | 0.28s |
| 基数排序 | O ( k n ) O(kn) O(kn) | O ( n + k ) O(n+k) O(n+k) | 稳定 | 整数排序/固定范围数据 | 0.18s |
工程建议:
- 通用场景优先选择快速排序
- 内存敏感时选用堆排序
- 稳定排序需求使用归并排序
- 整数排序可尝试基数排序
- 小规模数据(n<1000)使用插入排序
实际应用时需结合数据特征进行算法选择,必要时可采用混合排序策略。
三、性能优化建议
- 混合排序策略:当快速排序子数组长度小于15时切换为插入排序
- 内存预分配:归并排序的临时数组可提前分配避免重复申请
- 基数排序优化:使用位运算替代除法操作提升计算效率
- 并行化改造:归并排序和快速排序适合多线程优化
相关文章:
常见排序算法深度评测:从原理到10万级数据实战
常见排序算法深度评测:从原理到10万级数据实战 摘要 本文系统解析冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序和基数排序8种经典算法,通过C语言实现10万随机数排序并统计耗时。测试显示:快速排序综合性能最优&…...
Scaled_dot_product_attention(SDPA)使用详解
在学习huggingFace的Transformer库时,我们不可避免会遇到scaled_dot_product_attention(SDPA)这个函数,它被用来加速大模型的Attention计算,本文就详细介绍一下它的使用方法,核心内容主要参考了torch.nn.functional中该函数的注释…...
Linux练级宝典->Linux进程概念介绍
目录 进程基本概念 PCB概念 task_struct tack_struct内容分类 PID和PPID fork函数创建子进程 进程优先级概念 4个名词 进程地址空间 进程地址空间的意义 内核进程调度队列 优先级 活动队列 过期队列 进程基本概念 一个正在执行的程序。担当分配系统资源的实体&#…...
OpenHarmony 5.0 mpegts封装的H265视频播放失败的解决方案
问题现象 OpenHarmony 5.0版本使用AVPlayer播放mpegts封装格式的H.265(HEVC)编码格式的视频时出现报错导致播放失败 问题原因 OpenHarmony 5.0版本AVPlayer播放器使用histreamer引擎,因为 libav_codec_hevc_parser.z.so 动态库未开源导致H265编码格式视频解析不到…...
Qt从入门到入土(九) -model/view(模型/视图)框架
简介 Qt的模型/视图(Model/View)架构是一种用于分离数据处理和用户界面展示的设计模式。它允许开发者将数据存储和管理(模型)与数据的显示和交互(视图)解耦,从而提高代码的可维护性和可扩展性。…...
缓存之美:Guava Cache 相比于 Caffeine 差在哪里?
大家好,我是 方圆。本文将结合 Guava Cache 的源码来分析它的实现原理,并阐述它相比于 Caffeine Cache 在性能上的劣势。为了让大家对 Guava Cache 理解起来更容易,我们还是在开篇介绍它的原理: Guava Cache 通过分段(…...
[漏洞篇]XSS漏洞详解
[漏洞篇]XSS漏洞 一、 介绍 概念 XSS:通过JS达到攻击效果 XSS全称跨站脚本(Cross Site Scripting),为避免与层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故缩写为XSS。这是一种将任意 Javascript 代码插入到其他Web用户页面里执行以…...
【Leetcode 每日一题】2269. 找到一个数字的 K 美丽值
问题背景 一个整数 n u m num num 的 k k k 美丽值定义为 n u m num num 中符合以下条件的 子字符串 数目: 子字符串长度为 k k k。子字符串能整除 n u m num num。 给你整数 n u m num num 和 k k k,请你返回 n u m num num 的 k k k 美丽值…...
IO进程线程(线程)
作业 1.创建两个线程,分支线程1拷贝文件的前一部分,分支线程2拷贝文件的后一部分 2.创建三个线程,实现线程A打印A,线程B打印B,线程C打印C;重复打印顺序ABC。 信号量实现: 条件变量实现&#x…...
1-002:MySQL InnoDB引擎中的聚簇索引和非聚簇索引有什么区别?
在 MySQL InnoDB 存储引擎 中,索引主要分为 聚簇索引(Clustered Index) 和 非聚簇索引(Secondary Index)。它们的主要区别如下: 1. 聚簇索引(Clustered Index) 定义 聚簇索引是表数…...
tomcat单机多实例部署
一、部署方法 多实例可以运行多个不同的应用,也可以运行相同的应用,类似于虚拟主机,但是他可以做负载均衡。 方式一: 把tomcat的主目录挨个复制,然后把每台主机的端口给改掉就行了。 优点是最简单最直接,…...
论文阅读分享——UMDF(AAAI-24)
概述 题目:A Unified Self-Distillation Framework for Multimodal Sentiment Analysis with Uncertain Missing Modalities 发表:The Thirty-Eighth AAAI Conference on Artificial Intelligence (AAAI-24) 年份:2024 Github:暂…...
解决asp.net mvc发布到iis下安全问题
解决asp.net mvc发布到iis下安全问题 环境信息1.The web/application server is leaking version information via the "Server" HTTP response2.确保您的Web服务器、应用程序服务器、负载均衡器等已配置为强制执行Strict-Transport-Security。3.在HTML提交表单中找不…...
概念|RabbitMQ 消息生命周期 待消费的消息和待应答的消息有什么区别
目录 消息生命周期 一、消息创建与发布阶段 二、消息路由与存储阶段 三、消息存活与过期阶段 四、消息投递与消费阶段 五、消息生命周期终止 关键配置建议 待消费的消息和待应答的消息 一、待消费的消息(Unconsumed Messages) 二、待应答的消息…...
springboot三层架构详细讲解
目录 springBoot三层架构 0.简介1.各层架构 1.1 Controller层1.2 Service层1.3 ServiceImpl1.4 Mapper1.5 Entity1.6 Mapper.xml 2.各层之间的联系 2.1 Controller 与 Service2.2 Service 与 ServiceImpl2.3 Service 与 Mapper2.4 Mapper 与 Mapper.xml2.5 Service 与 Entity2…...
2025最新群智能优化算法:云漂移优化(Cloud Drift Optimization,CDO)算法求解23个经典函数测试集,MATLAB
一、云漂移优化算法 云漂移优化(Cloud Drift Optimization,CDO)算法是2025年提出的一种受自然现象启发的元启发式算法,它模拟云在大气中漂移的动态行为来解决复杂的优化问题。云在大气中受到各种大气力的影响,其粒子的…...
2025年Draw.io最新版本下载安装教程,附详细图文
2025年Draw.io最新版本下载安装教程,附详细图文 大家好,今天给大家介绍一款非常实用的流程图绘制软件——Draw.io。不管你是平时需要设计流程图、绘制思维导图,还是制作架构图,甚至是简单的草图,它都能帮你轻松搞定。…...
记录--洛谷 P1451 求细胞数量
如果想查看完整题目,请前往洛谷 P1451 求细胞数量 P1451 求细胞数量 题目描述 一矩形阵列由数字 0 0 0 到 9 9 9 组成,数字 1 1 1 到 9 9 9 代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形…...
Android Studio 配置国内镜像源
Android Studio版本号:2022.1.1 Patch 2 1、配置gradle国内镜像,用腾讯云 镜像源地址:https\://mirrors.cloud.tencent.com/gradle 2、配置Android SDK国内镜像 地址:Index of /AndroidSDK/...
做到哪一步才算精通SQL
做到哪一步才算精通SQL-Structured Query Language 数据定义语言 DDL for StructCREATE:用来创建数据库、表、索引等对象ALTER:用来修改已存在的数据库对象DROP:用来删除整个数据库或者数据库中的表TRUNCATE:用来删除表中所有的行…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
欢乐熊大话蓝牙知识17:多连接 BLE 怎么设计服务不会乱?分层思维来救场!
多连接 BLE 怎么设计服务不会乱?分层思维来救场! 作者按: 你是不是也遇到过 BLE 多连接时,调试现场像网吧“掉线风暴”? 温度传感器连上了,心率带丢了;一边 OTA 更新,一边通知卡壳。…...
STL 2迭代器
文章目录 1.迭代器2.输入迭代器3.输出迭代器1.插入迭代器 4.前向迭代器5.双向迭代器6.随机访问迭代器7.不同容器返回的迭代器类型1.输入 / 输出迭代器2.前向迭代器3.双向迭代器4.随机访问迭代器5.特殊迭代器适配器6.为什么 unordered_set 只提供前向迭代器? 1.迭代器…...
GB/T 43887-2024 核级柔性石墨板材检测
核级柔性石墨板材是指以可膨胀石墨为原料、未经改性和增强、用于核工业的核级柔性石墨板材。 GB/T 43887-2024核级柔性石墨板材检测检测指标: 测试项目 测试标准 外观 GB/T 43887 尺寸偏差 GB/T 43887 化学成分 GB/T 43887 密度偏差 GB/T 43887 拉伸强度…...
