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

三大基本排序算法:冒泡排序、直接插入排序、直接选择排序

三大基本排序算法:冒泡排序、直接插入排序、直接选择排序

冒泡排序、直接插入排序和直接选择排序是排序算法中最基础的三种,虽然时间复杂度都是 O(n²),但它们各自的思想、实现细节和适用场景有着本质区别。本文从算法思想、代码实现、复杂度分析到稳定性逐一拆解,适合初学者建立对排序算法的系统认知。


冒泡排序

算法思想

冒泡排序的核心是"相邻比较、逐轮冒泡":每一轮从数组头部开始,依次比较相邻的两个元素,如果顺序不对就交换它们。一轮下来,当前未排序部分的最大值就会被"推"到它应该在的位置——就像气泡从水中浮出一样。

具体步骤

  1. 从第一个元素开始,依次比较相邻的两个元素arr[j]arr[j+1]
  2. 如果arr[j] > arr[j+1](升序),则交换它们。
  3. 每一轮遍历后,未排序部分的最大元素被放到了正确位置(当前轮的末尾)。
  4. 下一轮缩小范围,继续对剩余元素重复上述过程。
  5. 如果某一轮没有发生任何交换,说明数组已经有序,可以提前结束。

以一个数组[5, 3, 8, 1, 2]为例,第一轮冒泡过程:

初始:[5, 3, 8, 1, 2] 5>3 交换 → [3, 5, 8, 1, 2] 5<8 不换 → [3, 5, 8, 1, 2] 8>1 交换 → [3, 5, 1, 8, 2] 8>2 交换 → [3, 5, 1, 2, 8] ← 8 归位

代码实现

