选择排序:原理、实现与优化

选择排序(Selection Sort)是入门级的排序算法之一,它的核心思想简单易懂,实现成本低,非常适合编程新手理解排序的基本逻辑。本文将从原理、C 语言实现、性能分析到优化思路,全方位讲解选择排序。

一、选择排序的核心原理

选择排序的核心可以概括为 **"找最值,放位置"**,它将数组分为 "已排序区间" 和 "未排序区间":

  1. 初始时,已排序区间为空,未排序区间为整个数组;

  2. 遍历未排序区间,找到其中的最小值(或最大值);

  3. 将找到的最值与未排序区间的第一个元素交换位置,此时该元素归入已排序区间;

  4. 重复步骤 2-3,直到未排序区间为空

    直观示例

    以数组 [5, 2, 9, 1, 5, 6] 为例,选择排序的执行过程:

  5. 第 1 轮:未排序区间 [5,2,9,1,5,6],最小值是 1,与第一个元素 5 交换 → [1, 2, 9, 5, 5, 6]

  6. 第 2 轮:未排序区间 [2,9,5,5,6],最小值是 2,无需交换 → [1, 2, 9, 5, 5, 6]

  7. 第 3 轮:未排序区间 [9,5,5,6],最小值是 5,与 9 交换 → [1, 2, 5, 9, 5, 6]

  8. 第 4 轮:未排序区间 [9,5,6],最小值是 5,与 9 交换 → [1, 2, 5, 5, 9, 6]

  9. 第 5 轮:未排序区间 [9,6],最小值是 6,与 9 交换 → [1, 2, 5, 5, 6, 9]

  10. 第 6 轮:未排序区间仅剩一个元素,排序完成。二、C 语言实现选择排序(升序)

二、C 语言实现选择排序(升序)

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

// 交换两个整数的值
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 选择排序(升序)
void selectionSort(int arr[], int n) {
    // i 表示已排序区间的末尾(未排序区间的起始)
    for (int i = 0; i < n - 1; i++) {
        // 假设未排序区间第一个元素是最小值
        int minIndex = i;
        
        // 遍历未排序区间,找到最小值的下标
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j; // 更新最小值下标
            }
        }
        
        // 将最小值交换到未排序区间的第一个位置
        if (minIndex != i) { // 优化:避免自身交换
            swap(&arr[i], &arr[minIndex]);
        }
    }
}

// 打印数组
void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

// 主函数测试
int main() {
    int arr[] = {5, 2, 9, 1, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    
    printf("排序前的数组:");
    printArray(arr, n);
    
    selectionSort(arr, n);
    
    printf("排序后的数组:");
    printArray(arr, n);
    
    return 0;
}

三、选择排序的性能分析

1. 时间复杂度

  • 最好情况:数组已有序,时间复杂度仍为 O(n2)(必须遍历找最值,无法提前终止);
  • 最坏情况:数组逆序,时间复杂度 O(n2);
  • 平均情况:O(n2)。

选择排序的时间复杂度始终是 O(n2),这是因为它的内层循环必须完整遍历未排序区间,无法像冒泡排序那样提前终止。

2. 空间复杂度

选择排序是原地排序算法 (In-place Sort),仅使用了常数级的临时变量(如 tempminIndex),空间复杂度为 O(1)。

3. 稳定性

选择排序是不稳定排序 。例如数组 [2, 3, 2, 1],第一轮找到最小值 1,与第一个 2 交换后,原数组中两个 2 的相对位置被改变(变为 [1, 3, 2, 2]

四、选择排序的优化:双向选择排序

基础选择排序每轮只找最小值,优化思路是每轮同时找最小值和最大值,减少循环次数,这就是 "双向选择排序"(也叫 "鸡尾酒排序" 简化版)

cs 复制代码
// 双向选择排序(同时找最小和最大值)
void bidirectionalSelectionSort(int arr[], int n) {
    int left = 0;          // 未排序区间左边界
    int right = n - 1;     // 未排序区间右边界
    
    while (left < right) {
        int minIndex = left;
        int maxIndex = right;
        
        // 遍历未排序区间,同时找最小和最大值下标
        for (int i = left; i <= right; i++) {
            if (arr[i] < arr[minIndex]) {
                minIndex = i;
            }
            if (arr[i] > arr[maxIndex]) {
                maxIndex = i;
            }
        }
        
        // 交换最小值到左边界
        if (minIndex != left) {
            swap(&arr[left], &arr[minIndex]);
        }
        
        // 注意:如果最大值在左边界(刚被交换走),需要更新maxIndex
        if (maxIndex == left) {
            maxIndex = minIndex;
        }
        
        // 交换最大值到右边界
        if (maxIndex != right) {
            swap(&arr[right], &arr[maxIndex]);
        }
        
        // 缩小未排序区间
        left++;
        right--;
    }
}

优化说明

双向选择排序每轮处理两个元素(最小值放左、最大值放右),循环次数减少约一半,但时间复杂度仍为 O(n2)(仅减少常数项,不改变阶数),适合数据量较大的场景。

五、选择排序的适用场景

选择排序的优势是交换次数少(最多 n−1 次交换),因此适合:

  1. 数据量小的场景(如嵌入式系统、单片机);
  2. 交换成本远高于比较成本的场景(如磁盘数据排序);
  3. 编程新手理解排序逻辑的入门场景。

总结

  1. 选择排序的核心是遍历找最值,交换到指定位置,将数组分为已排序 / 未排序区间;
  2. 基础选择排序的 C 语言实现简单,时间复杂度固定为 O(n2),空间复杂度 O(1),是不稳定排序;
  3. 双向选择排序可减少循环次数,但未改变时间复杂度阶数,适合对交换次数敏感的场景。

选择排序虽然效率不高,但它的逻辑简单、代码易实现,是理解排序算法 "分区间、找规律" 思想的绝佳入门案例。掌握选择排序后,再学习冒泡、插入排序等算法,会更容易理解不同排序思路的差异

相关推荐
想唱rap3 小时前
应用层协议与序列化
linux·运维·服务器·网络·数据结构·c++·算法
重生之我是Java开发战士3 小时前
【笔试强训】Week3:重排字符串,分组,DNA序列
算法
We་ct3 小时前
LeetCode 97. 交错字符串:动态规划详解
前端·算法·leetcode·typescript·动态规划
热心网友俣先生3 小时前
2026年第二十三届五一数学建模竞赛B题四问参考答案+多算法对比
算法·数学建模
无敌昊哥战神3 小时前
【LeetCode 37】解数独 (Sudoku Solver) —— 回溯法详解 (Python/C/C++)
c语言·c++·python·算法·leetcode
风筝在晴天搁浅3 小时前
LeetCode 162.寻找峰值
算法·leetcode
itzixiao3 小时前
L1-067 洛希极限(10分)[java][python]
java·开发语言·算法
jinyishu_4 小时前
链表经典OJ题
c语言·数据结构·算法·链表
葫三生4 小时前
三生原理文章被AtomGit‌开源社区收录的意义探析?
人工智能·深度学习·神经网络·算法·搜索引擎·开源·transformer
AI进化营-智能译站4 小时前
ROS2 C++开发系列15-模板实现通用算法|宏定义ROS2调试开关|一次编码适配多平台
java·c++·算法·ai