当前位置: 首页 > news >正文

快速排序算法详解与洛谷例题实战

快速排序算法详解与洛谷例题实战

一、算法原理深度剖析

快速排序采用分治策略实现高效排序,核心思想可概括为:
排序(A[p..r])=排序(A[p..q−1])⊕基准值⊕排序(A[q+1..r]) \text{排序}(A[p..r]) = \text{排序}(A[p..q-1]) \oplus \text{基准值} \oplus \text{排序}(A[q+1..r]) 排序(A[p..r])=排序(A[p..q1])基准值排序(A[q+1..r])
其中qqq为基准值位置,满足:
∀x∈A[p..q−1],x≤A[q]且∀y∈A[q+1..r],y≥A[q] \forall x \in A[p..q-1], x \leq A[q] \quad \text{且} \quad \forall y \in A[q+1..r], y \geq A[q] xA[p..q1],xA[q]yA[q+1..r],yA[q]

时间复杂度分析:

  • 最优情况O(nlog⁡n)O(n \log n)O(nlogn)(每次划分平衡)
  • 最坏情况O(n2)O(n^2)O(n2)(完全有序数组)
  • 空间复杂度O(log⁡n)O(\log n)O(logn)(递归栈深度)

稳定性证明:
设原始序列中ai=aj(i<j)a_i = a_j(i<j)ai=aj(i<j),若基准值选择导致aia_iaiaja_jaj分属不同分区,则相对位置可能改变,故为不稳定排序


二、算法优化策略
  1. 基准值三数取中法

    def median_of_three(arr, low, high):mid = (low + high) // 2if arr[low] > arr[mid]:arr[low], arr[mid] = arr[mid], arr[low]if arr[low] > arr[high]:arr[low], arr[high] = arr[high], arr[low]if arr[mid] > arr[high]:arr[mid], arr[high] = arr[high], arr[mid]return mid
    
  2. 尾递归优化(减少栈深度)

    void quickSort(int arr[], int low, int high) {while (low < high) {int pi = partition(arr, low, high);if (pi - low < high - pi) {quickSort(arr, low, pi - 1);low = pi + 1;} else {quickSort(arr, pi + 1, high);high = pi - 1;}}
    }
    
  3. 三路划分法(处理重复元素)
    A[p..r]→{小于基准:A[p..i]等于基准:A[i+1..j]大于基准:A[j+1..r] A[p..r] \rightarrow \begin{cases} \text{小于基准} & : A[p..i] \\ \text{等于基准} & : A[i+1..j] \\ \text{大于基准} & : A[j+1..r] \end{cases} A[p..r]小于基准等于基准大于基准:A[p..i]:A[i+1..j]:A[j+1..r]


三、洛谷经典例题实战

例题1:P1177 【模板】快速排序

题目描述
给定nnn个整数,使用快速排序升序排列(1≤n≤1051 \leq n \leq 10^51n105

输入样例

5
4 2 4 1 3

优化解法(C++)

#include <iostream>
#include <algorithm>
using namespace std;int partition(int arr[], int low, int high) {int mid = low + (high - low)/2;int pivot = arr[mid];swap(arr[mid], arr[high]);int i = low;for (int j = low; j < high; j++) {if (arr[j] < pivot) {swap(arr[i], arr[j]);i++;}}swap(arr[i], arr[high]);return i;
}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);}
}int main() {int n;cin >> n;int arr[n];for (int i = 0; i < n; i++) cin >> arr[i];quickSort(arr, 0, n-1);for (int i = 0; i < n; i++) cout << arr[i] << " ";return 0;
}

算法要点

  1. 使用中间位置作为基准值避免有序退化
  2. 单次遍历完成分区操作
  3. 时间复杂度稳定在O(nlog⁡n)O(n \log n)O(nlogn)

例题2:P1923 【深基9.例4】求第 k 小的数

题目描述
给定nnn个整数和kkk,求升序排列后第kkk小的数(1≤n≤5×1061 \leq n \leq 5 \times 10^61n5×106

快速选择算法(C++)

#include <iostream>
using namespace std;int quickSelect(int arr[], int low, int high, int k) {if (low == high) return arr[low];int pivot = arr[(low+high)/2];int i = low, j = high;while (i <= j) {while (arr[i] < pivot) i++;while (arr[j] > pivot) j--;if (i <= j) swap(arr[i++], arr[j--]);}if (k <= j) return quickSelect(arr, low, j, k);if (k >= i) return quickSelect(arr, i, high, k);return arr[k];
}int main() {int n, k;scanf("%d %d", &n, &k);int arr[n];for (int i = 0; i < n; i++) scanf("%d", &arr[i]);cout << quickSelect(arr, 0, n-1, k);return 0;
}

复杂度分析
T(n)=T(n/2)+O(n)⇒T(n)=O(n) T(n) = T(n/2) + O(n) \Rightarrow T(n) = O(n) T(n)=T(n/2)+O(n)T(n)=O(n)
通过避免完全排序,将时间复杂度优化至线性阶


四、工程实践要点

  1. 混合排序策略
    当分区大小<16<16<16时切换插入排序:

    void hybridSort(int arr[], int low, int high) {while (high - low > 16) {int pi = partition(arr, low, high);hybridSort(arr, low, pi-1);low = pi+1;}insertionSort(arr, low, high);
    }
    
  2. 内存访问优化
    基准值选择公式:
    pivot=arr[low+cache_line_size/sizeof(int)] \text{pivot} = \text{arr}[\text{low} + \text{cache\_line\_size}/\text{sizeof(int)}] pivot=arr[low+cache_line_size/sizeof(int)]
    充分利用CPU缓存局部性原理

  3. 并行化实现

    from concurrent.futures import ThreadPoolExecutordef parallel_quick_sort(arr):if len(arr) <= 10000:return sorted(arr)pivot = median_of_three(arr)with ThreadPoolExecutor() as executor:left = executor.submit(parallel_quick_sort, [x for x in arr if x < pivot])right = executor.submit(parallel_quick_sort, [x for x in arr if x > pivot])return left.result() + [x for x in arr if x == pivot] + right.result()
    

五、算法对比分析

特性快速排序归并排序堆排序
时间复杂度O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)
空间复杂度O(log⁡n)O(\log n)O(logn)O(n)O(n)O(n)O(1)O(1)O(1)
稳定性
缓存友好性
最坏情况O(n2)O(n^2)O(n2)O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)

六、扩展应用场景

  1. 数据库索引优化
    B+树节点分裂使用快速排序确定中间键值:
    split_index=quick_select(keys,0,n−1,n//2) \text{split\_index} = \text{quick\_select}(\text{keys}, 0, n-1, n//2) split_index=quick_select(keys,0,n1,n//2)

  2. 计算机图形学
    深度测试中的物体渲染顺序确定:
    z-buffer 排序=quick_sort(objects,key=depth) z\text{-buffer} \text{ 排序} = \text{quick\_sort}(\text{objects}, \text{key}=\text{depth}) z-buffer 排序=quick_sort(objects,key=depth)

  3. 机器学习
    特征选择时的信息增益排序:
    feature_rank=argsort(−information_gain) \text{feature\_rank} = \text{argsort}(-\text{information\_gain}) feature_rank=argsort(information_gain)

http://www.dtcms.com/a/309218.html

相关文章:

  • 【PHP 构造函数与析构函数:从基础到高级的完整指南】
  • 直播平台中的美白滤镜实现:美颜SDK的核心架构与性能优化指南
  • Qt结合ffmpeg实现图片参数调节/明亮度对比度饱和度设置/滤镜的使用
  • Windows编译安装ffmpeg和sdl
  • CG--逻辑判断1
  • 实战指南:如何将Git仓库中的特定文件夹及其历史完整迁移到另一个仓库
  • Git 各场景使用方法总结
  • java8学习笔记-Stream流
  • 在uni-app中引入本地日志插件
  • 城市数字孪生之GISBox三维顶层重建白皮书
  • 操作系统:共享内存通信(Shared Memory Systems)
  • WAIC 2025再发AI十大展望
  • WaitForSingleObject 函数参数影响及信号处理分析
  • SpringAI智能客服Function Calling兼容性问题解决方案
  • 中国信通院/华为:智能体技术和应用研究报告(2025)(转载)
  • 充电桩与照明“联动”创新:智慧灯杆破解新能源基建难题
  • AntFlow 1.0.0 正式发布:企业级开源工作流引擎,历经一年打磨,全面上线!
  • Nginx配置优先级问题导致静态资源404
  • 新书速览|Python数据分析师成长之路
  • 实战指南|虚拟电厂管理平台搭建全流程解析(一)
  • 谷歌Firebase动态链接将失效:如何选择深度链接替代方案?
  • ccf接口测试实战
  • 机器学习sklearn:编码、哑变量、二值化和分段
  • Implement recovery based on PITR using dump file and binlog
  • 用离子交换树脂做镍钴分离的工艺优势
  • Solana:解决Anchor Build编译程序报错 no method named `source_file` found for struct
  • 暑期算法训练.12
  • 练习javaweb+mysql+jsp
  • 渗透测试常用指令
  • [vue3 echarts] echarts 动态数据更新 setInterval