【数据结构排序算法篇】----选择排序【实战演练】

简介: 【数据结构排序算法篇】----选择排序【实战演练】

作为一名对技术充满热情的学习者,我一直以来都深刻地体会到知识的广度和深度。在这个不断演变的数字时代,我远非专家,而是一位不断追求进步的旅行者。通过这篇博客,我想分享我在某个领域的学习经验,与大家共同探讨、共同成长。请大家以开放的心态阅读,相信你们也会在这段知识之旅中找到启示。



前言

前面我们已经学习了较为简单的冒泡排序,相信大家对排序也有了新的认识,今天我们就来谈谈选择排序,通过对选择排序的讲解,搭配各种实战题目,来加强大家对排序算法新的认识,也希望同学们可以看完讲解后先将题目做一做。


一、什么是选择排序

选择排序是一种简单直观的比较排序算法。它的基本思想是:首先通过比较找出最小(或最大)元素,然后将它和数组的第一个元素交换。接下来,再从剩下的元素中找出最小(或最大)的元素,再与数组的第二个元素交换。如此继续,直到整个数组排序完成。

选择排序的过程大概可以分为以下几个步骤:

  1. 从数组的当前位置开始扫描数组,找到最小(或最大)元素的索引,这个位置可以称作“选择位置”。
  2. 将找到的最小(或最大)元素与“选择位置”上的元素交换。
  3. 对数组的剩余部分重复以上步骤。

选择排序的性能分析:

  • 时间复杂度:由于选择排序需要两层循环,其平均和最坏情况下的时间复杂度均为 O(n^2),其中 n 是数组的长度。
  • 空间复杂度:选择排序是原地排序算法,因此空间复杂度为 O(1)。
  • 不稳定性:选择排序是不稳定的排序算法,因为它在交换元素时可能会改变相等元素的初始相对位置。

选择排序比较适合小规模数据的排序,但由于其时间复杂度较高,在大规模数据排序时效率要低于其他效率更高的排序算法,如快速排序、归并排序等。

二、练习

较为简单的练习

这里有一个简单的选择排序的例题:

  • 例题:“使用选择排序算法对数组 [29, 10, 14, 37, 13] 进行升序排序,并说明每一轮选择过程。”
  • 解答:

选择排序的基本思想是遍历数组,每一轮都找出当前未处理序列中最小的元素,然后与未处理序列的第一个元素交换位置。

对于数组 [29, 10, 14, 37, 13],选择排序的过程是这样的:

第1轮:

  • 查找最小值:10
  • 10 与第一个元素 29 交换位置
  • 排序后的数组:[10, 29, 14, 37, 13]

第2轮:

  • 从第二个元素开始查找最小值:13
  • 13 与第二个元素 29 交换位置
  • 排序后的数组:[10, 13, 14, 37, 29]

第3轮:

  • 从第三个元素开始查找最小值:14 (这一轮实际上不需要做任何交换,因为第三个元素已经是当前最小值)
  • 排序后的数组:[10, 13, 14, 37, 29]

第4轮:

  • 从第四个元素开始查找最小值:29
  • 29 与第四个元素 37 交换位置
  • 排序后的数组:[10, 13, 14, 29, 37]

至此排序已经完成,因为最后一轮只剩一个元素,它必定是当前最大值。最终排序结果为:[10, 13, 14, 29, 37]

这就是选择排序的基本操作。每一轮选择都保证了该轮选择位置开始到数组末尾部分的最小值被放置在了选择位置上。经过多轮这样的处理,数组最终达到有序状态。

较为复杂的练习

  • 例题:“使用选择排序算法对数组 [64, 34, 25, 12, 22, 11, 90, 11, 64] 进行升序排序,并详细说明每一步骤。”
  • 解答:

使用选择排序对数组进行升序排序的详细步骤如下:

初始数组:[64, 34, 25, 12, 22, 11, 90, 11, 64]

第1轮:

  • 查找最小值:11(索引5)
  • 11(索引5)与第一个元素64(索引0)交换位置
  • 排序后数组:[11, 34, 25, 12, 22, 64, 90, 11, 64]

第2轮:

  • 从第二个元素开始查找最小值:11(索引7)
  • 11(索引7)与第二个元素34(索引1)交换位置
  • 排序后数组:[11, 11, 25, 12, 22, 64, 90, 34, 64]

第3轮:

  • 从第三个元素开始查找最小值:12(索引3)
  • 12(索引3)与第三个元素25(索引2)交换位置
  • 排序后数组:[11, 11, 12, 25, 22, 64, 90, 34, 64]

