常见排序算法深度评测:从原理到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:用来删除表中所有的行…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
