深入理解C語言快速排序與自省排序(Introsort)

排序算法是計算機科學中最基礎也是最重要的知識之一。快速排序(Quicksort)因其平均時間復雜度為?O(n log n)?而廣受歡迎,但在最壞情況下會退化到?O(n2)。為了克服這一缺點,自省排序(Introsort)?應運而生,它結合了快速排序、堆排序和插入排序的優點,成為C++標準庫(std::sort)的默認實現。

本文將詳細介紹:

  1. 快速排序的原理與優化

  2. 自省排序的設計思想

  3. C語言實現自省排序

  4. 性能分析與對比


1. 快速排序(Quicksort)回顧

快速排序由Tony Hoare于1959年提出,采用?分治法(Divide and Conquer)

  1. 選擇基準值(Pivot):通常取第一個、最后一個或隨機元素。

  2. 分區(Partition):將數組分為兩部分,左邊 ≤ pivot,右邊 ≥ pivot。

  3. 遞歸排序:對左右子數組重復上述過程。

C語言實現(經典快速排序)

c

void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}int partition(int arr[], int low, int high) {int pivot = arr[high]; // 選擇最后一個元素作為基準int i = low - 1;       // i 指向小于pivot的區域的末尾for (int j = low; j < high; j++) {if (arr[j] <= pivot) {i++;swap(&arr[i], &arr[j]);}}swap(&arr[i + 1], &arr[high]); // 將pivot放到正確位置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);}
}

快速排序的缺點

  • 最壞情況(如數組已有序或逆序):遞歸深度?O(n),時間復雜度?O(n2)

  • 對小數組效率低:遞歸調用開銷大。


2. 自省排序(Introsort)

自省排序由David Musser于1997年提出,結合了:

  1. 快速排序(主算法,高效分區)

  2. 堆排序(防止最壞情況)

  3. 插入排序(優化小數組)

核心思想

  1. 遞歸深度限制

    • 如果遞歸深度超過?2 log?n,切換到堆排序(保證最壞情況?O(n log n))。

  2. 小數組優化

    • 當子數組大小 ≤?16(經驗值),改用插入排序(減少遞歸開銷)。

  3. 三數取中法(Median-of-Three)

    • 優化基準值選擇,減少最壞情況概率。


3. C語言實現自省排序