第4轮:

  • 从第四个元素开始查找最小值:22(索引4)
  • 22(索引4)与第四个元素25(索引3)交换位置
  • 排序后数组:[11, 11, 12, 22, 25, 64, 90, 34, 64]

第5轮:

  • 从第五个元素开始查找最小值:25(索引4,当前位置)
  • 25 已处于正确位置,无需交换
  • 排序后数组:[11, 11, 12, 22, 25, 64, 90, 34, 64]

第6轮:

  • 从第六个元素开始查找最小值:34(索引7)
  • 34(索引7)与第六个元素64(索引5)交换位置
  • 排序后数组:[11, 11, 12, 22, 25, 34, 90, 64, 64]

第7轮:

  • 从第七个元素开始查找最小值:64(索引7)
  • 64(索引7)与第七个元素90(索引6)交换位置
  • 排序后数组:[11, 11, 12, 22, 25, 34, 64, 90, 64]

第8轮(最后一轮):

  • 从第八个元素开始查找最小值:64(索引8)
  • 64(索引8)与第八个元素90(索引7)交换位置
  • 排序后数组:[11, 11, 12, 22, 25, 34, 64, 64, 90]

排序完成。最终排序结果为:[11, 11, 12, 22, 25, 34, 64, 64, 90]。

在选择排序中,每次迭代后最小的未排序元素都被放置到前面的正确位置,逐步完成整个数组的排序。这个例子比前一个例子更复杂,因为数组较长并且包含了重复的元素。请注意,即使11重复两次,在选择排序中它们也会被找到并放置在数组的开始两个位置,所以算法在处理重复值时也同样适用。

三、排序算法的优缺点

选择排序算法的优缺点可以从多个方面进行分析:

  • 优点:

1. 简单易懂:选择排序的算法逻辑十分简单,它通过不断选择剩余元素中的最小值来实现排序,非常容易理解和实现。

2. 原地排序:不需要额外的大量存储空间,除了输入数组外,只需要一个额外的存储空间来保存临时变量(当前最小值的索引)。

3. 数据移动最小化:选择排序在交换过程中,每次迭代只需要做一次交换动作,即便是在数组完全逆序的情况下,其数据交换次数也不会增加。

  • 缺点:

1. 时间复杂度高:不论数组的初始状态如何,选择排序都会执行 O(n^2) 次比较。因此,其平均和最坏情况下的时间复杂度都是 O(n^2),这使得选择排序在处理较大数据集时效率低下。

2. 不稳定的排序算法:当存在相等的元素时,由于选择排序可能会跳过它们将更远处的元素交换到前面,从而打乱相等元素的初始相对顺序。

3. 性能问题:由于时间复杂度为 O(n^2),选择排序在数据量大时表现不佳,特别是与 O(n log n) 时间复杂度的高效排序算法(如快速排序、归并排序等)相比,性能上差距明显。

4. 不适应动态数据:选择排序不适合对实时生成的数据或者动态变化的数据集进行排序,因为它需要在开始排序之前拥有完整的数据集。

综上所述,选择排序由于算法简单,可能适合于小数据量的排序任务。然而,在大多数实际应用场景中,会选择更高效的排序算法来处理数据。

四、面试题

由于选择排序算法比较简单,在实际面试考察中,题目一般都比较简单。不过如果面试官希望测试对选择排序的深入理解和编程细节,他们可能会问一些关于优化和特定情况的处理的问题。

下面提供一个简单的选择排序实现,并在注释中详细解释代码:

public class SelectionSort {
    public static void sort(int[] arr) {
        // arr.length 为数组的长度
        for (int i = 0; i < arr.length - 1; i++) {
            // 初始时假设最小值的位置从i开始
            int minIndex = i;
            
            // 在数组剩余部分寻找最小值的索引
            for (int j = i + 1; j < arr.length; j++) {
                // 如果找到比当前最小值更小的元素
                // 更新最小值的索引
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            
            // 如果最小值不在其原本假设的位置,交换位置
            if (minIndex != i) {
                int temp = arr[minIndex];
                arr[minIndex] = arr[i];
                arr[i] = temp;
            }
            
            // 打印每轮排序后的数组状态
            System.out.println(java.util.Arrays.toString(arr));
        }
    }
    public static void main(String[] args) {
        int[] exampleArray = {64, 25, 12, 22, 11};
        // 调用排序方法
        sort(exampleArray);
        // 打印排序结果
        System.out.println("Sorted array: ");
        System.out.println(java.util.Arrays.toString(exampleArray));
    }
}

解释:

  • 这段代码实现了一个标准的选择排序算法。
  • sort 方法接收一个 int 类型数组 arr 作为参数,并对其进行原地排序。
  • 外层循环从第一个元素开始迭代,直到倒数第二个元素。因为当只剩最后一个元素时,它已经是在正确的位置,不需要再排序。
  • minIndex 初始设为当前迭代的起始位置 i,这代表了在每一轮迭代我们假设的最小元素的索引。
  • 内层循环从 i+1 开始,即未排序的部分,用于寻找实际的最小元素的索引。
  • 内层循环中如果发现有更小的元素,则更新 minIndex
  • 内层循环结束后,如果 minIndex 不等于 i(表示有比假设的最小值更小的元素),将这两个元素交换。
  • 每次外层循环结束后,都会打印当前排序状态,方便面试者展示每一步的排序结果。
  • main 方法创建了一个示例数组,调用 sort 方法并最终打印出排序后的数组。

记住,在面试时面试官可能更偏向于了解代码的效率、逻辑清晰性以及对排序算法的理解。因此,即使选择排序算法逻辑比较简单,你依然可以展现出对代码细节和性能影响的深入理解。


总结

通过讲解和题目的练习,相信大家对其他排算法的探究有了更多的热情,后面我们会不断地学习后续排序算法,希望大家可以在学习排序中理解数据结构这门课程真正的意义。

感谢大家抽出宝贵的时间来阅读博主的博客,新人博主,感谢大家关注点赞,祝大家未来的学习工作生活一帆风顺,加油!!!

目录
相关文章
|
30天前
|
算法 数据可视化 测试技术
HNSW算法实战:用分层图索引替换k-NN暴力搜索
HNSW是一种高效向量检索算法,通过分层图结构实现近似最近邻的对数时间搜索,显著降低查询延迟。相比暴力搜索,它在保持高召回率的同时,将性能提升数十倍,广泛应用于大规模RAG系统。
123 10
HNSW算法实战:用分层图索引替换k-NN暴力搜索
|
6月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
1月前
|
机器学习/深度学习 缓存 算法
微店关键词搜索接口核心突破:动态权重算法与语义引擎的实战落地
本文详解微店搜索接口从基础匹配到智能推荐的技术进阶路径,涵盖动态权重、语义理解与行为闭环三大创新,助力商家提升搜索转化率、商品曝光与用户留存,实现技术驱动的业绩增长。
|
3月前
|
机器学习/深度学习 算法 文件存储
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
神经架构搜索(NAS)正被广泛应用于大模型及语言/视觉模型设计,如LangVision-LoRA-NAS、Jet-Nemotron等。本文回顾NAS核心技术,解析其自动化设计原理,探讨强化学习、进化算法与梯度方法的应用与差异,揭示NAS在大模型时代的潜力与挑战。
786 6
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
|
1月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
2月前
|
机器学习/深度学习 资源调度 算法
遗传算法模型深度解析与实战应用
摘要 遗传算法(GA)作为一种受生物进化启发的优化算法,在复杂问题求解中展现出独特优势。本文系统介绍了GA的核心理论、实现细节和应用经验。算法通过模拟自然选择机制,利用选择、交叉、变异三大操作在解空间中进行全局搜索。与梯度下降等传统方法相比,GA不依赖目标函数的连续性或可微性,特别适合处理离散优化、多目标优化等复杂问题。文中详细阐述了染色体编码、适应度函数设计、遗传操作实现等关键技术,并提供了Python代码实现示例。实践表明,GA的成功应用关键在于平衡探索与开发,通过精心调参维持种群多样性同时确保收敛效率
|
2月前
|
机器学习/深度学习 边缘计算 人工智能
粒子群算法模型深度解析与实战应用
蒋星熠Jaxonic是一位深耕智能优化算法领域多年的技术探索者,专注于粒子群优化(PSO)算法的研究与应用。他深入剖析了PSO的数学模型、核心公式及实现方法,并通过大量实践验证了其在神经网络优化、工程设计等复杂问题上的卓越性能。本文全面展示了PSO的理论基础、改进策略与前沿发展方向,为读者提供了一份详尽的技术指南。
粒子群算法模型深度解析与实战应用
|
4月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
146 1
|
4月前
|
搜索推荐
选择排序与其它排序算法比较
选择排序与冒泡排序同属O(n²)排序算法,但选择排序不稳定。相比堆排序,虽每轮均选最大元素,但选择排序基于线性结构,效率较低,而堆排序利用大顶堆结构提升了选择效率。
72 0
|
4月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
144 0