当前位置: 首页 > news >正文

【C语言选择排序算法详解】+ 算法性能优化 + 动态演示实现

文章目录

      • 一、算法介绍
      • 二、算法特点
      • 三、代码实现与解析
      • 四、代码解析
          • 1. 打印数组函数
          • 2. 选择排序核心逻辑
          • 3. 动态展示实现
          • 4. 主函数
      • 五、算法优化思路与实现
          • 优化1:减少交换次数
          • 优化原理:
          • 优化2:双向选择排序
          • 优化原理:
          • 优化3:提前终止检查
          • 优化原理:
      • 总结:

一、算法介绍

选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理是:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

二、算法特点

时间复杂度:O(n²)

空间复杂度:O(1)

不稳定排序算法

原地排序算法

三、代码实现与解析

#include <stdio.h>
#include <windows.h>  // 用于Sleep函数(Windows环境)// 打印数组
void loop_print_array(int arr[], int len) {for (int i = 0; i < len; i++) {printf("%d ", arr[i]);}printf("\n");
}// 选择排序(添加动态展示逻辑)
void selection_sort(int arr[], int len) {for (int i = 0; i < len - 1; i++) {for (int j = i + 1; j < len; j++) {if (arr[i] > arr[j]) {// 交换元素int temp = arr[i];arr[i] = arr[j];arr[j] = temp;// 🔴 关键:交换后打印当前数组 + 暂停system("cls");  // Windows下清屏,让显示更连贯(Linux/macOS用system("clear"))printf("第 %d 轮比较,交换 arr[%d] 和 arr[%d] 后:\n", i+1, i, j);loop_print_array(arr, len);Sleep(1000);  // 暂停800毫秒(可调整速度,单位:毫秒)}}}
}
int main() {// 设置控制台输出编码为UTF-8,避免中文乱码SetConsoleOutputCP(CP_UTF8);SetConsoleCP(CP_UTF8);int arr[10] = {5, 8, 1, 4, 2, 9, 10, 3, 7, 6};int len = sizeof(arr) / sizeof(int);printf("排序前:\n");loop_print_array(arr, len);Sleep(1000);  // 先暂停1秒,看清初始数组selection_sort(arr, len);printf("\n排序完成:\n");loop_print_array(arr, len);return 0;
}

四、代码解析

1. 打印数组函数

c
void loop_print_array(int arr[], int len) {
for (int i = 0; i < len; i++) {
printf(“%d “, arr[i]);
}
printf(”\n”);
}
这个函数负责遍历数组并打印所有元素,方便我们观察排序过程中数组的变化。

2. 选择排序核心逻辑
void selection_sort(int arr[], int len) {for (int i = 0; i < len - 1; i++) {for (int j = i + 1; j < len; j++) {if (arr[i] > arr[j]) {// 交换元素int temp = arr[i];arr[i] = arr[j];arr[j] = temp;// 动态展示部分system("cls");printf("第 %d 轮比较,交换 arr[%d] 和 arr[%d] 后:\n", i+1, i, j);loop_print_array(arr, len);Sleep(1000);}}}
}

选择排序的核心是双重循环:

  • 外层循环控制排序的轮数,每轮确定一个最小元素的位置

  • 内层循环用于查找未排序部分的最小元素

  • 当找到比当前基准更小的元素时,进行交换

3. 动态展示实现

代码中添加了动态展示逻辑:

使用 system(“cls”) 清屏,使每次输出更加清晰

打印当前操作信息(第几轮比较,交换了哪些元素)

使用 Sleep(1000) 暂停1秒,方便观察每一步的变化

4. 主函数
int main() {SetConsoleOutputCP(CP_UTF8);SetConsoleCP(CP_UTF8);int arr[10] = {5, 8, 1, 4, 2, 9, 10, 3, 7, 6};int len = sizeof(arr) / sizeof(int);// 初始数组展示printf("排序前:\n");loop_print_array(arr, len);Sleep(1000);// 执行排序selection_sort(arr, len);// 最终结果展示printf("\n排序完成:\n");loop_print_array(arr, len);return 0;
}

主函数中:

设置控制台编码为UTF-8,避免中文乱码

初始化待排序数组

展示排序前的数组

调用选择排序函数

展示排序后的最终结果

五、算法优化思路与实现

虽然选择排序的时间复杂度固定为O(n²),但仍可以做一些优化来提高实际性能:

优化1:减少交换次数

原始实现中每次找到更小的元素就立即交换,实际上我们可以记录最小值的索引,在一轮比较完成后只交换一次:

// 优化版本1:减少交换次数
void selection_sort_optimized(int arr[], int len) {for (int i = 0; i < len - 1; i++) {int min_index = i; // 记录最小元素的索引for (int j = i + 1; j < len; j++) {if (arr[j] < arr[min_index]) {min_index = j; // 更新最小元素的索引}}// 只有在找到更小元素时才交换if (min_index != i) {int temp = arr[i];arr[i] = arr[min_index];arr[min_index] = temp;// 动态展示system("cls");printf("第 %d 轮,找到最小值 arr[%d]=%d,与 arr[%d]=%d 交换后:\n", i+1, min_index, arr[i], i, arr[min_index]);loop_print_array(arr, len);Sleep(1000);}}
}
优化原理:

减少不必要的交换操作,每轮最多只交换一次

对于大型对象或复杂数据结构,交换操作可能成本较高,此优化能显著提高性能

优化2:双向选择排序

同时寻找最大值和最小值,减少排序轮数:

// 优化版本2:双向选择排序
void selection_sort_bidirectional(int arr[], int len) {int left = 0, right = len - 1;while (left < right) {int min_index = left, max_index = right;// 确保min_index <= max_indexif (arr[min_index] > arr[max_index]) {int temp = arr[min_index];arr[min_index] = arr[max_index];arr[max_index] = temp;}// 在剩余部分中查找最小和最大值for (int i = left + 1; i < right; i++) {if (arr[i] < arr[min_index]) {min_index = i;} else if (arr[i] > arr[max_index]) {max_index = i;}}// 将最小值放到左边if (min_index != left) {int temp = arr[left];arr[left] = arr[min_index];arr[min_index] = temp;// 如果最大值原本在left位置,现在被移到了min_index位置if (max_index == left) {max_index = min_index;}}// 将最大值放到右边if (max_index != right) {int temp = arr[right];arr[right] = arr[max_index];arr[max_index] = temp;}// 动态展示system("cls");printf("范围 [%d,%d],最小值放左边,最大值放右边后:\n", left, right);loop_print_array(arr, len);Sleep(1000);left++;right--;}
}
优化原理:

每轮同时找到最小和最大元素,分别放到序列的两端

减少大约一半的排序轮数

对于随机数据,性能提升约50%

优化3:提前终止检查

添加提前终止检查,当数组已经有序时提前结束排序:

// 优化版本3:添加提前终止检查
void selection_sort_early_termination(int arr[], int len) {for (int i = 0; i < len - 1; i++) {int min_index = i;bool swapped = false; // 标记本轮是否发生交换for (int j = i + 1; j < len; j++) {if (arr[j] < arr[min_index]) {min_index = j;swapped = true;}}if (min_index != i) {int temp = arr[i];arr[i] = arr[min_index];arr[min_index] = temp;// 动态展示system("cls");printf("第 %d 轮,交换 arr[%d] 和 arr[%d] 后:\n", i+1, i, min_index);loop_print_array(arr, len);Sleep(1000);} else if (!swapped) {// 如果没有找到更小的元素且未发生交换,说明数组已有序printf("第 %d 轮检测到数组已有序,提前终止排序\n", i+1);break;}}
}
优化原理:

当某一轮未发生任何交换时,说明数组已经有序,可以提前终止排序

对于近乎有序的数组,能显著提高性能

性能对比
为了直观展示优化效果,我们可以添加简单的性能测试代码:

#include <time.h>// 性能测试函数
void performance_test() {const int SIZE = 10000;int arr1[SIZE], arr2[SIZE], arr3[SIZE];// 初始化随机数组for (int i = 0; i < SIZE; i++) {int val = rand() % 1000;arr1[i] = val;arr2[i] = val;arr3[i] = val;}clock_t start, end;// 测试原始版本start = clock();selection_sort(arr1, SIZE);end = clock();printf("原始版本耗时: %.3f 秒\n", (double)(end - start) / CLOCKS_PER_SEC);// 测试优化版本1start = clock();selection_sort_optimized(arr2, SIZE);end = clock();printf("优化版本1耗时: %.3f 秒\n", (double)(end - start) / CLOCKS_PER_SEC);// 测试优化版本2start = clock();selection_sort_bidirectional(arr3, SIZE);end = clock();printf("优化版本2耗时: %.3f 秒\n", (double)(end - start) / CLOCKS_PER_SEC);
}

运行效果
运行程序后,控制台会逐步展示排序过程:

首先显示初始数组:5 8 1 4 2 9 10 3 7 6

每一轮比较后,清屏并显示当前数组状态和操作信息

最后显示排序完成的有序数组:1 2 3 4 5 6 7 8 9 10

适用场景与总结
选择排序是一种简单但低效的排序算法,主要适用于:

  1. 小规模数据排序

  2. 对内存使用有严格限制的场景

  3. 作为算法学习的入门示例

总结:

选择排序的时间复杂度为O(n²),不适合大规模数据排序

通过优化可以减少交换次数和排序轮数,提高实际性能

对于大规模数据排序,建议使用更高效的算法如快速排序、归并排序等。

Created by LiuJinTao on 2025/9/13.


文章转载自:

http://mkEsfQE0.ngghw.cn
http://8ZoZbPzl.ngghw.cn
http://OU0ttl34.ngghw.cn
http://fdBLi4qW.ngghw.cn
http://lWturw8X.ngghw.cn
http://Eu9unIdT.ngghw.cn
http://gyj5hu3t.ngghw.cn
http://Jf2Kj2Gd.ngghw.cn
http://uuw3EY6T.ngghw.cn
http://y0FGEz8o.ngghw.cn
http://4HE2mvDv.ngghw.cn
http://t1Y7mne5.ngghw.cn
http://UcDVkymD.ngghw.cn
http://FxXwQ8KQ.ngghw.cn
http://2G8JEpn5.ngghw.cn
http://Gl2ia35W.ngghw.cn
http://4wnaq2gZ.ngghw.cn
http://u9Y8N1T8.ngghw.cn
http://2dXSV7aO.ngghw.cn
http://lDrsuedD.ngghw.cn
http://PcCUf2Tw.ngghw.cn
http://Ebp3eeVX.ngghw.cn
http://BZs37N4t.ngghw.cn
http://BF8jjheu.ngghw.cn
http://7DrEnsM1.ngghw.cn
http://usomXnQd.ngghw.cn
http://06mhCfeS.ngghw.cn
http://2FaU8cyT.ngghw.cn
http://OCtZJPNO.ngghw.cn
http://idawRWIX.ngghw.cn
http://www.dtcms.com/a/382049.html

相关文章:

  • 基于Matlab硬币圆形检测的实现
  • go使用反射获取http.Request参数到结构体
  • vscode使用tmux技巧
  • 【Block总结】ConverseNet:神经网络中的反向卷积算子
  • C++学习记录(8)list
  • 【C++】STL·List
  • 网络安全与iptables防火墙配置
  • Django + Vue3 前后端分离技术实现自动化测试平台从零到有系列 <第一章> 之 注册登录实现
  • Flink面试题及详细答案100道(41-60)- 状态管理与容错
  • 从基础到高级:一文快速认识MySQL UPDATE 语句
  • 基于KAZE算法的织物图像拼接matlab仿真,对比SIFT和SURF
  • 知识输出零散没有体系怎么办
  • 【LeetCode】37. 解数独
  • Redis常见性能问题
  • 数据帮助我们理解未知世界
  • 泛型通配符 T、E、K、V、?
  • STL简介及string
  • Ditty WordPress插件displayItems端点未授权访问漏洞(CVE-2025-8085)
  • 【性能优化需要关注的参数——Batches】
  • React Device Detect 完全指南:构建响应式跨设备应用的最佳实践
  • 开始 ComfyUI 的 AI 绘图之旅-Qwen-Image(十一)
  • python根据路径获取文件后缀名
  • c++雾里探花-静态多态
  • Java基础知识(十五)
  • 2025.9.14英语红宝书
  • Easy系列PLC枚举变量类型(为什么可以不实例化直接使用)
  • python全栈-自动化office
  • smartctl_exporter smartctl 统计信息
  • 软件测试常见Bug清单
  • 大数据电商流量分析项目实战:可视化 数据分析(九)