C語言實現的常見排序算法

排序是計算機科學中非常重要的基礎算法之一。無論是在數據分析、數據庫查詢還是圖形界面中,我們都可能會遇到排序問題。本文將介紹幾種常見的排序算法,并提供其C語言實現代碼。排序算法的效率和應用場景有很大關系,不同的算法有不同的時間復雜度和空間復雜度。

1. 冒泡排序(Bubble Sort)

冒泡排序是最簡單的排序算法之一。它通過重復交換相鄰的元素,將最大或最小的元素逐漸“冒泡”到序列的一端。雖然實現簡單,但其時間復雜度較高,通常不適用于大規模數據的排序。

實現邏輯

冒泡排序的核心思想是通過不斷交換相鄰的元素,將較大的元素逐步“冒泡”到數組的一端。每一輪排序,都會將一個最大(或最小)元素放到正確的位置。具體步驟如下:

  1. 從數組的第一個元素開始,依次比較相鄰的元素。如果前一個元素比后一個元素大,就交換它們的位置。
  2. 這樣,經過第一輪比較后,最大的元素被移動到數組的最后一個位置。
  3. 在下一輪比較時,忽略已經排序好的部分(即已排好序的元素),只比較剩余部分,依此類推。
  4. 當某一輪排序中沒有發生任何交換時,說明數組已經有序,可以提前結束排序。
1.1 冒泡排序的C語言實現
#include <stdio.h>// 冒泡排序函數
void bubbleSort(int arr[], int n) {int i, j, temp;// 外層循環控制比較的輪次for (i = 0; i < n-1; i++) {// 內層循環進行相鄰元素的比較與交換for (j = 0; j < n-i-1; j++) {// 如果當前元素大于下一個元素,則交換它們if (arr[j] > arr[j+1]) {temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}
}// 打印數組的函數
void printArray(int arr[], int size) {int i;for (i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {64, 34, 25, 12, 22, 11, 90};int n = sizeof(arr)/sizeof(arr[0]); // 獲取數組長度printf("原始數組: \n");printArray(arr, n);bubbleSort(arr, n); // 調用冒泡排序printf("排序后的數組: \n");printArray(arr, n); // 打印排序后的數組return 0;
}
1.2 時間復雜度:
  • 最壞時間復雜度:O(n^2)
  • 最好時間復雜度:O(n)(當數組已經有序時)

2. 選擇排序(Selection Sort)

實現邏輯

選擇排序的核心思想是每一次從未排序部分中選擇一個最小(或最大)元素,并將其放到已排序部分的末尾。具體步驟如下:

  1. 從數組的第一個元素開始,假設它是最小的元素,遍歷剩余部分,找到真正的最小元素。
  2. 將最小元素與當前元素交換位置。
  3. 繼續從下一個元素開始,重復上述操作,直到整個數組有序。

與冒泡排序不同,選擇排序每次只進行一次交換,即使找到最小值,也不會像冒泡排序那樣進行多次交換。

2.1 選擇排序的C語言實現
#include <stdio.h>// 選擇排序函數
void selectionSort(int arr[], int n) {int i, j, minIndex, temp;// 外層循環每次選擇一個最小值for (i = 0; i < n-1; i++) {minIndex = i; // 假設當前元素是最小的// 內層循環找出未排序部分中的最小元素for (j = i+1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j; // 更新最小值的索引}}// 交換當前元素和最小元素temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}
}// 打印數組的函數
void printArray(int arr[], int size) {int i;for (i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr)/sizeof(arr[0]); // 獲取數組長度printf("原始數組: \n");printArray(arr, n);selectionSort(arr, n); // 調用選擇排序printf("排序后的數組: \n");printArray(arr, n); // 打印排序后的數組return 0;
}
2.2 時間復雜度:
  • 最壞時間復雜度:O(n^2)
  • 最好時間復雜度:O(n^2)

3. 插入排序(Insertion Sort)

插入排序將數組分為已排序部分和未排序部分,每次取未排序部分的第一個元素,將其插入到已排序部分的合適位置,直到整個數組有序。

實現邏輯

插入排序的核心思想是將數組分為已排序和未排序兩部分,依次將未排序部分的元素插入到已排序部分的合適位置。具體步驟如下:

  1. 從第二個元素開始,將其與前面的元素進行比較,找到它應該插入的位置。
  2. 將插入位置之后的元素依次右移,直到找到合適的位置。
  3. 將當前元素插入到合適位置。
  4. 重復上述操作,直到數組全部有序。
3.1 插入排序的C語言實現
#include <stdio.h>// 插入排序函數
void insertionSort(int arr[], int n) {int i, key, j;// 從第二個元素開始,每次將一個元素插入到已排序部分for (i = 1; i < n; i++) {key = arr[i]; // 保存當前要插入的元素j = i - 1;// 將已排序部分大于 key 的元素向右移動while (j >= 0 && arr[j] > key) {arr[j+1] = arr[j];j = j - 1;}// 將 key 插入到正確的位置arr[j+1] = key;}
}// 打印數組的函數
void printArray(int arr[], int size) {int i;for (i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {12, 11, 13, 5, 6};int n = sizeof(arr)/sizeof(arr[0]); // 獲取數組長度printf("原始數組: \n");printArray(arr, n);insertionSort(arr, n); // 調用插入排序printf("排序后的數組: \n");printArray(arr, n); // 打印排序后的數組return 0;
}
3.2 時間復雜度:
  • 最壞時間復雜度:O(n^2)
  • 最好時間復雜度:O(n)(當數組已經有序時)

4. 快速排序(Quick Sort)

快速排序是一種分治法排序算法,它通過一個基準元素將數組分為兩個子數組,然后遞歸地排序這兩個子數組。由于其平均時間復雜度較低,快速排序在實際應用中非常高效。

實現邏輯

快速排序是一種分治算法,其核心思想是通過一個基準元素將數組分為兩部分:一部分比基準元素小,另一部分比基準元素大。然后遞歸地對這兩部分進行排序,直到整個數組有序。具體步驟如下:

  1. 選擇一個基準元素(通常選擇數組的第一個元素、最后一個元素或隨機選擇一個元素)。
  2. 將數組重新排列,使得所有比基準元素小的元素都在基準元素的左邊,所有比基準元素大的元素都在右邊。
  3. 基準元素就位后,將左子數組和右子數組遞歸地進行快速排序。
  4. 遞歸的終止條件是子數組的大小為1或0。

快速排序通過分治策略來將大問題分解為小問題,因此具有較高的效率。

4.1 快速排序的C語言實現
#include <stdio.h>// 分區操作:將數組分為兩個子數組
int partition(int arr[], int low, int high) {int pivot = arr[high]; // 選擇最右側元素作為基準int i = low - 1; // i 是已排序部分的邊界// 遍歷數組,將小于基準的元素放到左邊,大于基準的放到右邊for (int j = low; j < high; j++) {if (arr[j] < pivot) {i++; // 更新已排序部分的邊界// 交換 arr[i] 和 arr[j]int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}// 將基準元素放到正確位置int temp = arr[i+1];arr[i+1] = arr[high];arr[high] = temp;return i + 1; // 返回基準元素的索引
}// 快速排序函數
void quickSort(int arr[], int low, int high) {if (low < high) {// 獲取分區后的基準元素索引int pi = partition(arr, low, high);// 分別對左子數組和右子數組進行快速排序quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}
}// 打印數組的函數
void printArray(int arr[], int size) {int i;for (i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {10, 7, 8, 9, 1, 5};int n = sizeof(arr)/sizeof(arr[0]); // 獲取數組長度printf("原始數組: \n");printArray(arr, n);quickSort(arr, 0, n-1); // 調用快速排序printf("排序后的數組: \n");printArray(arr, n); // 打印排序后的數組return 0;
}
4.2 時間復雜度:
  • 最壞時間復雜度:O(n^2)
  • 最好時間復雜度:O(n log n)
  • 平均時間復雜度:O(n log n)

5. 歸并排序(Merge Sort)

歸并排序也是一種分治法排序算法,它將數組分為兩個子數組,分別對它們排序后再合并。歸并排序是一個穩定的排序算法,適用于大規模數據。

實現邏輯

歸并排序也是一種分治算法,核心思想是將數組分成兩個子數組,分別對其進行排序,然后將兩個已排序的子數組合并成一個大的有序數組。具體步驟如下:

  1. 將數組遞歸地分割成兩半,直到每個子數組只包含一個元素。
  2. 然后將這些小的有序子數組逐步合并成更大的有序子數組。
  3. 在合并時,始終保持兩個子數組之間的有序性。

歸并排序的關鍵操作是合并兩個已排序的子數組,合并過程是線性時間復雜度。

5.1 歸并排序的C語言實現
#include <stdio.h>// 合并兩個已排序的子數組
void merge(int arr[], int l, int m, int r) {int n1 = m - l + 1; // 左子數組的大小int n2 = r - m;     // 右子數組的大小// 創建臨時數組int L[n1], R[n2];// 將數據拷貝到臨時數組for (int i = 0; i < n1; i++)L[i] = arr[l + i];for (int j = 0; j < n2; j++)R[j] = arr[m + 1 + j];int i = 0, j = 0, k = l;// 合并兩個臨時數組while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i];i++;} else {arr[k] = R[j];j++;}k++;}// 將剩余的元素拷貝到原數組while (i < n1) {arr[k] = L[i];i++;k++;}while (j < n2) {arr[k] = R[j];j++;k++;}
}// 歸并排序函數
void mergeSort(int arr[], int l, int r) {if (l < r) {int m = l + (r - l) / 2; // 計算中間位置mergeSort(arr, l, m); // 對左半部分進行歸并排序mergeSort(arr, m + 1, r); // 對右半部分進行歸并排序merge(arr, l, m, r); // 合并兩個已排序的子數組}
}// 打印數組的函數
void printArray(int arr[], int size) {int i;for (i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {12, 11, 13, 5, 6, 7};int n = sizeof(arr)/sizeof(arr[0]); // 獲取數組長度printf("原始數組: \n");printArray(arr, n);mergeSort(arr, 0, n-1); // 調用歸并排序printf("排序后的數組: \n");printArray(arr, n); // 打印排序后的數組return 0;
}
5.2 時間復雜度:
  • 最壞時間復雜度:O(n log n)
  • 最好時間復雜度:O(n log n)
  • 平均時間復雜度:O(n log n)

總結

本文介紹了幾種經典的排序算法,包括冒泡排序、選擇排序、插入排序、快速排序和歸并排序。每種排序算法都有其特定的優缺點,適用于不同的應用場景。在選擇排序算法時,需要根據數據的規模、要求的時間復雜度以及是否需要穩定排序來做出決策。通過理解這些排序算法的實現和性能特點,您可以在實際開發中更加高效地選擇合適的排序算法。

版權聲明:本文為原創文章,轉載請注明出處。

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

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

相關文章

對于簡單的HTML、CSS、JavaScript前端,我們可以通過幾種方式連接后端

1. 使用Fetch API發送HTTP請求&#xff08;最簡單的方式&#xff09;&#xff1a; //home.html // 示例&#xff1a;提交表單數據到后端 const submitForm async (formData) > {try {const response await fetch(http://your-backend-url/api/submit, {method: POST,head…

[論文閱讀] SeeSR: Towards Semantics-Aware Real-World Image Super-Resolution

文章目錄 一、前言二、主要貢獻三、Introduction四、Methodology4.1 Motivation &#xff1a;4.2Framework Overview.** 一、前言 通信作者是香港理工大學 & OPPO研究所的張磊教授&#xff0c;也是圖像超分ISR的一個大牛了。 論文如下 SeeSR: Towards Semantics-Aware Rea…

案例-04.部門管理-刪除

一.功能演示 二.需求說明 三.接口文檔 四.思路 既然是通過id刪除對應的部門&#xff0c;那么必然要獲取到前端請求的要刪除部門的id。id作為請求路徑傳遞過來&#xff0c;那么要從請求路徑中獲取&#xff0c;id是一個路徑參數。因此使用注解PathVariable獲取路徑參數。 請求方…

Blazor-父子組件傳遞任意參數

在我們從父組件傳參數給子組件時&#xff0c;可以通過子組件定義的[Parameter]特性的公開屬性進行傳值&#xff0c;但是當我們需要傳遞多個值的時候&#xff0c;就需要通過[Parameter]特性定義多個屬性&#xff0c;有沒有更簡便的方式&#xff1f; 我們可以使用定義 IDictionar…

DeepSeek 的創新融合:多行業應用實踐探索

引言 在數字化轉型的浪潮中&#xff0c;技術的融合與創新成為推動各行業發展的關鍵力量。藍耘平臺作為行業內備受矚目的創新平臺&#xff0c;以其強大的資源整合能力和靈活的架構&#xff0c;為企業提供了高效的服務支持。而 DeepSeek 憑借先進的人工智能技術&#xff0c;在自然…

STM32創建靜態庫lib

創建靜態庫lib 1. 新建工程1.1 創建工程文件夾1.2 編寫用戶相關代碼1.2.1 stm32f4xx_it.h1.2.2 stm32f4xx_it.c1.2.3 標準庫配置&#xff1a;stm32f4xx_conf.h1.2.4 HAL庫的配置&#xff1a;stm32f4xx_hal_conf.h1.2.5 LL庫配置&#xff1a;stm32f4xx_ll_conf.h 1.3 移植通用文…

elabradio入門第二講——BPSK數字調制與解調(插值、升余弦濾波、速率匹配、符號同步)

數字信號可以通過數字基帶傳輸系統進行傳輸&#xff0c;而基帶傳輸系統僅僅適用于低頻信道下的數字信號傳輸。然而&#xff0c;在實際的通信系統中信道通常具有帶通特性&#xff0c;因而需要將基帶信號搬移到適合信道傳輸的高頻載波上&#xff0c;使得信號與信道相匹配&#xf…

汽車 OTA 升級:提升下載與升級速度,優化用戶體驗

摘要&#xff1a; 隨著汽車智能化的飛速發展&#xff0c;OTA&#xff08;Over - the - Air&#xff09;升級已成為汽車行業的重要技術&#xff0c;它能為車輛持續帶來功能更新與性能優化。然而&#xff0c;下載及升級速度較慢的問題常常影響用戶體驗。本文深入探討在汽車 OTA …

【Spring+MyBatis】留言墻的實現

目錄 1. 添加依賴 2. 配置數據庫 2.1 創建數據庫與數據表 2.2 創建與數據庫對應的實體類 3. 后端代碼 3.1 目錄結構 3.2 MessageController類 3.3 MessageService類 3.4 MessageMapper接口 4. 前端代碼 5. 單元測試 5.1 后端接口測試 5.2 使用前端頁面測試 在Spri…

SQLite Select 語句詳解

SQLite Select 語句詳解 SQLite 是一個輕量級的數據庫管理系統&#xff0c;以其簡潔的設計和高效的性能被廣泛應用于各種場景。在 SQLite 中&#xff0c;SELECT 語句是用于查詢數據庫中的數據的命令。本文將詳細介紹 SQLite 的 SELECT 語句&#xff0c;包括其基本語法、常用功…

深度學習05 ResNet殘差網絡

目錄 傳統卷積神經網絡存在的問題 如何解決 批量歸一化BatchNormalization, BN 殘差連接方式 ?殘差結構 ResNet網絡 ResNet 網絡是在 2015年 由微軟實驗室中的何凱明等幾位大神提出&#xff0c;斬獲當年ImageNet競賽中分類任務第一名&#xff0c;目標檢測第一名。獲得CO…

組件庫地址

react&#xff1a; https://react-vant.3lang.dev/components/dialoghttps://react-vant.3lang.dev/components/dialog vue用v2的 Vant 2 - Mobile UI Components built on Vue

docker 進階命令(基于Ubuntu)

數據卷 Volume: 目錄映射, 目錄掛載 匿名綁定: 匿名綁定的 volume 在容器刪除的時候, 數據卷也會被刪除, 匿名綁定是不能做到持久化的, 地址一般是 /var/lib/docker/volumes/xxxxx/_data 綁定卷時修改宿主機的目錄或文件, 容器內的數據也會同步修改, 反之亦然 # 查看所有 vo…

從入門到精通:Postman 實用指南

Postman 是一款超棒的 API 開發工具&#xff0c;能用來測試、調試和管理 API&#xff0c;大大提升開發效率。下面就給大家詳細講講它的安裝、使用方法&#xff0c;再分享些實用技巧。 一、安裝 Postman 你能在 Postman 官網&#xff08;https://www.postman.com &#xff09;下…

將圖片base64編碼后,數據轉成圖片

將圖片數據進行base64編碼后&#xff0c;可以在瀏覽器上查看圖片&#xff0c;只需在前端加上data:image/png;base64,即可 在線工具&#xff1a; Base64轉圖片 - 加菲工具

【動態規劃】詳解 0-1背包問題

文章目錄 1. 問題引入2. 從 dfs 到動態規劃3. 動態規劃過程分析4. 二維 dp 的遍歷順序5. 從二維數組到一維數組6. 一維數組的遍歷次序7. 背包的遍歷順序8. 代碼總結9. 總結 1. 問題引入 0-1 背包是比較經典的動態規劃問題&#xff0c;這里以代碼隨想錄里面的例子來介紹下。總的…

LeetCode每日精進:20.有效的括號

題目鏈接&#xff1a;20.有效的括號 題目描述&#xff1a; 給定一個只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判斷字符串是否有效。 有效字符串需滿足&#xff1a; 左括號必須用相同類型的右括號閉合。左括號必須以…

llama.cpp部署 DeepSeek-R1 模型

一、llama.cpp 介紹 使用純 C/C推理 Meta 的LLaMA模型&#xff08;及其他模型&#xff09;。主要目標llama.cpp是在各種硬件&#xff08;本地和云端&#xff09;上以最少的設置和最先進的性能實現 LLM 推理。純 C/C 實現&#xff0c;無任何依賴項Apple 芯片是一流的——通過 A…

Web后端 - Maven管理工具

一 Maven簡單介紹 Maven是apache旗下的一個開源項目&#xff0c;是一款用于管理和構建java項目的工具。 Maven的作用 二 Maven 安裝配置 依賴配置 依賴傳遞 依賴范圍 生命周期 注意事項&#xff1a;在同一套生命周期中&#xff0c;當運行后面的階段時&#xff0c;前面的階段都…

[LeetCode力扣hot100]-C++常用數據結構

0.Vector 1.Set-常用滑動窗口 set<char> ans;//根據類型定義&#xff0c;像vector ans.count()//檢查某個元素是否在set里&#xff0c;1在0不在 ans.insert();//插入元素 ans.erase()//刪除某個指定元素 2.棧 3.樹 樹是一種特殊的數據結構&#xff0c;力扣二叉樹相…