【C語言選擇排序算法詳解】+ 算法性能優化 + 動態演示實現

文章目錄

      • 一、算法介紹
      • 二、算法特點
      • 三、代碼實現與解析
      • 四、代碼解析
          • 1. 打印數組函數
          • 2. 選擇排序核心邏輯
          • 3. 動態展示實現
          • 4. 主函數
      • 五、算法優化思路與實現
          • 優化1:減少交換次數
          • 優化原理:
          • 優化2:雙向選擇排序
          • 優化原理:
          • 優化3:提前終止檢查
          • 優化原理:
      • 總結:

一、算法介紹

選擇排序(Selection Sort)是一種簡單直觀的排序算法。它的工作原理是:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后再從剩余未排序元素中繼續尋找最小(大)元素,然后放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。

二、算法特點

時間復雜度:O(n2)

空間復雜度: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(n2),但仍可以做一些優化來提高實際性能:

優化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(n2),不適合大規模數據排序

通過優化可以減少交換次數和排序輪數,提高實際性能

對于大規模數據排序,建議使用更高效的算法如快速排序、歸并排序等。

Created by LiuJinTao on 2025/9/13.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/96675.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/96675.shtml
英文地址,請注明出處:http://en.pswp.cn/web/96675.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

棧(Java)

提示&#xff1a;多練才是王道,加油?(?????)? 棧Java1. 棧2. Java中棧的其中兩種實現方式2.1 Stack類2.1.1 Stack的模擬實現2.2 LinkedList類3. 典型習題講解3.1 逆波蘭表達式求值3.2 匹配括號3.3 合理彈出序列3.4 最小棧1. 棧 棧是一種特殊的線性表,其只允許在固定的一…

LayaAir鼠標(手指)控制相機旋轉,限制角度

切換天空盒腳本掛載到相機身上 const { regClass, property } Laya;regClass() export class SmoothCameraController extends Laya.Script {declare owner: Laya.Camera;// 旋轉靈敏度property({ type: Number, name: "旋轉靈敏度" })public rotationSensitivity:…

【數據結構入門】排序算法(4)歸并排序

目錄 1.排序的原理 1.1 保證子數組有序 1.2 時間復雜度 2. 遞歸實現 2.1 思路 2.2 代碼 3. 非遞歸實現 3.1 思路 3.2 代碼 4.面試題 4.1 題目 4.2 思路 1.排序的原理 歸并排序是外排序&#xff0c;所謂外排序就是說能夠對文件中的數據進行排序。 ①首先&#xff…

FLEXSPI_Init 硬件故障問題

使用官方例程發現FLEXSPI_Init會引起硬件故障&#xff0c;查閱相關帖子發現主要有兩個可能&#xff1a;1、外部閃存配置差異修改 LUT&#xff08;查找表&#xff09;命令&#xff1a;示例中擦除扇區命令為 0xD7&#xff0c;寫狀態寄存器命令為 0x01&#xff0c;需分別改為 閃存…

如何用 Rust 重寫 SQLite 數據庫(一):項目探索

要使用 Rust 重寫 SQLite 數據庫&#xff0c;我們需要實現一個簡化的關系型數據庫核心功能&#xff08;如 SQL 解析、存儲引擎、事務管理&#xff09;。以下是一個分步實踐指南&#xff0c;包含關鍵代碼示例。一、項目規劃 我們將實現一個超簡化數據庫 MiniSQL&#xff0c;支持…

JVM之堆(Heap)

一、堆的核心特性 唯一性與共享性 每個JVM實例僅有一個堆&#xff0c;所有線程共享&#xff0c;但可通過線程私有緩沖區&#xff08;TLAB&#xff09;減少多線程分配沖突。內存結構演變 JDK 7及之前&#xff1a;堆分為新生代&#xff08;Young&#xff09;、老年代&#xff08;…

單片機的RAM與ROM概念

RAM與ROM1、RAM與ROM2、 bss、data、heap、stack、text詳細講解3、詳細探討 TCM、OCRAM 和 HBNRAM 之間的區別及其具體作用。3.1、TCM&#xff08;Tightly Coupled Memory&#xff09;3.2、 OCRAM&#xff08;On Chip RAM&#xff09;3.3、HBNRAM (Hibernate RAM)3.4、總結1、R…

實驗3:事件處理(2學時)

實驗目的&#xff08;1&#xff09;熟練掌握 v-on 指令的用法&#xff0c;學會使用 v-on 指令監聽 DOM 元素的事件&#xff0c;并通過該事件觸發調用事件處理程序。&#xff08;2&#xff09;掌握v-on 指令修飾符的基本用法。實驗內容實現購物車功能的拓展&#xff08;商品數量…

商品庫存扣減方案

文章目錄1. Lua腳本 Redis&#xff08;業界首選&#xff0c;綜合最優&#xff09;2. Redis原子命令&#xff08;DECRBY 結果校驗&#xff09;3. Redis事務&#xff08;MULTI/EXEC&#xff09;4. 分布式鎖&#xff08;基于Redis實現&#xff09;5. Redisson客戶端封裝&#xf…

關于在阿里云DMS誤操作后如何恢復數據的記錄

前言 昨天因客戶員工操作錯誤&#xff0c;導致快遞單號和訂單互換。客戶員工那邊讓筆記修改數據。 于是筆者寫下如下SQL來操作&#xff0c;導致了災難性事故。 update t_order_fed_ex_record set tracking_number 884102170661, master_tracking_number 884102170661, push…

【操作系統核心知識梳理】線程(Thread)重點與易錯點全面總結

在多任務操作系統中&#xff0c;線程是比進程更輕量的執行單元&#xff0c;理解線程的特性和實現方式是掌握并發編程的基礎。本文系統梳理了線程相關的核心知識點和常見誤區&#xff0c;助你夯實操作系統基礎。一、線程的基本概念與引入目的 1.1 什么是線程&#xff1f; 線程是…

深入理解 Python 中的 `__call__` 方法

化身為可調用的對象&#xff1a;深入理解 Python 中的 __call__ 方法 引言&#xff1a;函數與對象的邊界模糊化 在 Python 中&#xff0c;我們最熟悉的概念莫過于函數&#xff08;Function&#xff09; 和對象&#xff08;Object&#xff09;。函數是可調用的&#xff08;calla…

云服務器使用代理穩定與github通信方法

使用SSH反向隧道 (SSH Reverse Tunneling) 利用SSH連接在您的本地電腦和云服務器之間建立一個反向的加密通道。 原理&#xff1a; 從本地電腦發起一個SSH命令到您的云服務器&#xff0c;這個命令會告訴云服務器&#xff1a;“請監聽您自己的某個端口&#xff08;例如&#xff1…

7.k8s四層代理service

Service的基本介紹 Cluster IP&#xff1a;每個 Service 都分配了一個Cluster IP&#xff0c;它是一個虛擬的內部IP地址&#xff0c;用于在集群內部進行訪問。這個虛擬IP是由Kubernetes自動分配的&#xff0c;并且與Service對象一一對應。 端口映射&#xff1a;Service可以映射…

Qt 工程中 UI 文件在 Makefile 中的處理

Qt 工程中 UI 文件在 Makefile 中的處理 在 Qt 工程中&#xff0c;.ui 文件&#xff08;Qt Designer 界面文件&#xff09;需要通過 uic&#xff08;用戶界面編譯器&#xff09;工具轉換為對應的頭文件。以下是幾種情況下如何處理 UI 文件&#xff1a;1. 使用 qmake 自動生成 M…

ZLMediaKit性能測試

一、環境 系統&#xff1a;虛擬機 Ubuntu22.04 64bit配置: 4核8G設置&#xff1a;ulimit -n 102400 二、安裝 依賴安裝sudo apt update sudo apt install ffmpeg sudo apt install nloadzlm服務安裝參考&#xff1a;https://blog.csdn.net/hanbo622/article/details/149064939?…

智能文檔處理業務,應該選擇大模型還是OCR專用小模型?

智能文檔處理業務中&#xff0c;最佳策略不是二選一&#xff0c;而是“大小模型協同”。用專用小模型處理高頻、標準化的核心文檔流&#xff0c;實現極致效率與成本控制&#xff1b;用大模型賦能非標、長尾文檔的靈活處理&#xff0c;加速業務創新。 OCR小模型會被大模型取代嗎…

android 如何判定底部導航欄顯示時 不是鍵盤顯示

在 Android 中判定底部導航欄是否顯示時&#xff0c;核心痛點是 區分 “導航欄的底部 Insets” 和 “軟鍵盤彈出的底部 Insets”—— 兩者都會導致 getSystemWindowInsetBottom() 返回非零值&#xff0c;直接判斷會誤將鍵盤彈出當成導航欄顯示。以下是基于 WindowInsets 類型區…

你知道服務器和電腦主機的區別嗎?

我們都知道服務器和臺式主機有著不同之處&#xff0c;但具體說出個一二三來很多人還是一頭霧水&#xff0c;也就是知其然不知其所以然&#xff0c;都是CPU主板 內存 硬盤 電源&#xff0c;撐死就差一個顯卡不同&#xff0c;但其實服務器和我們正常使用的臺式主機差距很大&#…

什么是包裝類

什么是包裝類 在Java中&#xff0c;包裝類&#xff08;Wrapper Class&#xff09;是為基本數據類型提供的對應的引用類型。Java中的基本數據類型&#xff08;如int、char、boolean等&#xff09;不是對象&#xff0c;為了在需要對象的場景中使用基本數據類型&#xff08;如集合…