算法实现 - 选择排序(Selection sort) - 理解版

算法介绍

一种简单直观的排序算法,其基本思想是每次从待排序的元素中选择最小(或最大)的元素,放到已排序序列的末尾,以此类推,直到所有元素排序完成。

选择排序适用于数据量小或者对排序效率要求不高的场景,常用于教学和学习排序算法的基本概念。

算法分析

核心思想

  1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  2. 从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

图解运行过程

使用数列a[] = {40, 20, 30, 60, 10, 50} 进行分析

分析:
第1轮(i=0):

  • 当前数组: {40, 20, 30, 60, 10, 50}
  • 找到最小值:
    • 与 40 比较:20 是更小的,更新 minIndex = 1
    • 与 20 比较:30 > 20,不更新
    • 与 30 比较:60 > 20,不更新
    • 与 60 比较:10 是更小的,更新 minIndex = 4
    • 与 10 比较:50 > 10,不更新
  • 最小值为 10,位置为 4,交换 40 和 10。

第2轮(i=1):

  • 当前数组: {10, 20, 30, 60, 40, 50}
  • 找到最小值:
    • 与 20 比较:30 > 20,不更新
    • 与 20 比较:60 > 20,不更新
    • 与 20 比较:40 > 20,不更新
    • 与 20 比较:50 > 20,不更新
  • 最小值为 20,位置为 1,不需要交换。

第3轮(i=2):

  • 当前数组: {10, 20, 30, 60, 40, 50}
  • 找到最小值:
    • 与 30 比较:60 > 30,不更新
    • 与 30 比较:40 > 30,不更新
    • 与 30 比较:50 > 30,不更新
  • 最小值为 30,位置为 2,不需要交换。

第4轮(i=3):

  • 当前数组: {10, 20, 30, 60, 40, 50}
  • 找到最小值:
    • 与 60 比较:40 是更小的,更新 minIndex = 4
    • 与 60 比较:50 > 40,不更新
  • 最小值为 40,位置为 4,交换 60 和 40。

第5轮(i=4):

  • 当前数组: {10, 20, 30, 40, 60, 50}
  • 找到最小值:
    • 与 60 比较:50 是更小的,更新 minIndex = 5
  • 最小值为 50,位置为 5,交换 60 和 50。

第6轮(i=5):

  • 当前数组: {10, 20, 30, 40, 50, 60}
  • 这是最后一个元素,不需要再查找。
  • 最终结果数组: {10, 20, 30, 40, 50, 60}

算法稳定性和复杂度

稳定性

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

选择排序不稳定的原因在于其工作原理:在每一轮选择最小(或最大)元素的过程中,如果存在多个相同的最小(或最大)元素,选择排序可能会将它们的位置交换,从而导致这些相同元素的相对位置发生改变。

示例分析:

考虑数组 { 4 a 4_a 4a, 3, 4 b 4_b 4b, 2} 进行选择排序的过程:

第一轮: 找到最小值 2,交换到最前面。结果为 {2, 3, 4, 4 a 4_a 4a}。

第二轮: 找到下一个最小值 3,已在正确的位置,无需交换。结果仍为 {2, 3, 4, 4 a 4_a 4a}。

第三轮: 找到下一最小值 4,发现最后的 4 与当前 4 交换,结果变为 {2, 3, 4 a 4_a 4a, 4 b 4_b 4b}。

在整个排序过程中,两个 4 的相对位置没有发生变化。但如果选择排序选择了交换的策略,比如有多个相同最小值造成的交换,会使 4 的相对顺序发生变化。

时间复杂度

最差情况

基本操作:

循环遍历:遍历未排序部分以找到最小(或最大)元素。

交换元素:将找到的最小(或最大)元素与未排序部分的第一个元素交换位置。

执行次数:

