數據結構:選擇排序 (Selection Sort)

目錄

從學生排隊開始

算法的初始狀態和核心操作

代碼的逐步完善

第一階段:定義函數框架和外層循環

第二階段:實現“尋找最小元素”的邏輯(內層循環)

第三階段:完成“交換”操作

復雜度與特性分析

時間復雜度 (Time Complexity)

空間復雜度 (Space Complexity)

穩定性 (Stability)


從學生排隊開始

我們已經探討了兩種排序思路:

  1. 冒泡排序:不斷比較相鄰的元素,像“本地微調”,慢慢把大的元素換到后面。

  2. 插入排序:始終維護一個有序的局部,然后把新元素插入進去。

現在我們思考一種完全不同的、更具“全局觀”的策略。想象一下,老師讓一隊學生按身高從矮到高排隊。老師會怎么做?

一種非常直接的方法是:

  1. 老師先掃視所有未排隊的學生,從中找出最矮的那一個。

  2. 然后指著隊伍的最前面說:“你,站到這里來。”

  3. 接著,老師在剩下的學生中,再掃視一遍,找出剩下人里最矮的。

  4. 然后指著隊伍的第二個位置說:“你,站到這里來。”

  5. 重復這個過程,直到所有學生都排好隊。

這個“每次選擇一個最值,放到它最終應該在的位置”的思路,就是選擇排序的靈魂。


算法的初始狀態和核心操作

和插入排序一樣,我們也將數組在邏輯上分為兩個部分:

  1. 左邊是已經排好序、元素都已在最終位置的有序區。

  2. 右邊是還未處理、元素位置都是臨時的無序區。

算法開始時,有序區是空的,整個數組都是無序區。

📌?核心操作(一輪迭代)

  1. 在無序區中,通過一次完整的掃描,找到值最小的那個元素。

  2. 將這個最小的元素與無序區的第一個元素交換位置。

  3. 交換完成后,無序區的第一個元素就變成了有序區的最后一個元素。有序區長度加一,無序區長度減一。

我們來手動模擬一下。假設數組是 arr = [64, 25, 12, 22, 11]

  • 有序區: []

  • 無序區: [64, 25, 12, 22, 11]

1???第一輪 (i=0):

  1. 掃描無序區 [64, 25, 12, 22, 11]

  2. 發現最小的元素是 11,它的索引是 4

  3. 11 與無序區的第一個元素 64 交換。

  • ??結果:[**11**, 25, 12, 22, 64]。現在 11 已經在它的最終位置了。

  • 有序區: [11], 無序區: [25, 12, 22, 64]

2???第二輪 (i=1):

  1. 掃描無序區 [25, 12, 22, 64]

  2. 發現最小的元素是 12,它的索引是 2

  3. 12 與無序區的第一個元素 25 交換。

  • ? 結果:[11, **12**, 25, 22, 64]。現在 12 也歸位了。

  • 有序區: [11, 12], 無序區: [25, 22, 64]

這個過程持續 n-1 輪,當 n-1 個元素都歸位后,剩下的最后一個元素自然也在正確的位置上了。


代碼的逐步完善

現在,我們將這個“選擇-交換”的策略翻譯成代碼。

第一階段:定義函數框架和外層循環

外層循環的職責是控制輪次,也就是每次為哪個位置尋找正確的元素。

i 將代表當前“坑位”的索引,我們要在無序區中找到元素來填這個“坑”。

#include <iostream>void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 選擇排序函數框架
void selectionSort(int arr[], int n) {// 外層循環控制輪次,i 是當前要放置正確元素的目標位置// 我們需要為 arr[0], arr[1], ..., arr[n-2] 依次尋找元素// 當 arr[n-2] 也正確時,arr[n-1] 必然也正確了for (int i = 0; i < n - 1; ++i) {// 在這里,我們將找到無序區 arr[i...n-1] 中的最小元素,// 然后把它放到 arr[i] 這個位置上。}
}

第二階段:實現“尋找最小元素”的邏輯(內層循環)

在每一輪中,我們需要一個內層循環來掃描整個無序區,目的是找到最小元素的索引。

void selectionSort(int arr[], int n) {for (int i = 0; i < n - 1; ++i) {// 1. 先假設當前無序區的第一個元素就是最小的int min_idx = i;// 2. 用內層循環掃描無序區的其他元素for (int j = i + 1; j < n; ++j) {// 如果發現了更小的元素...if (arr[j] < arr[min_idx]) {// ...就更新最小元素的索引min_idx = j;}}// 當這個內層循環結束后,min_idx 就一定指向了// 整個無序區中最小元素的實際位置。// 接下來就是交換操作了。}
}

第三階段:完成“交換”操作

找到了最小元素的索引 min_idx 后,我們只需要將它和當前輪次的目標位置 i 的元素進行一次交換。這個交換操作發生在內層循環結束之后。

void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {std::cout << arr[i] << " ";}std::cout << std::endl;
}// 最終的選擇排序代碼
void selectionSort(int arr[], int n) {for (int i = 0; i < n - 1; ++i) {// 尋找 [i, n-1] 區間里的最小元素int min_idx = i;for (int j = i + 1; j < n; ++j) {if (arr[j] < arr[min_idx]) {min_idx = j;}}// 將找到的最小元素與 i 位置的元素交換swap(&arr[min_idx], &arr[i]);std::cout << "第 " << i + 1 << " 輪排序后: ";printArray(arr, n);}
}

至此,一個從“全局選擇最優”這個第一性原理出發的選擇排序算法就清晰地構建完成了。


復雜度與特性分析

我們用之前建立的評判標準來分析它。

時間復雜度 (Time Complexity)

  • 算法的主要耗時在于嵌套的循環。

    • 外層循環執行 n-1 次。

    • 內層循環的執行次數:

      • i=0 時,比較 n-1 次。

      • i=1 時,比較 n-2 次。

      • ...

      • i=n-2 時,比較 1 次。

  • 總的比較/移動次數大約是 1 + 2 + ... + (n?1) = n * (n?1) / 2。

?? 請注意,無論輸入的數組是已經有序、還是完全逆序,選擇排序的這個比較次數是固定不變的

因為它必須完整地掃描完無序區,才能確認哪個是最小的。它無法像插入排序或優化后的冒泡排序那樣提前結束。

因此,選擇排序的最好、最壞和平均情況的時間復雜度都是:O(n^2)


空間復雜度 (Space Complexity)

  • 在排序過程中,我們只使用了 i, j, min_idx 這幾個輔助變量。

  • 變量數量是固定的常數,不隨 n 的增長而增長。

  • 因此,空間復雜度是:O(1)

  • 它也是一個原地排序 (In-place Sort) 算法。


穩定性 (Stability)

  • 這是選擇排序一個非常重要的特性。我們來舉個例子判斷一下。

  • 假設數組是 [5a, 8, 5b, 2] (這里 5a5b 值相等,但我們為了區分,加上了標記)。

  • 第一輪 (i=0)

    1. 掃描整個數組,發現最小元素是 2

    2. 2 與無序區的第一個元素 arr[0] (也就是 5a) 進行交換。

    3. 交換后,數組變為 [2, 8, 5b, 5a]

  • 觀察結果:在原始數組中,5a5b 的前面。但在第一輪排序后,5a 跑到了 5b 的后面。它們的相對位置發生了改變。

  • 僅僅一個反例就足以證明,選擇排序不是一個穩定的排序算法。

  • 因此,選擇排序是?不穩定排序 (Unstable Sort)


選擇排序的特點非常鮮明:它的時間復雜度很“死板”,不受輸入數據的影響,始終是 O(n^2)。

但它有一個優點,就是數據交換的次數非常少,最多只有 n-1 次。在一些“寫”操作遠比“讀”操作昂貴的場景下,這可能成為一個考慮因素。

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

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

相關文章

Django Admin 管理工具

一、簡介Django Admin 是 Django 框架最受歡迎和強大的特性之一。它是一個自動生成的管理后臺&#xff0c;允許開發者無需或僅需編寫少量代碼&#xff0c;就能對網站的數據模型&#xff08;數據庫中的表&#xff09;進行直觀的增、刪、改、查&#xff08;CRUD&#xff09;操作。…

園區智慧水電管理系統:讓能源管理從“成本黑洞”變“利潤引擎”

園區智慧水電管理系統&#xff0c;是一套專為產業園區、科技園、企業總部等大型空間設計的集智能計量、遠程管控、自動計費、能耗分析于一體的數字化能源解決方案。它用技術手段解決水電管理中的“抄表難、收費亂、浪費多、數據缺”四大頑疾&#xff0c;真正實現降本、提效、控…

DeepSeek應用技巧-通過MCP打造數據分析助手

本文章將通過MCP服務來打造一個數據分析助手&#xff0c;可以直接讀取本地的excel或csv的文件&#xff0c;然后生成可視化的報告并保存在本地&#xff0c;十分有應用和實踐的價值&#xff0c;話不多說&#xff0c;我們開始手把手搭建。一、知識應用&#xff08;1&#xff09;Fu…

React Hooks 完全指南:從基礎到高級的實戰技巧

概述 React Hooks 是 React 16.8 引入的新特性&#xff0c;允許在函數組件中使用狀態和其他 React 特性。根據數據的使用場景和更新機制&#xff0c;可以將 Hooks 分為三大類&#xff1a; 1. 保存只讀數據 useMemo 用途&#xff1a; 緩存計算結果&#xff0c;避免重復計算 …

PCIe 6.0 vs 5.0:帶寬翻倍背后的技術革命

PCIe 6.0 vs 5.0&#xff1a;帶寬翻倍背后的技術革命在數據中心、AI計算和高速存儲需求爆炸式增長的今天&#xff0c;傳統接口帶寬已成為系統性能提升的瓶頸。PCIe 6.0的推出正是為了解決這一挑戰&#xff0c;它通過革命性的技術創新&#xff0c;在保持向后兼容的同時實現了帶寬…

突破傳統企業組網瓶頸:某科技公司智能組網服務項目深度解析

在現代企業的數字化轉型過程中&#xff0c;穩定、高效、安全的網絡基礎設施已成為業務發展的關鍵。然而&#xff0c;傳統組網方案往往面臨諸多挑戰&#xff0c;如網絡性能不足、組網復雜度高、擴展性不佳、以及安全防護薄弱等問題。為了解決這些痛點&#xff0c;某科技公司通過…

ubuntu單機實現10000個連接同時在線測試

連接前 成功連接后 前端測試連接腳本: c_5k.sh !/bin/bash ulimit -n 100000 # client_simulator.sh SERVER_IP="192.168.0.106" SERVER_PORT=8080 MAX_CLIENTS=5000 BATCH_SIZE=100echo "Starting $MAX_CLIENTS clients to $SERVER_IP:$SERVER_PORT"…

防護墻技術(一):NAT

###源NAT基本原理 NAT&#xff08;Network Address Translation&#xff09;網絡地址轉換技術 源NAT技術對IP報文的源地址進行轉換&#xff0c;將私有IP地址轉換為公網IP地址&#xff0c;使大量私網用戶可以利用少量公網IP地址訪問internet&#xff0c;大大減少對公網IP的消耗 …

動態規劃2(c++)

酒鬼#include <bits/stdc.h> using namespace std; int main() {int n;cin>>n;int a[10010];for(int i 1;i<n;i){cin>>a[i];}int dp[1010][5] {0};dp[0][0] 0;dp[1][0] 0;dp[1][1] a[1];dp[1][2] 0;dp[2][0] a[1];dp[2][1] a[2];dp[2][2] a[1]a[…

「LangChain 學習筆記」LangChain大模型應用開發:代理 (Agent)

「LangChain大模型應用開發」 系列文章目錄&#xff1a; LangChain大模型應用開發&#xff1a;模型&#xff0c;提示和輸出解釋器 LangChain大模型應用開發&#xff1a;儲存(Memory) LangChain大模型應用開發&#xff1a;模型鏈&#xff08;Chains&#xff09; LangChain大模…

python pyqt5開發DoIP上位機【介紹】

目錄文章合集一、核心功能概述二、主要模塊解析1. 導入的庫2. 輔助函數3. DOIP協議處理&#xff08;DOIPProtocol類&#xff09;4. 網絡工具&#xff08;NetworkUtils類&#xff09;5. 通信線程&#xff08;DOIPCommunicationThread類&#xff09;6. UDS命令輸入組件&#xff0…

從零實現一個可擴展的規則解析引擎 —— 支持 AND/OR 優先級、短路求值與多類型運算符

在日常業務開發中&#xff0c;我們經常需要基于一些“規則”來決定程序的走向。比如&#xff1a; 客服機器人 根據用戶問題領域和復雜度選擇不同的模型&#xff1b;營銷系統 根據用戶畫像匹配不同優惠券&#xff1b;風控引擎 根據請求參數、時間、分值判定是否放行。 這些規則往…

Preprocessing Model in MPC 3 - 基于同態加密的協議 - Over Rings 環

參考論文&#xff1a;SoK: Multiparty Computation in the Preprocessing Model MPC (Secure Multi-Party Computation) 博士生入門資料。抄襲必究。 本系列教程將逐字解讀參考論文(以下簡稱MPCiPPM)&#xff0c;在此過程中&#xff0c;將論文中涵蓋的40篇參考文獻進行梳理與講…

uni-app 跨平臺項目的 iOS 上架流程:多工具組合的高效協作方案

跨平臺框架的興起&#xff0c;讓許多團隊選擇 uni-app 來開發移動應用。 一套代碼多端運行&#xff0c;確實大大降低了研發成本&#xff0c;但當項目進入 iOS 上架階段 時&#xff0c;很多團隊依舊面臨挑戰&#xff1a;證書復雜、環境不統一、上傳繁瑣。 本文結合實戰經驗&…

掌握 Linux 文件權限:chown 命令深度解析與實踐

在 Linux 系統的日常運維與開發工作里&#xff0c;文件權限管理是保障系統安全、規范文件訪問的關鍵環節。其中&#xff0c;chown 命令作為修改文件所有者及關聯組的核心工具&#xff0c;對精準把控文件權限起著重要作用。接下來&#xff0c;我們將全面拆解 chown 命令&#xf…

計算機算術7-浮點基礎知識

1. 浮點表示其中b表示基底&#xff0c;e表示指數&#xff0c;s表示尾數&#xff0c;注意在s的表示過程中&#xff0c;有個隱藏1.同時還有個符號位從下面這個圖可以看出&#xff0c;向上溢出和向下溢出的概念&#xff0c;overflow表示的是數的絕對值超過了最大的表示范圍&#x…

設計模式8-命令模式

定義 Command Partern: 將一個請求封裝成一個對象&#xff0c;從而讓你使用不同的請求把客戶端參數化&#xff0c;對請求排隊或者記錄請求日志&#xff0c;可以提供命令的撤銷和恢復功能。&#xff08;核心思想是將“動作”與“執行者”解耦&#xff09; 場景 GUI&#xff1a;…

數據結構(順序表力扣刷題)

1.移除元素 給你一個數組 nums 和一個值 val&#xff0c;你需要 原地 移除所有數值等于 val 的元素。元素的順序可能發生改變。然后返回 nums 中與 val 不同的元素的數量。 假設 nums 中不等于 val 的元素數量為 k&#xff0c;要通過此題&#xff0c;您需要執行以下操作&…

機器學習 - Kaggle項目實踐(6)Dogs vs. Cats Redux: Kernels Edition 貓狗二分類

Dogs vs. Cats Redux: Kernels Edition | Kaggle 任務&#xff1a;給定貓狗圖像數據集 進行二分類。 Cats or Dogs - using CNN with Transfer Learning | Kaggle&#xff08;參考&#xff09; Cats or Dogs | Kaggle &#xff08;我的kaggle&#xff09; 本文介紹了使用Re…

基礎的匯編指令

目錄 1、接上一個csdn特殊功能寄存器 1.1CPSR寄存器 1.2SPSR寄存器 1.3CPSR寄存器的高四位和第四位 ?編輯 2、匯編指令的分類 3、匯編指令的基本格式 4、數據搬移指令&#xff08;賦值指令&#xff09; 4.1指令碼 4.2指令格式 4.3測試代碼 4.5立即數 4.6ldr偽指令 …