【排序算法】快速排序詳解--附詳細流程代碼

快速排序算法

介紹

快速排序(Quick Sort)是一種高效的分治排序算法,由英國計算機科學家 Tony Hoare 于 1960 年提出。它是實際應用中最常用的排序算法之一。快速排序的基本思想是:選擇一個"基準"(pivot)元素,通過一次排序將待排序列分割成獨立的兩部分,一部分所有元素均小于基準,另一部分所有元素均大于基準,然后遞歸地對這兩部分分別進行快速排序。分治策略的運用讓快速排序在平均情況下能達到 O(nlogn) 的時間復雜度,大大優于簡單排序算法的 O(n2) 性能。

算法步驟

  1. 從數列中選擇一個元素作為"基準"(pivot),本文采用最左側元素作為基準
  2. 將所有比基準值小的元素放到基準前面,所有比基準值大的元素放到基準后面(分區操作)
  3. 對基準左右兩個子序列分別重復步驟1和2,直到子序列只有一個元素或為空

核心特性

  • 分治策略:將問題分解為更小的子問題,逐步解決
  • 原地排序:只需要 O(logn) 的額外空間復雜度(主要用于遞歸調用的棧空間)
  • 時間復雜度:平均情況為 O(nlogn),最壞情況為 O(n2),最好情況為 O(nlogn)
  • 不穩定性:相等元素的相對位置在排序后可能會改變
  • 高效性:在實際應用中,快速排序通常是最快的排序算法之一

基礎實現

接下來大家一起看下快速排序的部分主流語言實現:

代碼實現

Java實現

public class QuickSort {public static void quickSort(int[] arr, int low, int high) {if (low < high) {int pivotIndex = partition(arr, low, high);quickSort(arr, low, pivotIndex - 1);quickSort(arr, pivotIndex + 1, high);}}private static int partition(int[] arr, int low, int high) {int pivot = arr[low];int i = low + 1;for (int j = low + 1; j <= high; j++) {if (arr[j] < pivot) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;i++;}}int temp = arr[low];arr[low] = arr[i - 1];arr[i - 1] = temp;return i - 1;}public static void printArray(int[] arr) {for (int i : arr) {System.out.print(i + " ");}System.out.println();}public static void main(String[] args) {int[] arr = {10, 7, 8, 9, 1, 5};System.out.println("排序前的數組:");printArray(arr);quickSort(arr, 0, arr.length - 1);System.out.println("排序后的數組:");printArray(arr);}
}

注意,在上述代碼里,通過:

for (int j = low + 1; j <= high; j++) {if (arr[j] < pivot) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;i++;}
}

將小于基準的元素移到左側,然后通過:

int temp = arr[low];
arr[low] = arr[i - 1];
arr[i - 1] = temp;

修正基準的位置,實現基準左側都小于基準、基準右側大于等于基準。

優化策略

隨機選擇基準元素

使用最左側元素作為基準可能會在數組已經排序或接近排序時導致最壞性能,隨機選擇基準可以降低這種風險:

private static int randomPartition(int[] arr, int low, int high) {int randomIndex = low + (int)(Math.random() * (high - low + 1));int temp = arr[randomIndex];arr[randomIndex] = arr[low];arr[low] = temp;return partition(arr, low, high);
}

三數取中法

選擇左端、中間和右端三個元素的中值作為基準,可以進一步優化快速排序:

private static int medianOfThreePartition(int[] arr, int low, int high) {int mid = low + (high - low) / 2;if (arr[mid] < arr[low])swap(arr, mid, low);if (arr[high] < arr[low])swap(arr, high, low);if (arr[high] < arr[mid])swap(arr, high, mid);swap(arr, mid, low);return partition(arr, low, high);
}

優缺點

優點

  • 平均情況下非常高效,時間復雜度為 O(nlogn)
  • 原地排序,空間復雜度低
  • 緩存友好,數據局部性好
  • 適合處理大規模數據
  • 在許多實際應用中表現優秀

缺點

  • 最壞情況下性能退化至 O(n2),比如當數組已經排序時
  • 不穩定的排序算法
  • 對于小數組,快速排序可能比其他基礎排序慢
  • 遞歸實現可能導致棧溢出(可以使用迭代方式解決)

應用場景

  • 需要高效排序大量數據的情況
  • 作為系統庫中的排序函數(如 C++ 的 std::sort、Java 的 Arrays.sort)
  • 需要就地排序且對空間復雜度敏感的場景
  • 需要平均情況下高性能的應用

擴展

雙軸快速排序

Java 的 Arrays.sort() 使用的是雙軸快速排序,它使用兩個樞軸(基準),可以進一步提高性能:

public static void dualPivotQuickSort(int[] arr, int low, int high) {if (high <= low) return;if (arr[low] > arr[high]) {int temp = arr[low];arr[low] = arr[high];arr[high] = temp;}int pivot1 = arr[low];int pivot2 = arr[high];int lt = low + 1;    int gt = high - 1;   int i = low + 1;     while (i <= gt) {if (arr[i] < pivot1) {int temp = arr[lt];arr[lt] = arr[i];arr[i] = temp;lt++;i++;} else if (arr[i] > pivot2) {int temp = arr[i];arr[i] = arr[gt];arr[gt] = temp;gt--;} else {i++;}}arr[low] = arr[lt - 1];arr[lt - 1] = pivot1;arr[high] = arr[gt + 1];arr[gt + 1] = pivot2;dualPivotQuickSort(arr, low, lt - 2);dualPivotQuickSort(arr, lt, gt);dualPivotQuickSort(arr, gt + 2, high);
}

測驗

這里準備了一些測試題,方便大家判斷自己的掌握情況:

  1. 快速排序的平均時間復雜度是多少?
  2. 快速排序是穩定的排序算法嗎?
  3. 使用最左側元素作為基準的快速排序在什么情況下會出現最壞性能?
  4. 快速排序的空間復雜度是多少?為什么?

測驗答案

  1. O(nlogn)。
  2. 不是,因為基準元素的移動可能會改變相等元素的相對位置。
  3. 當數組已經排序或接近排序時,每次分區只能減少一個元素,時間復雜度退化為O(n2)。
  4. O(logn),主要是遞歸調用占用的棧空間,最壞情況下為O(n)。

相關的 LeetCode 熱門題目

給大家推薦一些可以用來練手的 LeetCode 題目:

  • 215. 數組中的第K個最大元素 - 可以使用快速選擇算法(快速排序的變體)求解,練習分區思想
  • 912. 排序數組
  • 75. 顏色分類 - 一個經典的荷蘭國旗問題,可以使用類似快速排序的分區思想解決

來自: 快速排序 - 算法導航

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

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

相關文章

【監控】Prometheus中的告警機制介紹

prometheus實戰之三&#xff1a;告警規則_驗證prometheus告警規則-CSDN博客 Prometheus是一款開源的系統監控和告警工具&#xff0c;其告警功能是保障系統穩定運行的重要部分。以下將從告警的整體架構、核心概念、規則配置以及具體的通知流程等方面對Prometheus中的告警進行介…

53、用例(Use Case)詳解

1. 定義與核心概念 用例&#xff08;Use Case&#xff09; 是軟件工程中用于描述系統功能需求的核心工具&#xff0c;它通過結構化的方式定義系統與外部參與者&#xff08;用戶、其他系統&#xff09;之間的交互行為&#xff0c;以實現具體的業務目標。用例強調從用戶視角出發…

對比Redis與向量數據庫(如Milvus)在AI中的應用

對比Redis與向量數據庫&#xff08;如Milvus&#xff09;在AI中的應用 在AI架構中&#xff0c;緩存系統的設計直接影響響應速度、資源成本以及推理路徑是否高效。而面對不同的AI業務訴求&#xff0c;選用什么類型的緩存系統、如何搭配&#xff0c;往往是系統架構設計中必須深入…

Oracle 的 MOVE 操作是否重建表?

Oracle 的 MOVE 操作是否重建表&#xff1f; Oracle 的 ALTER TABLE ... MOVE 操作實質上是重建表的物理存儲結構&#xff0c;但保留表的邏輯定義不變。 MOVE 操作的本質 物理重建&#xff1a; 創建新的數據段&#xff08;物理存儲結構&#xff09;將原表數據按順序重新插入到…

數據庫中表的設計規范

表的結構 列&#xff1a;由多個字段構成&#xff0c;每個字段存儲單一數據項&#xff0c;列的先后順序對表沒有影響 行&#xff1a;記錄&#xff0c;一個表中不能存在完全相同的兩行&#xff0c;行的順序對表沒有影響 主鍵&#xff1a;primary key 表中的一列或多列組合起來…

[學習]C語言指針函數與函數指針詳解(代碼示例)

C語言指針函數與函數指針詳解 文章目錄 C語言指針函數與函數指針詳解一、引言二、指針函數&#xff08;函數返回指針&#xff09;定義與語法典型應用場景注意事項 三、函數指針&#xff08;指向函數的指針&#xff09;定義與聲明初始化與調用賦值方式調用語法 高級應用回調函數…

Python 實現桶排序詳解

1. 核心原理 桶排序是一種非比較型排序算法&#xff0c;通過將數據分配到多個“桶”中&#xff0c;每個桶單獨排序后再合并。其核心步驟包括&#xff1a; 分桶&#xff1a;根據元素的范圍或分布&#xff0c;將數據分配到有限數量的桶中。桶內排序&#xff1a;對每個非空桶內的…

brep2seq 論文筆記

Brep2Seq: a dataset and hierarchical deep learning network for reconstruction and generation of computer-aided design models | Journal of Computational Design and Engineering | Oxford Academic 這段文本描述了一個多頭自注意力機制&#xff08;MultiHead Attenti…

在 LangGraph 中集成 Mem0 記憶系統教程

簡介 LangGraph 是一個強大的對話流程編排框架&#xff0c;而 Mem0 則是一個高效的記憶系統。本教程將介紹如何將兩者結合&#xff0c;創建一個具有記憶能力的客服助手系統。 環境準備 首先安裝必要的依賴&#xff1a; pip install langgraph mem0 langchain openai基礎配置…