对于长度为 n 的数组,选择排序需要进行 n-1 轮选择。在第 i 轮选择中,算法需要在剩余的 n-i 个元素中找到最小(或最大)元素,这需要 n-i 次比较。因此,总比较次数是:
C ( n ) = ( n − 1 ) + ( n − 2 ) + . . . + 2 + 1 = ( n − 1 ) n 2 C(n) = (n-1) + (n-2) + ... + 2 + 1 = \frac{(n-1)n}{2} C(n)=(n−1)+(n−2)+...+2+1=2(n−1)n

交换操作在最坏情况下也需要 n-1 次,因为每次都需要交换找到的最小(或最大)元素与未排序序列的第一个元素。

大O表示:

总操作次数(比较和交换)接近于 n 2 2 \frac{n^2}{2} 2n2,因此最差情况下的时间复杂度为 O(n^2)

平均情况

基本操作:

平均情况下,选择排序的基本操作与最差情况相同,因为每一轮都需要在剩余的未排序元素中找到最小(或最大)元素。

执行次数:

平均情况下,每轮选择操作的次数仍然是 n-i 次比较,总比较次数仍然是 n(n-1)/2。交换操作的次数仍然是 n-1。

大O表示:

总操作次数(比较和交换)接近于 n 2 2 \frac{n^2}{2} 2n2,因此最差情况下的时间复杂度为 O(n^2)

空间复杂度

选择排序是一种原地排序算法,不需要额外的存储空间,因此:

空间复杂度: O(1)

代码实现

老规矩,上原滋原味的代码💙C语言💙,

c 复制代码
#include <stdio.h>

/**
 * Selection sort by C Lang.
 *
 *  params:
 *      array -- the data need to sort
 *      n -- the length of array
 */
void selectSort(int arr[], int n)
{
    // Notice: outter loop max running time is `n-2`
    for (size_t i = 0; i < n - 1; i++)
    {
        // Assume the current position holds the minimum element
        int minIndex = i;

        // Find the minimun in arr[i+1...n].
        for (size_t j = i + 1; j < n; j++)
        {
            if (arr[j] < arr[minIndex])
            {
                // Update minIndex if a smaller element is found
                minIndex = j;
            }
        }

        // Move minimum element to its correct position
        if (minIndex != i)
        {
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
}

/**
 * show array
 */
void printArray(int arr[], int n)
{
    for (size_t i = 0; i < n; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n\n");
}

int main()
{
    int arr[] = {40, 20, 30, 60, 10, 50};
    // calculate the length of a array
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("before sort: \n");
    printArray(arr, n);

    selectSort(arr, n - 1);

    printf("after sort: \n");
    printArray(arr, n);

    return 0;
}

欢迎⭐️,附上我的Github,选择排序源代码>>

相关推荐
egoist202325 分钟前
数据结构之栈和队列(超详解)
c语言·开发语言·数据结构·算法·leetcode·栈和队列·学习成长
睡不着还睡不醒29 分钟前
【力扣】53.最大子数组和
数据结构·算法·leetcode
OpenC++4 小时前
【C++】线程池实现
开发语言·c++·经验分享·算法·leetcode·设计模式
gyeolhada7 小时前
2025蓝桥杯JAVA编程题练习Day2
java·数据结构·算法·蓝桥杯
飞yu流星9 小时前
c++ stl 遍历算法和查找算法
开发语言·c++·算法
Swift社区11 小时前
LeetCode - #197 Swift 实现找出温度更高的日期
算法·leetcode·swift
嗯嗯你说的对11 小时前
记忆化搜索和动态规划 --最长回文子串为例
算法·动态规划
金融OG12 小时前
98.2 AI量化开发:基于DeepSeek打造个人专属金融消息面-AI量化分析师(理论+全套Python代码)
人工智能·python·算法·机器学习·数学建模·金融
某个默默无闻奋斗的人14 小时前
三傻排序的比较(选择,冒泡,插入)
java·数据结构·算法
黄雪超15 小时前
算法基础——一致性
大数据·算法·一致性