voidswap(int*a,int*b){inttmp=*a;*a=*b;*b=tmp;}voidBubbleSort(int*arr,intn){for(inti=0;i<n;i++){intflag=0;// 每轮重置,标记是否发生交换for(intj=0;j<n-i-1;j++){if(arr[j]>arr[j+1]){swap(&arr[j],&arr[j+1]);flag=1;}}if(flag==0)// 本轮没有交换,已经有序{break;}}}

优化点flag变量用于检测某一轮是否发生了交换。如果没有发生交换,说明数组已经有序,可以提前结束循环。这使得最好情况下(数组已经有序)时间复杂度降为 O(n)。

复杂度与稳定性

指标说明
最好时间复杂度O(n) — 数组已经有序,一轮扫描后 flag=0 直接退出
最坏时间复杂度O(n²) — 数组逆序,每轮都要交换
平均时间复杂度O(n²)
空间复杂度O(1) — 原地排序,仅用常量级额外空间
稳定性稳定— 只有arr[j] > arr[j+1]时才交换,相等元素不会互换位置

直接插入排序

算法思想

直接插入排序模拟的是"打扑克牌时整理手牌"的过程:手里已经有一部分排好序的牌(有序序列),每拿到一张新牌(待插入元素),就从后往前扫描已排序部分,找到合适的位置插入。

具体步骤

  1. 将第一个元素视为已排序序列。
  2. 取出下一个元素作为待插入元素tmp
  3. 在已排序序列中从后向前扫描,如果已排序元素大于tmp,则将该元素后移一位。
  4. 找到第一个不大于tmp的位置,将tmp插入其后。
  5. 重复步骤 2-4,直到所有元素处理完毕。

以数组[5, 3, 8, 1, 2]为例:

i=0: [5 | 3, 8, 1, 2] 5视为已排序 i=1: [3, 5 | 8, 1, 2] 3插入到5前面 i=2: [3, 5, 8 | 1, 2] 8不变,已在正确位置 i=3: [1, 3, 5, 8 | 2] 1一直移动到最前面 i=4: [1, 2, 3, 5, 8] 2插入到3前面

代码实现

voidInsertSort(int*arr,intn){for(inti=0;i<n-1;i++){intend=i;// 已排序部分的最后一个位置inttmp=arr[end+1];// 待插入的元素while(end>=0){if(arr[end]>tmp){arr[end+1]=arr[end];// 比tmp大的元素后移end--;}else{break;// 找到插入位置}}arr[end+1]=tmp;// 插入到正确位置}}

关键细节

  • 外层循环条件是i < n - 1,因为当i = n-2时取arr[n-1]作为最后一个待插入元素。
  • while循环的终止条件是end >= 0,当end减到-1时说明tmp比所有已排序元素都小,插入到数组最前面。

复杂度与稳定性

指标说明
最好时间复杂度O(n) — 数组已经有序,内层 while 每次只比较一次就 break
最坏时间复杂度O(n²) — 数组逆序,每个元素都要移到最前面
平均时间复杂度O(n²)
空间复杂度O(1) — 原地排序
稳定性稳定— 只有arr[end] > tmp时才后移,相等元素不跨越

直接选择排序

算法思想

直接选择排序的核心是"每轮选出最值,放到两端":每一轮在未排序区间中找到最小值和最大值,将最小值放到区间开头,最大值放到区间末尾,然后缩小区间继续。

本文展示的是双向优化版本,每轮同时选出最小值和最大值,比传统单向选择排序少一半的遍历轮数。

具体步骤

  1. 设定左右边界begin = 0end = n - 1
  2. [begin, end]范围内遍历,记录最小值下标mini和最大值下标maxi
  3. arr[mini]arr[begin]交换,将arr[maxi]arr[end]交换。
  4. begin++end--,缩小区间。
  5. 重复步骤 2-4,直到begin >= end

以数组[5, 3, 8, 1, 2]为例:

[5, 3, 8, 1, 2] begin=0, end=4, mini=3(值1), maxi=2(值8) 交换mini↔begin, maxi↔end → [1, 3, 2, 5, 8] [1, 3, 2, 5, 8] begin=1, end=3, mini=2(值2), maxi=3(值5) 交换mini↔begin, maxi↔end → [1, 2, 3, 5, 8] begin=2, end=2 → 结束

代码实现

voidSelectSort(int*arr,intn){intbegin=0,end=n-1;while(begin<end){intmaxi=begin;intmini=begin;// 在 [begin, end] 中同时找最大值和最小值的下标for(inti=begin+1;i<=end;i++){if(arr[i]>arr[maxi]){maxi=i;}if(arr[i]<arr[mini]){mini=i;}}// 关键:如果 begin 位置恰好是最大值,第一次交换会把它移走// 需要让 maxi 指向最大值被移到的位置(即原来的 mini 位置)if(begin==maxi){maxi=mini;}swap(&arr[mini],&arr[begin]);// 最小值放到区间头swap(&arr[maxi],&arr[end]);// 最大值放到区间尾begin++;end--;}}

swap 顺序的陷阱:这是选择排序中最容易出错的细节。我们先交换minibegin,但如果begin恰好是maxi(即最大值就在区间头),第一次交换后最大值已经被移到了原来mini的位置,此时maxi仍然指向begin就会出错。所以需要先判断begin == maxi,将maxi更新为mini,确保第二次交换时maxi指向真正的最大值。

复杂度与稳定性

指标说明
最好时间复杂度O(n²) — 即使数组有序,仍然需要完整遍历
最坏时间复杂度O(n²)
平均时间复杂度O(n²)
空间复杂度O(1) — 原地排序
稳定性不稳定— 交换非相邻元素会打乱相等元素的相对顺序

选择排序是三种算法中唯一不稳定的排序。例如数组[5, 8, 5, 2],第一个 5 会和 2 交换,导致两个 5 的相对顺序发生改变。


三种排序对比

冒泡排序直接插入排序直接选择排序
最好时间O(n)O(n)O(n²)
最坏时间O(n²)O(n²)O(n²)
平均时间O(n²)O(n²)O(n²)
空间O(1)O(1)O(1)
稳定性稳定稳定不稳定
比较次数多(相邻比较)少(提前终止)多(必须扫完)
移动/交换次数多(每次比较可能交换)多(元素逐个后移)少(每轮最多2次交换)
适用场景小规模数据,教学入门基本有序的数据,小规模对交换次数敏感的场景

总结

  • 冒泡排序:思路最直观,适合入门理解排序的基本操作(比较和交换)。通过flag优化可以在有序时达到 O(n)。
  • 直接插入排序:模拟理牌过程,对于基本有序的数据表现极好(接近 O(n)),是小规模数据和部分排序场景的首选。
  • 直接选择排序:交换次数最少,但无论如何都要 O(n²) 的比较次数,且不稳定。双向优化可以减少遍历轮数,但不改变时间复杂度级别。

三种算法虽然在实际项目中很少直接使用(规模稍大就会被快排、归并等 O(n log n) 算法替代),但它们是理解更复杂排序算法的基石,也是面试中的高频考点。

http://www.gsyq.cn/news/1467086.html

相关文章:

  • 如何快速掌握SPT-AKI存档编辑:塔科夫离线版游戏进度管理终极指南
  • 百联OK卡回收最新指南 靠谱高价格平台解析 - 购物卡回收找京尔回收
  • 房产估值偏差诊断:数据科学四步法实战指南
  • DRAM技术演进:从工艺微缩到架构革新,应对物理极限与市场需求
  • 2026 西北旅游优质文旅企业甄选推荐|西北旅游哪家好靠谱旅行社盘点 - 深度智识库
  • 从MobileNetV3的h-swish激活函数说起:PyTorch实战中如何为你的轻量级模型提速
  • AI教材写作秘籍:利用低查重AI工具,轻松打造优质教材!
  • 2026年西安高顶商务车定制销售公司横向评测:奔驰威霆V300L高顶 丰田海狮改装 GL8 全国TOP3对比 - 深度智识库
  • 2026年华南BOPP卷膜生产厂家盘点:规模化生产与高性价比之选 - 资讯速览
  • 闲置电视盒子变身专业服务器:Armbian系统完全指南
  • DDrawCompat终极指南:三步让经典Windows游戏在现代系统上重生
  • 掌握AI教材写作技巧,低查重率不是梦,高效生成专业教材
  • 如何快速下载网易云音乐无损FLAC:打造高品质个人音乐库的完整指南
  • requests爬虫老手才知道的坑:除了verify=False,处理HTTPS连接池Max retries exceeded还有这些招
  • Beyond Compare 5密钥生成终极指南:3分钟免费激活的专业文件对比工具
  • AI写专著高效之道:利用AI工具,一周完成20万字专著创作!
  • 免费获取Wallpaper Engine创意工坊壁纸的终极解决方案
  • HarmonyOS分布式游戏开发实战:Cocos Creator跨设备协同技术解析
  • OpenCore Legacy Patcher:让老旧Mac重获新生的终极技术方案
  • 2026长沙婚纱照实测盘点:8家探店真实测评,备婚挑选不踩坑 - 江湖评测
  • 告别喜马拉雅VIP音频无法下载的烦恼:XMly-Downloader-Qt5使用全攻略
  • 3分钟诊断:用VisualCppRedist AIO彻底解决Windows系统运行库缺失难题
  • 大模型MoE稀疏激活真相:参数规模与动态激活率解析
  • ssl协商2 - 小镇
  • 终极网盘直链下载助手:3分钟告别限速,实现高速下载自由
  • Archipack:Blender建筑建模的终极参数化解决方案
  • 别再只用GO/KEGG了!用R的clusterProfiler包做GSEA富集分析,从数据整理到出图保姆级教程
  • 2026年贵阳广告制作与门头招牌服务商深度选型指南|官方对接与避坑全解 - 优质企业观察收录
  • 基于STC89C52的AD590温度监测系统:带按键设定上下限、蜂鸣报警与LCD1602实时显示(含Proteus仿真+Keil工程)
  • 106短信平台哪家性价比高?合规短信服务商解析推荐对比 - Qqinqin