数据结构——选择排序
1. 引言上篇博客我们聊了插入排序那种像打扑克牌一样把新牌一张张插到合适位置的感觉相信大家还记忆犹新。今天我们换个思路来聊聊另一种同样经典的基础排序算法——选择排序。如果说插入排序是边摸牌边整理那选择排序更像是挑最顺眼的先拿走。它的思路非常直观每一轮都从剩下的元素里挑出最小的那个放到前面去。就像我们在宿舍里整理书架每次都从乱堆里挑出最薄的一本书放到最左边一本一本排好。2. 选择排序的基本思想选择排序的核心思想可以用一句话概括每一轮从未排序区间中选出最小值放到已排序区间的末尾。具体来说假设我们有一个长度为 n 的数组排序过程分为 n-1 轮第 1 轮在全部 n 个元素中找出最小值与第 1 个位置交换第 2 轮在剩下的 n-1 个元素中找出最小值与第 2 个位置交换第 3 轮在剩下的 n-2 个元素中找出最小值与第 3 个位置交换……第 n-1 轮在剩下的 2 个元素中找出最小值与第 n-1 个位置交换。经过 n-1 轮之后最后一个元素自然就是最大值排序完成。2.1 一个直观的比喻想象你在整理一摞试卷要从乱序的卷子里按分数从低到高排好先扫一遍所有试卷找出分数最低的那张放到最上面再从剩下的试卷里找出分数最低的放到第二张的位置重复这个过程直到所有试卷排好。这个过程就是选择排序的生动写照——每次只做一件事找到当前最小的放到它该去的位置。2.2 动图3. 图解选择排序过程为了让大家看得更清楚我们用一个具体例子来走一遍完整流程。假设数组为[5, 3, 8, 1, 2]长度为 5需要 4 轮排序。第 1 轮在[5, 3, 8, 1, 2]中找最小值1与第 1 个元素5交换[1, 3, 8, 5, 2]第 2 轮在[3, 8, 5, 2]中找最小值2与第 2 个元素3交换[1, 2, 8, 5, 3]第 3 轮在[8, 5, 3]中找最小值3与第 3 个元素8交换[1, 2, 3, 5, 8]第 4 轮在[5, 8]中找最小值5与第 4 个元素5交换位置不变[1, 2, 3, 5, 8]排序完成可以看到每一轮结束后前面就多了一个已经排好序的元素。下面是整个过程的流程图否是是否输入待排序数组i 0在 i 到 n-1 区间找最小值下标 minIndexminIndex 是否等于 i?交换 arr[i] 与 arr[minIndex]无需交换i i 1i n-1?输出排序后数组4. 代码实现voidSwap(int*x,int*y)//交换两数据位置{inttemp*x;*x*y;*ytemp;}voidSelectSort(int*arr,intn)//简单选择排序{if(arrNULL||n1)return;//1.核心思想是在未排序数据中选出最大/小的值并与待交换数据交换位置与插入排序的差别之一就是插入排序比较过程中需要将元素后移直到遇到合适位置插入// 选择排序是先比较完然后将单趟最值与某值交换位置因此同样需要区分已排序和未排序区域for(inti0;in-1;i)//同样的防止越界{intmini;//2.定义当前最小值的位置for(intji1;jn;j)//3.寻找未排序数据中的最小值{if(arr[j]arr[min]){minj;//4.如果有就定义新的最小值的位置}}//5.比完以后得到本次最小值的位置与原本的最小值交换位置if(min!i){Swap(arr[min],arr[i]);}}}4.3 代码要点总结外层循环i表示已排序区间的末尾位置从 0 到 n-2内层循环j负责在未排序区间中扫描记录最小值下标min每一轮最多交换一次这是选择排序与冒泡排序的重要区别冒泡可能一轮交换多次。5. 复杂度分析5.1 时间复杂度最好情况O(n²)。即使数组已经有序内层循环依然要完整扫描未排序区间无法提前终止。最坏情况O(n²)。无论数据怎么分布比较次数都是固定的。平均情况O(n²)。具体来说比较次数恒为n(n-1)/2与数据初始顺序无关交换次数最多为n-1次每轮最多一次。5.2 空间复杂度空间复杂度O(1)只需要一个临时变量用于交换属于原地排序算法。5.3 稳定性分析选择排序是不稳定的。举个例子数组[5a, 5b, 1]两个 5 用 a、b 区分第一轮找到最小值1与第一个5a交换得到[1, 5b, 5a]此时两个 5 的相对顺序发生了改变。这一点在面试中经常被问到大家要特别注意。有同学会问如果把内层循环的比较条件从改成能否让选择排序变稳定答案是不能。选择排序的不稳定性根源在于交换操作而不是比较条件。即使你用让内层循环在遇到相等元素时也更新min下标也只是改变了选哪个相等元素的策略但交换本身依然可能破坏相对顺序。以数组[5, 6, 5, 0, 2, 0, 3]为例给相同元素编号[5a, 6, 5b, 0a, 2, 0b, 3]第 1 轮找最小值0a与第 1 个元素5a交换得到[0a, 6, 5b, 5a, 2, 0b, 3]。此时5a被换到了5b的后面两个 5 的相对顺序已被破坏而这一轮0a和0b的相对顺序反而保住了。第 2 轮在[6, 5b, 5a, 2, 0b, 3]中找最小值0b与第 2 个元素6交换得到[0a, 0b, 5b, 5a, 2, 6, 3]。这一轮0b又被换到了0a的后面两个 0 的相对顺序也被破坏了。可以看到即使能保证某一组相同元素的相对顺序也无法同时保证所有组的相对顺序。因为每一轮交换都会把当前最小值从后面直接跨越到前面跨越过程中会越过所有其他元素——包括与它值相同的元素。用时相等元素不会被选中相对顺序靠运气用时相等元素会被选中选最后一个虽然可能保住某一组的顺序但其他组的顺序照样会被交换破坏。所以只要选择排序采用交换来实现它就注定不稳定。要让选择排序变稳定必须改用插入的方式把最小值前面的元素整体后移再把最小值放进去而不是交换——但那样它就不再是经典的选择排序了。用循环不变量再证一遍上面的例子已经足够直观但如果你想让论证更严谨可以用循环不变量来证明无论比较条件用还是选择排序都不可能是稳定的。先回顾一下选择排序外层循环的不变量循环不变量在第i轮开始前即i次交换完成后数组的前i个位置已经排好序且它们恰好是原数组中最小的i个元素剩余n-i个元素仍在未排序区间[i, n-1]中。这个不变量在初始化i0时前 0 个元素自然有序、保持每轮把未排序区间的最小值放到i位置、终止in-1时前n-1个元素有序最后一个自然最大三个阶段都成立所以它保证了排序的正确性。但注意这个不变量只约束了哪些值被放到了前面完全没有约束相同值的相对顺序。它只保证前i个位置是最小的 i 个元素至于这些相等元素谁先谁后不变量一概不管。现在我们来证明不稳定。考虑任意一轮i设未排序区间[i, n-1]中存在两个相等的元素x和y且x在y的前面x的下标更小。这一轮要选出的最小值记为m分两种情况情况一m就是x或y本身。假设选中的是y即y是未排序区间的最小值且x与它相等。交换后y被放到位置i而x留在原地。由于x原本在y前面交换后y跑到了x的前面两者相对顺序被破坏。情况二m是另一个更小的元素。此时m会被交换到位置i而x、y的相对位置在这一轮保持不变。但注意这一轮没有破坏它们不代表后面不会破坏。在后续某一轮i当x或y成为未排序区间的最小值被选中并交换到前面时就会发生情况一破坏它们的相对顺序。换句话说只要存在两个相等的元素且它们不是同一轮被同时选中选择排序每轮只选一个最小值永远不可能同时选中两个那么迟早有一轮会把其中一个跨越到另一个的前面。这正是选择排序交换实现的本质缺陷。所以结论是循环不变量只能证明选择排序排对了却无法证明它排得稳。稳定性需要的是相等元素相对顺序不变这一条额外约束而选择排序的交换操作天然无法保证这一点。这也解释了为什么面试中稳定性和正确性是两个独立的问题——一个算法可以正确但不稳定。6. 选择排序 vs 插入排序上篇我们学了插入排序这里把两者放在一起对比方便大家记忆对比维度选择排序插入排序基本思路每轮选最小值放前面每轮把新元素插入到合适位置最好时间复杂度O(n²)O(n)已有序时最坏时间复杂度O(n²)O(n²)交换次数最多 n-1 次最多 n(n-1)/2 次稳定性不稳定稳定适用场景交换成本高、数据量小数据基本有序、数据量小小贴士如果交换两个元素的代价很大比如元素是复杂对象选择排序的交换次数少反而可能比插入排序更合适但如果数据基本有序插入排序凭借提前终止的优势会快很多。7. 常见面试考点选择排序虽然简单但面试官经常从它入手考察基础功底手写代码要求在白板上写出完整实现注意边界条件i n-1和j n。稳定性判断能举出反例说明它不稳定。复杂度推导能说出比较次数恒为n(n-1)/2。优化思路能否想到同时找最大值和最小值的优化版本每轮找最大和最小可减少一半轮次。与其它排序对比能清晰说出选择、插入、冒泡三者的区别。8. 总结选择排序是算法入门路上绕不开的一块基石。它的思想朴素而优雅——每次只做一件最简单的事重复 n-1 次就能完成整个排序。回顾一下今天的关键点核心思想每轮从未排序区间选最小值放到已排序区间末尾时间复杂度无论好坏都是 O(n²)空间复杂度O(1)原地排序稳定性不稳定与插入排序相比交换次数更少但无法利用数据的有序性。下篇博客我打算写冒泡排序把这三个 O(n²) 的基础排序放在一起做个对比

