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

选择排序专栏

选择排序是最基础也最容易理解的排序算法之一,它的核心思想简单直接,非常适合排序算法的入门学习。本文将从原理、实现、特性到优化,全面解析选择排序算法。

一、选择排序的核心思想

选择排序的工作原理就像它的名字一样 ——"选择":在未排序的元素中找到最小(或最大)的那个元素,然后将它与未排序部分的第一个元素交换位置。重复这个过程,直到所有元素都被排序。

形象地说,就好像你在整理一手扑克牌:每次从剩余的牌中挑出最小的一张,按顺序放在左手边,直到所有牌都被挑完。

排序过程分解

以数组 [5, 2, 4, 6, 1, 3] 为例,升序排序过程如下:

  1. 初始状态:[5, 2, 4, 6, 1, 3](全部未排序)
  2. 第 1 轮:找到最小值 1,与第一个元素 5 交换 → [1, 2, 4, 6, 5, 3]
  3. 第 2 轮:从剩余元素中找到最小值 2,位置不变 → [1, 2, 4, 6, 5, 3]
  4. 第 3 轮:找到最小值 3,与 4 交换 → [1, 2, 3, 6, 5, 4]
  5. 第 4 轮:找到最小值 4,与 6 交换 → [1, 2, 3, 4, 5, 6]
  6. 第 5 轮:剩余元素已有序,排序完成

二、Java 实现选择排序

下面是选择排序的 Java 实现代码,包含详细注释:

public class Selection {public static void main(String[] args) {Integer[] a = {1,9,6,7,66,11,326,98};sort(a);System.out.println(Arrays.toString(a));}public static void sort(Comparable[] a){//定义i为首个数据for (int i = 0; i < a.length-1; i++) {//定义最小值为minint min = i;//for (int j = i+1; j < a.length; j++) {if(greater(a[min],a[j])){min = j;}}//得到最小的放到最前面exchange(a,i,min);}}//比较v是否大于n;public static boolean greater(Comparable v,Comparable n){//调用comparable的方法//v大于n是返回 1,//v等于n时返回 0,//v小时n时返回 -1int i = v.compareTo(n);return i==1;}//交换方法public static void exchange(Comparable[] a,int i,int j){Comparable temp = a[i];a[i] = a[j];a[j] = temp;}}

代码解析

上面的实现包含三个主要部分:

  1. sort 方法:核心排序逻辑

    • 外层循环控制需要排序的元素范围
    • 内层循环在未排序部分中寻找最小值
    • 找到最小值后与未排序部分的第一个元素交换
  2. main 方法:测试排序算法,包含测试用例

  3. exchange方法:传入对象,实现位置的交换

  4. greater方法:实现数据比较

三、选择排序的特性分析

    选择排序的时间复杂度主要由比较操作交换操作两部分构成,其中比较操作占主导地位。

    时间复杂度分析

    对于长度为 n 的数组,选择排序的执行过程如下:

    • 第 1 轮:需要比较 n-1 次(在 n 个元素中找最小值)
    • 第 2 轮:需要比较 n-2 次(在 n-1 个元素中找最小值)
    • ...
    • 第 n-1 轮:需要比较 1 次

    总比较次数为:(n-1) + (n-2) + ... + 1 = n(n-1)/2,这是一个关于 n 的二次函数。

    时间复杂度情况

    • 最好情况:O (n²) - 即使数组已经有序,仍需完整遍历寻找最小值
    • 最坏情况:O (n²) - 数组完全逆序时
    • 平均情况:O(n²)

    选择排序的时间复杂度不受输入数据的有序程度影响,这是它与冒泡排序、插入排序的重要区别。

    因为不管你有没有序,我都要比较。

    空间复杂度分析

    选择排序的空间特性非常优秀:

    • 它只需要几个额外的变量(如用于记录最小值索引的 minIndex 和交换用的临时变量 temp
    • 排序过程在原数组上进行,不需要额外的数组或数据结构

    因此,选择排序的空间复杂度为 O (1),属于原地排序(In-place Sorting) 算法。

    稳定性

    选择排序是不稳定的排序算法。

    例如,对于数组 [2, 2, 1],排序后第一个 2 会被交换到最后,导致两个 2 的相对顺序改变。

    交换次数

    选择排序的交换次数很少,最多为 n-1 次(每轮最多交换一次),这是它相比冒泡排序的一个优势。

    四、选择排序的优化思路

    基础的选择排序每次只寻找一个最小值,我们可以优化为双向选择排序,同时寻找最小值和最大值:

    双向选择排序的Java实现

    public class Selection {public static void main(String[] args) {Integer[] a = {1,9,6,7,66,11,326,98};sort(a);System.out.println(Arrays.toString(a));}public static void sort(Comparable[] a){int left = 0;int right = a.length - 1;while (left < right) {int minIndex = left;int maxIndex = right;// 在未排序部分中同时找出最小值和最大值的索引for (int i = left; i <= right; i++) {if (greater(a[minIndex], a[i])) {minIndex = i;}if (greater(a[i], a[maxIndex])) {maxIndex = i;}}// 处理最小值if (minIndex != left) {exchange(a, minIndex, left);// 如果最大值在 left 位置,交换后最大值位置变为 minIndexif (maxIndex == left) {maxIndex = minIndex;}}// 处理最大值if (maxIndex != right) {exchange(a, maxIndex, right);}// 缩小未排序部分的范围left++;right--;}}// 比较v是否大于n;public static boolean greater(Comparable v, Comparable n){// 调用comparable的方法// v大于n时返回 1,// v等于n时返回 0,// v小于n时返回 -1int i = v.compareTo(n);return i > 0;}// 交换方法public static void exchange(Comparable[] a, int i, int j){Comparable temp = a[i];a[i] = a[j];a[j] = temp;}
    }

    双向选择排序的优势是将外层循环的次数减少了一半,虽然时间复杂度仍然是 O (n²),但实际运行效率有所提升。

    五、选择排序的适用场景

    选择排序虽然时间复杂度较高,但也有其适用场景:

    1. 数据量较小的情况:对于 n≤1000 的小规模数据,选择排序简单有效
    2. 内存空间有限的场景:原地排序特性使其适合内存受限环境
    3. 交换成本较高的场景:相比冒泡排序,选择排序的交换次数少得多

    在实际开发中,Java 标准库中的排序算法(如 Arrays.sort ())在不同场景下会使用不同的排序策略,但对于理解排序算法的基本思想,选择排序是一个很好的起点。

    总结

    选择排序是一种简单直观的排序算法,其核心思想是 "选择最小(大)元素,放到正确位置"。虽然时间复杂度为 O (n²),不适合大规模数据排序,但它实现简单、空间复杂度低、交换次数少的特点,使其在特定场景下仍有应用价值。

    http://www.lryc.cn/news/620027.html

    相关文章:

  • 使用 6 种方法将文件从 Android 无缝传输到iPad
  • C# 反射和特性(获取Type对象)
  • 攒钱学概论:5、创业术
  • window显示驱动开发—DirectX 9 资源创建
  • 《AVL树的原理与C++实现:详解平衡二叉搜索树的高效构建与操作》
  • 【自动化运维神器Ansible】playbook主机清单变量深度解析:主机变量与组变量的实战应用
  • JavaWeb-Servlet基础
  • CodeBuddy在AI开发方面的一些特色
  • 1.Cursor快速入门与配置
  • PyTorch Tensor完全指南:深度学习数据操作的核心艺术
  • Matlab(4)
  • C++ stack and queue
  • 【OSPP 开源之夏】Good First issue 第一步—— openEuler Embedded 计划
  • 机器视觉的零件误差检测系统:基于多角度点云融合的圆柱体零件尺寸测量
  • 5. synchronized 关键字 - 监视器锁 monitor lock
  • InnoDB如何解决脏读、不可重复读和幻读的?
  • mysql - 查询重复数据,不区分大小重复问题解决
  • 服务器查看 GPU 占用情况的方法
  • 安全点(Safepoint)完成后唤醒暂停线程的过程
  • 响应式对象的类型及其使用场景
  • 量子安全新纪元:F5发布全新AI驱动的全栈式后量子加密AI安全方案
  • 破解测试数据困境:5招兼顾安全与真实性
  • 全球AI安全防护迈入新阶段:F5推出全新AI驱动型应用AI安全解决方案
  • 【前端Vue】使用ElementUI实现表单中可选择可编辑的下拉框
  • 仓库无人叉车的安全功能有哪些?如何在提升效率时保障安全?
  • k8s中的控制器的使用
  • 汽车高位制动灯难达 CIE 标准?OAS 光学软件高效优化破局
  • 中科米堆CASAIM汽车零部件三维扫描检测解决方案
  • 服务器通过生成公钥和私钥安全登录
  • 单例模式的理解