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

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

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



前言

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


一、什么是选择排序

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

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

  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月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
49 1
|
2月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
119 4
|
3月前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
85 2
|
12天前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
49 20
|
2月前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
2月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
2月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
112 23
|
2月前
|
算法
数据结构之蜜蜂算法
蜜蜂算法是一种受蜜蜂觅食行为启发的优化算法,通过模拟蜜蜂的群体智能来解决优化问题。本文介绍了蜜蜂算法的基本原理、数据结构设计、核心代码实现及算法优缺点。算法通过迭代更新蜜蜂位置,逐步优化适应度,最终找到问题的最优解。代码实现了单链表结构,用于管理蜜蜂节点,并通过适应度计算、节点移动等操作实现算法的核心功能。蜜蜂算法具有全局寻优能力强、参数设置简单等优点,但也存在对初始化参数敏感、计算复杂度高等缺点。
62 20
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
65 1
|
2月前
|
机器学习/深度学习 算法 C++
数据结构之鲸鱼算法
鲸鱼算法(Whale Optimization Algorithm,WOA)是由伊朗研究员Seyedali Mirjalili于2016年提出的一种基于群体智能的全局优化算法,灵感源自鲸鱼捕食时的群体协作行为。该算法通过模拟鲸鱼的围捕猎物和喷出气泡网的行为,结合全局搜索和局部搜索策略,有效解决了复杂问题的优化需求。其应用广泛,涵盖函数优化、机器学习、图像处理等领域。鲸鱼算法以其简单直观的特点,成为初学者友好型的优化工具,但同时也存在参数敏感、可能陷入局部最优等问题。提供的C++代码示例展示了算法的基本实现和运行过程。
59 0