相关新闻

MFC多线程进度条不卡死:PostMessage消息驱动UI更新实践

MFC多线程进度条不卡死:PostMessage消息驱动UI更新实践

简介:面向Windows桌面开发者的MFC多线程编程示例,演示如何通过继承CWinThread并重写Run方法创建后台工作线程,利用PostMessage发送自定义进度消息,由主线程接收后调用SetPos实时更新对话框进度条,有效避免后台任务阻塞…

2026/10/18 22:46:51 阅读更多 →
codex怎么预定义提示词?例如中文回复:用 AGENTS.md 固化默认行为

codex怎么预定义提示词?例如中文回复:用 AGENTS.md 固化默认行为

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 22:46:51 阅读更多 →
AI Agent Harness 多终端同步管控:把 Codex auth.json 改到 TaoToken 的实操大纲

AI Agent Harness 多终端同步管控:把 Codex auth.json 改到 TaoToken 的实操大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 22:45:50 阅读更多 →

最新新闻

三则AI新闻揭示应用临界点:轻量模型、免费旗舰与团队回迁

三则AI新闻揭示应用临界点:轻量模型、免费旗舰与团队回迁

10月8日早上,我的朋友圈和几个技术群几乎同时被三则AI新闻刷屏:一家主流模型厂商发布了新的轻量快速模型H 5.5,另一家巨头把第六代旗舰模型向普通用户免费开放,还有一个此前把部分团队搬到外地的智能体产品团队,宣布要…

