排序---选择排序(Selection Sort)

一、选择排序的基本概念

选择排序(Selection Sort)是一种简单直观的排序算法,其核心思想是每次从待排序元素中找到最值(最小值或最大值),将其放到已排序序列的末尾,重复此过程直到所有元素完成排序

与冒泡排序通过相邻元素交换逐步"浮"出最值不同,选择排序通过"选择"最值并一次性交换到目标位置,减少了交换操作的次数。这种特性使选择排序在某些场景下(如交换成本较高的情况)表现优于冒泡排序。

二、选择排序的工作原理

选择排序的工作过程可分为以下步骤,我们以升序排序(找最小值)为例说明:

  1. 划分区域:将数组分为"已排序区域"和"未排序区域"。初始状态下,已排序区域为空,未排序区域为整个数组。
  2. 查找最值:在未排序区域中找到最小元素,记录其索引。
  3. 交换元素:将找到的最小元素与未排序区域的第一个元素交换,此时该元素被纳入已排序区域。
  4. 重复迭代:缩小未排序区域的范围(左边界右移一位),重复步骤2和3,直到未排序区域为空。

示例演示
对数组 [64, 25, 12, 22, 11] 进行升序排序的过程:

  • 第1轮:未排序区域为 [64, 25, 12, 22, 11],最小值为11(索引4),与未排序区域第一个元素64交换 → 数组变为 [11, 25, 12, 22, 64](已排序区域:[11])。
  • 第2轮:未排序区域为 [25, 12, 22, 64],最小值为12(索引2),与25交换 → 数组变为 [11, 12, 25, 22, 64](已排序区域:[11, 12])。
  • 第3轮:未排序区域为 [25, 22, 64],最小值为22(索引3),与25交换 → 数组变为 [11, 12, 22, 25, 64](已排序区域:[11, 12, 22])。
  • 第4轮:未排序区域为 [25, 64],最小值为25(索引3),无需交换 → 数组保持 [11, 12, 22, 25, 64](已排序区域:[11, 12, 22, 25])。
  • 结束:未排序区域仅剩最后一个元素64,排序完成。
三、算法特性分析
  1. 时间复杂度
    选择排序的时间复杂度不受输入数据的影响,始终为 O(n²)

    • 外层循环需要执行 n-1 次(每次确定一个元素的位置)。
    • 内层循环在第 i 轮需要遍历 n-i 个元素(寻找未排序区域的最值)。
    • 总操作次数为 (n-1) + (n-2) + ... + 1 = n(n-1)/2,近似为 n²/2,因此时间复杂度为 O(n²)。
  2. 空间复杂度
    选择排序仅使用常数级别的额外空间(如存储最值索引和临时交换变量),因此空间复杂度为 O(1),是一种"原地排序"算法。

  3. 稳定性
    选择排序是不稳定的排序算法。例如,对数组 [2, 2, 1] 排序时,第一个2会与1交换,导致两个2的相对位置发生改变(原顺序为 [2₁, 2₂, 1],排序后为 [1, 2₂, 2₁])。

  4. 优缺点

    • 优点:实现简单,空间复杂度低,交换操作次数少(最多 n-1 次)。
    • 缺点:时间复杂度高,不适合处理大规模数据;稳定性差,不适用于要求保持相等元素相对顺序的场景。
四、C/C++代码实现

下面是选择排序的C++实现,包含完整的排序函数、测试用例和打印函数:

#include <iostream>
#include <vector>using namespace std;// 选择排序函数(升序)
void selectionSort(int arr[], int n) {// 外层循环:控制已排序区域的边界(0 ~ i-1为已排序)for (int i = 0; i < n - 1; i++) {int minIndex = i; // 记录未排序区域中最小值的索引,初始假设为i// 内层循环:在未排序区域(i ~ n-1)中寻找最小值for (int j = i + 1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j; // 更新最小值索引}}// 将找到的最小值与未排序区域的第一个元素(arr[i])交换if (minIndex != i) { // 若最小值就是当前元素,无需交换int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}
}// 打印数组元素
void printArray(int arr[], int n) {for (int i = 0; i < n; i++) {cout << arr[i] << " ";}cout << endl;
}int main() {// 测试用例1:整数数组int arr1[] = {64, 25, 12, 22, 11};int n1 = sizeof(arr1) / sizeof(arr1[0]);cout << "排序前的数组:";printArray(arr1, n1);selectionSort(arr1, n1);cout << "排序后的数组:";printArray(arr1, n1);// 测试用例2:包含重复元素的数组int arr2[] = {3, 1, 4, 1, 5, 9, 2, 6};int n2 = sizeof(arr2) / sizeof(arr2[0]);cout << "\n排序前的数组(含重复元素):";printArray(arr2, n2);selectionSort(arr2, n2);cout << "排序后的数组(含重复元素):";printArray(arr2, n2);return 0;
}
五、代码解析
  1. 排序函数 selectionSort

    • 外层循环变量 i 表示已排序区域的边界(0 ~ i-1 为已排序元素),循环范围为 0 ~ n-2(最后一个元素无需排序)。
    • 内层循环从 i+1 开始遍历未排序区域,通过 minIndex 记录最小值的位置。
    • 找到最小值后,若其位置与 i 不同,则交换 arr[i]arr[minIndex],将最小值放入已排序区域的末尾。
  2. 辅助函数 printArray
    用于打印数组元素,方便观察排序前后的变化。

  3. 测试用例

    • 第一个测试用例验证基本排序功能,第二个测试用例验证对含重复元素数组的排序效果(可观察到选择排序的不稳定性)。
六、优化方向

标准选择排序可通过以下方式优化:

  1. 双向选择排序
    每次迭代同时寻找未排序区域的最小值和最大值,分别放到已排序区域的两端,减少循环次数(迭代次数从 n-1 减少到 n/2)。

    void bidirectionalSelectionSort(int arr[], int n) {int left = 0, right = n - 1;while (left < right) {int minIndex = left, maxIndex = right;// 找最小值和最大值for (int i = left; i <= right; i++) {if (arr[i] < arr[minIndex]) minIndex = i;if (arr[i] > arr[maxIndex]) maxIndex = i;}// 交换最小值到左侧swap(arr[left], arr[minIndex]);// 若最大值在左侧(被交换过),更新maxIndexif (maxIndex == left) maxIndex = minIndex;// 交换最大值到右侧swap(arr[right], arr[maxIndex]);left++;right--;}
    }
    
  2. 优化交换操作
    对于大型元素(如结构体),交换操作成本较高,可先记录最值位置,最后一次性移动元素(减少复制次数)。

七、适用场景

选择排序适合以下场景:

  • 数据量较小(如 n < 100),对排序效率要求不高。
  • 内存空间有限,需要原地排序(空间复杂度O(1))。
  • 交换操作成本较高(选择排序的交换次数最少)。

对于大规模数据(n > 1000),建议使用快速排序、归并排序等O(n log n)级别的算法。


选择排序是一种基础的排序算法,其核心思想是"选择最值并交换",实现简单但效率较低。
在实际开发中,需根据数据规模、空间限制和稳定性要求,选择合适的排序算法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98886.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98886.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端菜单权限方案

方案一&#xff1a;前端全量配置路由表 后端返回权限码思路所有可能的路由都在前端 router 中静态配置好&#xff08;就像你现在这样&#xff09;。登录后&#xff0c;后端返回当前用户的菜单权限&#xff08;通常是一个权限 code 列表&#xff09;。前端根据权限码过滤掉无权…

spring项目部署后为什么会生成 logback-spring.xml文件

以下内容为豆包生成&#xff0c;此处仅做记录在 Spring 项目&#xff08;尤其是 Spring Boot 项目&#xff09;部署后生成 logback-spring.xml 文件&#xff0c;通常有以下几种原因&#xff1a;1. 项目打包时主动包含了该文件logback-spring.xml 是 Logback 日志框架在 Spring …

如何解决pip安装报错ModuleNotFoundError: No module named ‘vaex’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘vaex’问题 摘要 在Python开发过程中&#xff0c;使用pip install时遇到错误是非常常见的情况。特别是在使用PyCharm等集成开发环境&#xff08;IDE&#xff0…

实习总结——关于联调解决的因CRC校验导致协议交互失败的调试经验总结

1.场景还原&#xff1a;在我开发USB PD测试模块时&#xff0c;发现待测主板始终不回复Request消息&#xff0c;导致我的测试失败&#xff1b;此时我的任务就是快速定位这个协议交互失败的原因&#xff0c;无论是软件、硬件还是协同。2.大致的调试步骤&#xff1a;1.首先使用了逻…

STM32之RTC

RTC简介 实时时钟(Real Time Clock&#xff0c;RTC)&#xff0c;本质是一个计数器&#xff0c;计数频率常为秒&#xff0c;专门用来记录时间。 普通定时器拿来作时钟可行吗&#xff1f;普通定时器无法掉电运行&#xff01; RTC特性&#xff1a; 1&#xff0c;能提供时间&…

【OC】单例模式

文章目录前言概念优缺点优点缺点两种使用模式懒汉模式实现代码运行结果饿汉模式实现代码运行结果在自定义类方法时的几种常见写法总结前言 在之前我们已经学习过单例模式的有关内容&#xff0c;但是只是最简单的单例&#xff0c;无法胜任多线程或者稍微多一点的情况便无法确定…

机器学习(七)决策树-分类

一 概念1 决策节点通过条件判断而进行分支选择的节点。将样本的属性值&#xff0c;也就是特征值与决策节点上的值进行比较&#xff0c;从而判断它的流向。2 叶子节点没有子节点的节点&#xff0c;表示最终的决策结果。3 决策树的深度所有节点的最大层次数决策树具有一定的层次结…

IT 服务管理的新格局:从工单系统到一体化 ITSM 平台

企业 IT 部门的角色转变在过去&#xff0c;IT 部门更多被视为“技术支持”&#xff0c;主要负责设备维护和故障处理。但随着数字化转型加速&#xff0c;IT 已经成为业务连续性和创新的重要推动力。从客户体验到数据安全&#xff0c;从业务敏捷到成本控制&#xff0c;IT 服务管理…

创建一个Spring Boot Starter风格的Basic认证SDK

文章目录前言设计思路SDK实现步骤1. 创建SDK Maven项目&#xff08;sdk目录&#xff09;2. 实现配置类3. 实现认证逻辑4. 实现拦截器5. 实现自动配置6. 创建spring.factories文件使用方集成步骤1. 引入SDK依赖2. 配置Application属性3. 创建测试接口4. 测试接口访问SDK扩展功能…

mybatis处理统计sql进度丢失问题

如何处理统计sql进度丢失 SELECT sum(decimal_column) AS sum_value FROM your_table如上sql执行时没有问题&#xff0c;在数据库可视工具可以正常显示&#xff0c;但是在mybatis执行时&#xff0c;却出现解决办法 使用转 decimal 控制精度 SELECT CAST(SUM(decimal_column) A…

全球首款!科聪控制器获德国 TÜV 莱茵功能安全认证

近日&#xff0c;浙江科聪控制技术有限公司&#xff08;以下简称"科聪"&#xff09;的安全移动机器人控制器MSC5000荣获全球权威认证机构德国莱茵TV集团&#xff08;TV Rheinland&#xff09;颁发的功能安全认证证书。这款控制器是全球首款通过SIL3、PLe 认证的移动机…

pureadmin的动态路由和静态路由

在 PureAdmin&#xff08;基于 Vue3 的后台管理框架&#xff09;中&#xff0c;静态路由和动态路由是实现路由管理的两种方式&#xff0c;主要区别在于路由的定义时机、加载方式和灵活性&#xff0c;具体区别如下&#xff1a; 1. 静态路由 定义方式&#xff1a;路由规则在代码中…

第3章:CPU实战

1. Linux操作系统CPU平均负载 以前我们总认为CPU使用率和CPU平均负载是一样的&#xff0c;负载高了就是CPU使用率提高。但是到底是什么情况呢&#xff1f; 1.1. CPU的平均负载 单位时间内 系统处于 可运行状态 和不可中断状态 的平均进程数&#xff0c;就是平均活跃进程数&a…

【Vue3】06-利用setup编写vue(1)

其它篇章&#xff1a; 1.【Vue3】01-创建Vue3工程 2.【Vue3】02-Vue3工程目录分析 3.【Vue3】03-编写app组件——src 4.【Vue3】04-编写vue实现一个简单效果 5.【Vue3】05-Options API和Composition API的区别 6.【Vue3】06-利用setup编写vue&#xff08;1&#xff09; 7.【Vue…

UDS NRC速查

目录 NRC 一、通用NRC(0x10~0x5F) 二、数据相关NRC(0x70~0x8F) 三、会话与状态NRC 注意事项 UDS中的NRC(Negative Response Code)即否定响应码,用于在诊断通信中表示服务端无法成功执行客户端请求的原因。以下是一些常用的UDS NRC码及其含义: HEX Name Description 01 …

【AI论文】多模态大型语言模型的视觉表征对齐

摘要&#xff1a;通过视觉指令微调训练的多模态大型语言模型&#xff08;MLLMs&#xff09;在各类任务中均取得了优异表现&#xff0c;然而在以视觉为中心的任务&#xff08;如物体计数或空间推理&#xff09;中&#xff0c;其性能仍存在局限。我们将这一差距归因于当前主流的纯…

SKywalking Agent配置+Oracle监控插件安装指南

SKywalking Agent配置Oracle监控插件安装指南前言&#xff1a; SkyWalking Elasticsearch8 容器化部署指南 Skywalking版本&#xff1a;V10.2.0 Skywalking Agent版本&#xff1a;V9.4.0 Skywalking Agent下载地址&#xff1a;Downloads | Apache SkyWalking 插件下载地址&…

ES相关问题汇总

问题一&#xff1a;关于【QueryBuilder对象】和【Query String语法】查询时底层运行方式和结果的差异

5. STM32 时钟系统分配

文章目录下述将以stm32f407 为例1. 时钟系统及频率分析2. 时钟配置下述将以stm32f407 为例 1. 时钟系统及频率分析 上述STM32F4时钟系统图解析入下&#xff1a; STM32F407 系列微控制器&#xff08;基于 Cortex-M4 内核&#xff0c;带 FPU&#xff09;的工作频率配置如下&…

《从 0 建立测试开发认知:先搞懂 “是什么”,再学 “怎么做”》

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C知识分享》《Linux 入门到实践&#xff1a;零基础也能懂》《数据结构与算法》《测试开发实战指南》《算法题闯关指南》 ⭐️人生格言&a…