ceph 報錯 full ratio(s) out of order

full ratio(s) out of order你遇到的錯誤信息: full ratio(s) out of order說明你設置的 OSD 空間使用閾值之間的數值順序不正確,即: nearfull_ratio ≤ backfillfull_ratio ≤ full_ratio ≤ osd_failsafe_full_ratio如果它們的關系不滿足這個順序,Ceph 就會報這個錯誤。…

NB-IoT NPUSCH(三)-資源映射

資源映射單獨做一章節&#xff0c;是因為NPUSCH的資源映射比較復雜。與LTE不同&#xff0c;為了提高數據傳輸的質量&#xff0c;NB-IoT的數據會有重復傳輸。NPUSCH一開始生成的TBS只與子載波個數、RU個數有關&#xff0c;與重復次數沒有關系。初始產生的數據為 個時隙&#xff…

華為OD機試真題——荒島求生(2025B卷:200分)Java/python/JavaScript/C/C++/GO最佳實現

2025 B卷 200分 題型 本專欄內全部題目均提供Java、python、JavaScript、C、C++、GO六種語言的最佳實現方式; 并且每種語言均涵蓋詳細的問題分析、解題思路、代碼實現、代碼詳解、3個測試用例以及綜合分析; 本文收錄于專欄:《2025華為OD真題目錄+全流程解析+備考攻略+經驗分…

centos7安裝MySQL(保姆級教學)

在 Linux 系統的軟件管理中&#xff0c;YUM&#xff08;Yellowdog Updater, Modified&#xff09;包管理器是不可或缺的工具&#xff0c;而 YUM 源的選擇與配置直接影響著軟件安裝與更新的效率。本文將深入解析網絡 YUM 源的分類&#xff0c;詳細介紹如何使用知名平臺提供的 YU…

DeepSeek 賦能教育游戲化:AI 重構學習體驗的技術密碼

目錄 一、引言&#xff1a;教育游戲化與 DeepSeek 的相遇二、DeepSeek 技術剖析2.1 核心架構2.2 關鍵技術 三、教育游戲化設計的奧秘3.1 概念與意義3.2 常見方法與元素3.3 成功案例借鑒 四、DeepSeek 在教育游戲化設計中的多面應用4.1 個性化學習路徑打造4.2 智能教學輔助工具4…

WPF命令與MVVM模式:打造優雅的應用程序架構

?? 打造優雅的應用程序架構 1. ?? 命令系統基礎1.1 ?? 為什么需要命令?1.2 ??? ICommand接口1.3 ??? 實現基本命令2. ??? MVVM模式詳解2.1 ?? MVVM三大組件2.2 ??? 創建ViewModel基類2.3 ?? 典型ViewModel示例3. ?? 命令綁定實戰3.1 ?? View中的命令…

真實案例拆解:智能AI客服系統中的兩類緩存協同

真實案例拆解:智能客服系統中的兩類緩存協同 在AI客服系統中,“響應速度”與“語義準確性”是一對天然的矛盾體。為了實現秒級應答與智能理解的雙重目標,系統需要在技術架構中融合精確命中的緩存系統(如Redis)與模糊語義識別的向量數據庫(如Milvus)。這兩種能力的結合,…

FastAPI與MongoDB分片集群:異步數據路由與聚合優化

title: FastAPI與MongoDB分片集群:異步數據路由與聚合優化 date: 2025/05/26 16:04:31 updated: 2025/05/26 16:04:31 author: cmdragon excerpt: FastAPI與MongoDB分片集群集成實戰探討了分片集群的核心概念、Motor驅動配置技巧、分片數據路由策略、聚合管道高級應用、分片…

一起學數據結構和算法(三)| 字符串(線性結構)

字符串&#xff08;String&#xff09; 字符串是由字符組成的有限序列&#xff0c;在計算機中通常以字符數組形式存儲&#xff0c;支持拼接、查找、替換等操作。 簡介 字符串是計算機科學中最常用的數據類型之一&#xff0c;由一系列字符組成的有限序列。在大多數編程語言中&…

2025電工杯數學建模競賽A題 光伏電站發電功率日前預測問題 保姆級教程講解|模型講解

完整內容請看文章最下面的推廣群 2025電工杯數學建模競賽 A題保姆級分析完整思路代碼數據教學 2025電工杯 A題保姆級教程思路分析 DS數模-全國大學生電工數學建模&#xff08;電工杯&#xff09; A題保姆級教程思路分析 A題&#xff1a;光伏電站發電功率日前預測問題 下面我…

React Native 拼音及拼音首字母搜索組件開發

寫在前面 “用戶說找不到聯系人&#xff1f;拼音搜索功能必須安排上&#xff01;” —— 當產品經理第N次提出這個需求時&#xff0c;我意識到需要開發一個強大的拼音搜索組件。本文將詳細介紹如何開發一個支持拼音匹配、首字母搜索的React Native搜索組件&#xff0c;讓你的應…