2026/10/18 23:39:35 阅读更多 →
语言模型中的语法伪相关:模型为何学错教训?

语言模型中的语法伪相关:模型为何学错教训?

看到标题里的“Syntactic-Domain Spurious Correlations”,我第一反应是想起自己踩过的一个坑:训练文本蕴含模型时,验证集上“矛盾”标签的准确率一路飙升到95%以上,当时我还以为模型真的学会了推理。结果我把一个用规则改写出来的…

2026/10/18 23:39:35 阅读更多 →
恒星级AI时代:AI短剧生产管线与数字分身序章

恒星级AI时代:AI短剧生产管线与数字分身序章

1. 从“恒星级AI”说起:这个标题到底在讲什么“恒星级AI时代降临”这个说法,第一次看到的时候我愣了一下。恒星级的能量量级是什么概念?太阳每秒释放的能量大约是3.8乘以10的26次方瓦,人类目前全球总发电功率大概在3乘10的12次方瓦…

2026/10/18 23:39:35 阅读更多 →
OpenSpec:规范优先开发的工程实践与CI/npm落地指南

OpenSpec:规范优先开发的工程实践与CI/npm落地指南

1. OpenSpec 是什么:一个被低估的规范优先开发实践工具链OpenSpec 不是一个 npm 包名,也不是某个具体开源项目的代号——它是一套正在快速成型的、以机器可读规范(Spec)为唯一事实源(Single Source of Truth&#xff0…

2026/10/18 23:38:35 阅读更多 →
空间复用与数据对齐实战:内存池、缓存行与SIMD优化指南

空间复用与数据对齐实战:内存池、缓存行与SIMD优化指南

空间复用和数据对齐这两件事,很多人是在踩了坑之后才回头补课的。我刚开始接触算法实现时,习惯把所有临时数据都放在堆上现申请现释放,结构体字段怎么顺手怎么排,跑起来也没觉得有什么问题——直到有一次把数据规模抬到千万级&…

2026/10/18 23:38:35 阅读更多 →
Sakurairo WordPress 主题指南:从零到一搭出你的多彩博客

Sakurairo WordPress 主题指南:从零到一搭出你的多彩博客

Sakurairo WordPress 主题指南:从零到一搭出你的多彩博客 【免费下载链接】Sakurairo A WordPress theme that is built with AI-assisted reading features, colorful, user-friendly, well-rounded, and rich in functionalities. Support Chinese, English, Japa…

2026/10/18 23:38:35 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →