常见排序算法深度评测:从原理到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:用来删除表中所有的行…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