c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>// 交換兩個元素
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 插入排序(用于小數組優化)
void insertionSort(int arr[], int low, int high) {for (int i = low + 1; i <= high; i++) {int key = arr[i];int j = i - 1;while (j >= low && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;}
}// 堆排序(用于防止快速排序退化)
void heapify(int arr[], int n, int i) {int largest = i;int left = 2 * i + 1;int right = 2 * i + 2;if (left < n && arr[left] > arr[largest])largest = left;if (right < n && arr[right] > arr[largest])largest = right;if (largest != i) {swap(&arr[i], &arr[largest]);heapify(arr, n, largest);}
}void heapSort(int arr[], int low, int high) {int n = high - low + 1;for (int i = n / 2 - 1; i >= 0; i--)heapify(arr, n, i);for (int i = n - 1; i > 0; i--) {swap(&arr[0], &arr[i]);heapify(arr, i, 0);}
}// 三數取中法選擇基準值
int medianOfThree(int arr[], int low, int high) {int mid = low + (high - low) / 2;if (arr[low] > arr[mid])swap(&arr[low], &arr[mid]);if (arr[low] > arr[high])swap(&arr[low], &arr[high]);if (arr[mid] > arr[high])swap(&arr[mid], &arr[high]);return mid; // 返回中間值的索引
}// 自省排序核心
void introSortUtil(int arr[], int low, int high, int depthLimit) {int size = high - low + 1;// 小數組優化:改用插入排序if (size <= 16) {insertionSort(arr, low, high);return;}// 遞歸深度超限:改用堆排序if (depthLimit == 0) {heapSort(arr, low, high);return;}// 三數取中法選擇基準值int pivotIdx = medianOfThree(arr, low, high);swap(&arr[pivotIdx], &arr[high]);// 快速排序分區int pi = partition(arr, low, high);// 遞歸排序左右子數組introSortUtil(arr, low, pi - 1, depthLimit - 1);introSortUtil(arr, pi + 1, high, depthLimit - 1);
}// 自省排序入口
void introSort(int arr[], int n) {int depthLimit = 2 * log2(n); // 計算最大遞歸深度introSortUtil(arr, 0, n - 1, depthLimit);
}

4. 性能對比

算法最佳平均最壞適用場景
快速排序O(n log n)O(n log n)O(n2)通用排序
堆排序O(n log n)O(n log n)O(n log n)最壞情況保證
插入排序O(n)O(n2)O(n2)小數組優化
自省排序O(n log n)O(n log n)O(n log n)綜合最優

5. 總結

  • 自省排序 = 快速排序 + 堆排序 + 插入排序,綜合了三種算法的優勢。

  • 防止快速排序退化:遞歸深度超限時切換堆排序。

  • 優化小數組:改用插入排序減少遞歸開銷。

  • C++ STL的std::sort就是基于自省排序,適用于絕大多數場景。

適用場景

  • 大規模數據排序(如數據庫、科學計算)。

  • 需要穩定高效排序(避免最壞情況)。

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

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

相關文章

C#編程基礎:運算符與結構詳解

目錄 一.關系運算符 常見關系運算符 二.邏輯運算符 常見邏輯運算符 1. 邏輯與&#xff08;&& 或 and&#xff09; 2. 邏輯或&#xff08;|| 或 or&#xff09; 3. 邏輯非&#xff08;! 或 not&#xff09; 運算符優先級 三.if語句 1.c#程序的三大結構 1.順序…

嵌入式學習-土堆目標檢測(3)-day27

再學一個labelme在labelstudio環境中再pip install labelme安裝好后直接輸入 labelme之后點擊保存&#xff0c;選擇保存文件地址還有一個就是將labelme的格式轉化為yolo格式還是在labelstudio這個環境里面安裝pip install labelme2yolo

Qt OpenGL 集成:開發 3D 圖形應用

Qt 提供了完善的 OpenGL 集成方案&#xff0c;使開發者能夠在 Qt 應用中高效開發 3D 圖形應用。通過 Qt 的 OpenGL 模塊&#xff0c;可簡化 OpenGL 上下文管理、窗口渲染和跨平臺適配&#xff0c;同時結合現代 OpenGL 特性&#xff08;如著色器、頂點緩沖、紋理等&#xff09;實…

【NLP輿情分析】基于python微博輿情分析可視化系統(flask+pandas+echarts) 視頻教程 - 熱詞評論查詢功能實現

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;最近寫了一套【NLP輿情分析】基于python微博輿情分析可視化系統(flaskpandasecharts)視頻教程&#xff0c;持續更新中&#xff0c;計劃月底更新完&#xff0c;感謝支持。今天講解熱詞評論查詢功能實現 視頻在線地址&#…

使用 Google Earth 的 DEM — 教程。

數字高程模型 (DEM)描繪了已知高程點之間的表面高程。本教程將向您展示如何使用 Google Earth 的高程數據生成 DEM。在當今世界&#xff0c;DEM 主要用于 GIS 應用。 當然&#xff0c;我們可以從美國地質調查局 (USGS) 網站下載數字高程模型 (DEM)。但如果我們想知道某個地點的…

在 UniApp 中實現中間凸起 TabBar 的完整指南

如何在 UniApp 中設置中間 TabBar 凸起效果 在移動應用開發中&#xff0c;TabBar 是常見的導航組件&#xff0c;而中間凸起的 TabBar 按鈕則是一種流行的設計風格&#xff0c;常用于突出重要功能&#xff08;如發布、拍照等&#xff09;。UniApp 提供了 midButton 屬性&#xf…

微觀低代碼

今日去深圳的一家工廠給客戶做培訓&#xff0c;主要培訓內容為低代碼產品的二開和功能演示。客戶使用了20年的ERP和OA系統&#xff0c;目前想對接到低代碼平臺。客戶目前想實現的主要功能是&#xff0c;對接OA的單點登錄&#xff0c;把ERP的功能遷移到低代碼平臺上來工廠規模比…

Linux進程控制:掌握系統的核心脈絡

Linux進程控制&#xff1a;掌握系統的核心脈絡 在 Linux 系統中&#xff0c;進程控制是系統運行的核心機制之一。無論是日常的命令行操作&#xff0c;還是復雜的后臺服務運行&#xff0c;都離不開對進程的管理和控制。本文將深入探討 Linux 進程控制的相關知識&#xff0c;幫助…

4N90-ASEMI電機控制專用4N90

編輯&#xff1a;LL4N90-ASEMI電機控制專用4N90型號&#xff1a;4N90品牌&#xff1a;ASEMI封裝&#xff1a;ITO-220ABRDS(on):3.60Ω批號&#xff1a;最新引腳數量&#xff1a;3封裝尺寸&#xff1a;如圖特性&#xff1a;N溝道MOS管工作結溫&#xff1a;-55℃~150℃一、卓越性…

Java 筆記 lambda

?Lambda 基本語法 (parameters) -> expression 或 (parameters) -> { statements }// 無參數 Runnable r () -> System.out.println("Hello");// 單個參數&#xff08;小括號可省略&#xff09; Consumer<String> c s -> System.out.println(s…

安全風險監測平臺:被動應對向主動預防的轉變

一、智能識別預警系統安全風險監測平臺通過部署多維度感知網絡&#xff0c;實現對各類安全隱患的智能識別與實時預警。系統采用深度學習算法&#xff0c;對人員行為、設備狀態、環境參數等進行全天候監測分析&#xff0c;建立動態風險評估模型。當檢測到異常情況時&#xff0c;…

圖片查重從設計到實現(2)Milvus安裝準備etcd介紹、應用場景及Docker安裝配置

etcd作用、應用場景及Docker安裝配置 在分布式向量數據庫 Milvus 的架構中&#xff0c;etcd 扮演著至關重要的角色。Milvus 用于存儲和管理海量向量數據&#xff0c;支持高效的相似性搜索等操作&#xff0c;而其分布式集群的正常運行高度依賴元數據的一致性和可靠性&#xff0c…

零彈窗干擾的貪吃蛇游戲,下載即玩

軟件介紹 在尋找貪吃蛇游戲的過程中&#xff0c;我發現了一款PC端版本&#xff0c;無需登錄即可直接使用&#xff0c;完全符合我的需求。 使用優勢 這款軟件最大的亮點在于完全免費&#xff0c;沒有任何廣告和彈窗干擾&#xff0c;支持完全離線運行&#xff0c;讓用戶能夠專注…

excel2013VBA開發access mdb數據庫系統的一點經驗分享

最近&#xff0c;自己從網盤里重新下載了過去保存的vba開發資料&#xff0c;就順手研究起了如何能通過excel203結合access 2013 mdb數據庫系統開發個VBA小系統。過簡單一說說了&#xff01;接說干貨經驗分享吧&#xff0c;1、俺先在mdb數據庫中建了一個有自動編號字段的數據表&…

我們能否承擔微服務帶來的復雜性和運維成本?

坦率地說&#xff0c;并非所有團隊都應該&#xff0c;承擔微服務帶來的復雜性和運維成本。在做出決定前&#xff0c;我們必須進行自我評估。 以下是評估是否能承擔微服務成本需要考慮的關鍵方面&#xff1a; 一、 復雜性帶來的挑戰 (Complexity Challenges):分布式系統固有復雜…

HCIP--MGRE實驗

一、實驗拓撲二、配置思路1、建立拓撲&#xff0c;配置IP&#xff0c;配置缺省路由是公網通暢2、路由器R1-R5,R2-R5,R3-R5之間都是串線鏈接&#xff0c;由于華為路由器默認的串線協議為PPP&#xff0c;因此根據實驗要求&#xff0c;R1-R5,R2-R5之間直接進行單向認證&#xff0c…

數字孿生映射探索驅動的具身導航!MorphoNavi:面向對象映射的空地機器人導航

作者&#xff1a; Sausar Karaf, Mikhail Martynov, Oleg Sautenkov, Zhanibek Darush, Dzmitry Tsetserukou單位&#xff1a;俄羅斯斯科爾科沃科學技術研究院智能空間機器人實驗室論文標題&#xff1a;MorphoNavi: Aerial-Ground Robot Navigation with Object Oriented Mappi…

統計與大數據分析與數學金融課程解析

CDA數據分析師證書含金量高&#xff0c;適應了未來數字化經濟和AI發展趨勢&#xff0c;難度不高&#xff0c;行業認可度高&#xff0c;對于找工作很有幫助。一、課程體系對比矩陣維度統計與大數據分析數學金融交叉領域數學基礎概率論(90%)隨機過程(85%)線性代數(100%)核心工具P…

整蠱小程序:關機程序(C語言)

整蠱小程序&#xff1a;關機程序&#xff08;C語言) 跟著潼心走&#xff0c;輕松拿捏C語言&#xff0c;困惑通通走&#xff0c;一去不回頭~歡迎開始今天的學習內容&#xff0c;你的支持就是博主最大的動力。 目錄 整蠱小程序&#xff1a;關機程序&#xff08;C語言) 程序內容…

PHP框架之Laravel框架教程:1. laravel搭建

1. laravel搭建 本教程適合有php基礎的同學學習 安裝方式一&#xff1a; 使用 Laravel 安裝器&#xff1a; 需要本地先安裝PHP 和 Composer&#xff0c;這個自行安裝下。 安裝完成后驗證方式&#xff1a; // 終端輸入&#xff0c;就可以看到結果 php --version composer --vers…