菜单
×
   ❮   
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS R TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI GO KOTLIN SASS VUE DSA GEN AI SCIPY AWS CYBERSECURITY DATA SCIENCE
     ❯   

DSA 选择排序


选择排序

选择排序算法查找数组中的最小值,并将其移到数组的前面。

速度

{{ msgDone }}

该算法一遍又一遍地查找数组,将下一个最小值移到前面,直到数组被排序。

工作原理

  1. 遍历数组以查找最小值。
  2. 将最小值移到未排序部分的前面。
  3. 再遍历数组,次数与数组中的值数量相同。

继续阅读,以完全理解选择排序算法以及如何自己实现它。


手动演练

在用编程语言实现选择排序算法之前,让我们只进行一次手动遍历一个短数组,以获得一些想法。

步骤 1:我们从一个未排序的数组开始。

[ 7, 12, 9, 11, 3]

步骤 2:逐个遍历数组。哪个值是最小的? 3,对吗?

[ 7, 12, 9, 11, 3]

步骤 3:将最小值 3 移到数组的前面。

[ 3, 7, 12, 9, 11]

步骤 4:查看剩余的值,从 7 开始。 7 是最小的值,并且已经放在了数组的前面,所以我们不需要移动它。

[ 3, 7, 12, 9, 11]

步骤 5:查看数组的其余部分:12、9 和 11。 9 是最小值。

[ 3, 7, 12, 9, 11]

步骤 6:将 9 移到前面。

[ 3, 7, 9, 12, 11]

步骤 7:查看 12 和 11,11 是最小的。

[ 3, 7, 9, 12, 11]

步骤 8:将其移到前面。

[ 3, 7, 9, 11, 12]

最后,数组已排序。


运行下面的模拟,以动画形式查看以上步骤。

{{ msgDone }}
[
{{ x.dieNmbr }}
]

手动运行:发生了什么?

我们必须理解上面发生了什么,才能完全理解该算法,以便用编程语言实现该算法。

您能看出最小值 3 发生了什么吗?在步骤 3 中,它已被移到数组的开头,这是它应在的位置,但在该步骤中,数组的其余部分仍未排序。

因此,选择排序算法必须一遍又一遍地遍历数组,每次都将下一个最小值移到未排序部分的前面,移到其正确的位置。排序一直进行到最大值 12 留在数组末尾。这意味着我们需要遍历数组 4 次,以对 5 个值的数组进行排序。

每次算法遍历数组时,数组中剩余的未排序部分都会变短。

现在,我们将使用我们学到的知识来实现编程语言中的选择排序算法。


选择排序实现

要在编程语言中实现选择排序算法,我们需要

  1. 一个包含待排序值的数组。
  2. 一个内循环,遍历数组,找到最小值,并将其移到数组的前面。此循环每次运行时必须少循环一个值。
  3. 一个外循环,控制内循环需要运行多少次。对于具有 \(n\) 个值的数组,此外循环必须运行 \(n-1\) 次。

生成的代码如下:

示例

my_array = [64, 34, 25, 5, 22, 11, 90, 12]

n = len(my_array)
for i in range(n-1):
    min_index = i
    for j in range(i+1, n):
        if my_array[j] < my_array[min_index]:
            min_index = j
    min_value = my_array.pop(min_index)
    my_array.insert(i, min_value)

print("Sorted array:", my_array)
运行示例 »

选择排序移动问题

选择排序算法可以进一步改进。

在上面的代码中,移除了最小值的元素,然后将其插入到数组的前面。

每次删除下一个最小值的数组元素时,所有后续元素都必须向下移动一个位置以弥补删除。

Shifting other elements when an array element is removed.

这些移动操作花费了大量时间,而且我们还没有完成!找到并移除了最小值(5)之后,将其插入到数组的开头,导致所有后续值移动一个位置以腾出新值空间,如下图所示。

Shifting other elements when an array element is inserted.

注意:如果您使用的是 Python 或 Java 等高级编程语言,则在代码中不会看到这些移动操作,但移动操作仍在后台进行。这些移动操作需要计算机额外的时间来完成,这可能是一个问题。


解决方案:交换值!

而不是所有的移动,而是像下图所示那样,将最小值(5)与第一个值(64)进行交换。

Shifting other elements when an array element is inserted.

我们可以像上图所示那样交换值,因为最小值最终会到达正确的位置,而我们与之交换的其他值的位置并不重要,因为它还没有排序。

这是一个模拟,显示了这种改进的选择排序如何通过交换工作

速度

{{ msgDone }}

这是改进的选择排序的实现,使用了交换

示例

my_array = [64, 34, 25, 12, 22, 11, 90, 5]

n = len(my_array)
for i in range(n):
    min_index = i
    for j in range(i+1, n):
        if my_array[j] < my_array[min_index]:
            min_index = j   
    my_array[i], my_array[min_index] = my_array[min_index], my_array[i]

print("Sorted array:", my_array)
运行示例 »

选择排序时间复杂度

有关时间复杂度的一般性解释,请访问此页面

有关选择排序时间复杂度的更全面、更详细的解释,请访问此页面

选择排序对 \(n\) 个值的数组进行排序。

平均而言,大约 \(\frac{n}{2}\) 个元素需要进行比较才能在每次循环中找到最小值。

并且选择排序大约需要运行 \(n\) 次循环来查找最小值。

我们得到时间复杂度

\[ O( \frac{n}{2} \cdot n) = \underline{\underline{O(n^2)}} \]

选择排序算法的时间复杂度可以在图表中显示如下

Selection Sort time complexity

正如您所见,运行时间与冒泡排序相同:当数组大小增加时,运行时间增加得非常快。

为不同大小的数组运行下面的模拟。

红色虚线代表理论时间复杂度 \(O(n^2)\)。

蓝色十字出现在您运行模拟时。蓝色十字显示了对给定大小的数组进行排序所需的运算次数。

{{ this.userX }}

操作次数:{{ operations }}

 

与冒泡排序相比,我们在此模拟中注意到的最显著的区别是,对于选择排序,最佳情况和最坏情况实际上几乎相同(\(O(n^2)\)),但对于冒泡排序,最佳情况的运行时间仅为 \(O(n)\)。

选择排序的最佳情况和最坏情况之间的差异主要是交换次数。在最佳情况下,选择排序不必交换任何值,因为数组已经排序。而在最坏情况下,数组已经排序,但顺序错误,因此选择排序必须进行与数组中值一样多的交换。


DSA 练习

通过练习来测试自己

练习

在此数组上使用选择排序

[7,12,9,11,3]

按递增(升序)顺序对值从左到右进行排序。

第一次遍历后,最后一个元素的值是多少?



开始练习



×

联系销售

如果您想将 W3Schools 服务用于教育机构、团队或企业,请发送电子邮件给我们
sales@w3schools.com

报告错误

如果您想报告错误,或想提出建议,请发送电子邮件给我们
help@w3schools.com

W3Schools 经过优化,旨在方便学习和培训。示例可能经过简化,以提高阅读和学习体验。教程、参考资料和示例会不断审查,以避免错误,但我们无法保证所有内容的完全正确性。使用 W3Schools 即表示您已阅读并接受我们的使用条款Cookie 和隐私政策

版权所有 1999-2024 Refsnes Data。保留所有权利。W3Schools 由 W3.CSS 提供支持