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

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

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



前言

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


一、什么是选择排序

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

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

  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 方法并最终打印出排序后的数组。

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


总结

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

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

目录
相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
90 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
2月前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
66 2
|
2月前
|
存储 缓存 算法
前端算法:优化与实战技巧的深度探索
【10月更文挑战第21天】前端算法:优化与实战技巧的深度探索
24 1
|
2月前
|
存储 算法 Java
Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性
Java Set因其“无重复”特性在集合框架中独树一帜。本文解析了Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性,并提供了最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的hashCode()与equals()方法。
40 4
|
2月前
|
搜索推荐 算法
数据结构与算法学习十四:常用排序算法总结和对比
关于常用排序算法的总结和对比,包括稳定性、内排序、外排序、时间复杂度和空间复杂度等术语的解释。
24 0
数据结构与算法学习十四:常用排序算法总结和对比
|
2月前
|
机器学习/深度学习 搜索推荐 算法
探索数据结构:初入算法之经典排序算法
探索数据结构:初入算法之经典排序算法
|
2月前
|
算法 Java 索引
数据结构与算法学习十五:常用查找算法介绍,线性排序、二分查找(折半查找)算法、差值查找算法、斐波那契(黄金分割法)查找算法
四种常用的查找算法:顺序查找、二分查找(折半查找)、插值查找和斐波那契查找,并提供了Java语言的实现代码和测试结果。
27 0
|
8天前
|
算法
基于GA遗传算法的PID控制器参数优化matlab建模与仿真
本项目基于遗传算法(GA)优化PID控制器参数,通过空间状态方程构建控制对象,自定义GA的选择、交叉、变异过程,以提高PID控制性能。与使用通用GA工具箱相比,此方法更灵活、针对性强。MATLAB2022A环境下测试,展示了GA优化前后PID控制效果的显著差异。核心代码实现了遗传算法的迭代优化过程,最终通过适应度函数评估并选择了最优PID参数,显著提升了系统响应速度和稳定性。
|
5天前
|
算法
基于WOA鲸鱼优化的购售电收益与风险评估算法matlab仿真
本研究提出了一种基于鲸鱼优化算法(WOA)的购售电收益与风险评估算法。通过将售电公司购售电收益风险计算公式作为WOA的目标函数,经过迭代优化计算出最优购电策略。实验结果表明,在迭代次数超过10次后,风险价值收益优化值达到1715.1万元的最大值。WOA还确定了中长期市场、现货市场及可再生能源等不同市场的最优购电量,验证了算法的有效性。核心程序使用MATLAB2022a实现,通过多次迭代优化,实现了售电公司收益最大化和风险最小化的目标。
|
3天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于深度学习网络的宝石类型识别算法matlab仿真
本项目利用GoogLeNet深度学习网络进行宝石类型识别,实验包括收集多类宝石图像数据集并按7:1:2比例划分。使用Matlab2022a实现算法,提供含中文注释的完整代码及操作视频。GoogLeNet通过其独特的Inception模块,结合数据增强、学习率调整和正则化等优化手段,有效提升了宝石识别的准确性和效率。