快速排序,分治法实际应用(含码源与解析)

简介: 快速排序,分治法实际应用(含码源与解析)

正文


定义


       快速排序是另一种基于分治技术的重要排序算法。与我们上一篇所讲的合并排序不一样。合并排序是按照元素在数组中的位置对它们进行划分,快速排序按照元素的值对它们进行划分。划分是对给定数组中的元素的重新排列,使得一个数组A[i],有s下标,A[s]左边的元素都小于等于A[s],而所有A[s]右边的元素都大于等于A[s]。


A[0]...A[s-1],A[s],A[s+1]...A[i-1]

       显然,在对数组建立了一个划分以后,A[s]已经位于它在有序数组中的最终位置,接下来我们可以继续对A[s]前和A[s]后的子数组分别进行排序(例如,使用同样的方法)。注意,它与合并排序的不同之处在于:在合并排序算法中,将问题划分成两个子问题是很快的,算法的主要工作在于合并子问题的解;而在快速排序中,算法的主要工作在于划分阶段,而不需要再去合并子问题的解了。


伪代码


       伪代码实现


Quicksort(A[ l..r ])
//用Quicksort对子数组排序
//输入:数组A[0..n-1]中的子数组A[ l..r ],由左右下标 l 和 r 定义
//输出:非降序排列的子数组A[ l..r ]
if l < r
        s <-Partition (A[1..r])//s是分裂位置
        Quicksort( A[ l.. (s - 1)])
        Quicksort(A[(s +1)..r ])


算法解析


       对于快速排序,有数组A[0..n-1],子数组A[e..r],我们要选择一个中轴,接下来会根据该元素的值来划分子数组。选择中轴有许多不同的策略,当我们分析该算法的效率时,我们会回到这个话题。现在,我们只使用最简单的策略——选择子数组的第一个元素,即p=A[0]。


       然后 我们将分别从子数组的两端进行扫描,并且将扫描到的元素与中轴相比较。从左到右的扫描(下面用指针i表示)从第二个元素开始。因为我们希望小于中轴的元素位于子数组的左半部分,扫描会忽略小于中轴的元素,直到遇到第一个大于等于中轴的元素才会停止。从右到左的扫描(下面用指针j表示)从最后一个元素开始。因为我们希望大于中轴的元素位于子数组的右半部分,扫描会忽略大于中轴的元素,直到遇到第一个小于等于中轴的元素才会停止。(为什么当遇到与中轴元素相等的元素时值得停止扫描?因为当遇到有很多相同元素的数组时,这个方法可以将数组分得更加平均,从而使算法运行得更快。如果我们遇到相等元素时继续扫描,对于一个具有n个相同元素的数组来说,划分后得到的两个子数组的长度可能分别是n~1和0,从而在扫描了整个数组后只将问题的规模减1。)


       两次扫描全部停止以后,取决于扫描的指针是否相交,会发生3种不同的情况。1、如果扫描指针i和 j不相交,也就是说i<j,我们简单地交换A[i]和A[j],再分别对i加1,对j减1,然后继续开始扫描;2、如果扫描指针相交,也就是说i> j,把中轴和A[j]交换以后,我们得到了该数组的一个划分;3、最后,如果扫描指针停下来时指向的是同一个元素,也就是说i= j,被指向元素的值一定等于p。(为什么?)因此,我们建立了该数组的一个划分,分裂点的位置s =i= j。


       我们可以把第三种情况和指针相交的情况(i> j )结合起来,只要i≥j,就交换中轴和A[j]的位置


时间效率分析


       在开始讨论快速排序的效率以前,我们应该要注意;如果扫描指针交叉了,建立划分之前所执行的键值比较次数是n+1;如果它们相等,则是n。如果所有的分裂点位于相应子数组的中点,这就是最优的情况。在最优情况下,键值比较的次数Cbes(n)满足下面的递推式:


当n>1时,777.gif


       根据主定理,;对于n=2*的情况求得 。


       在最差的情况下,所有的分裂点都趋于极端:两个子数组有一个为空,而另一个子数组仅仅比被划分的数组少一个元素。具体来说,这种令人遗憾的情况会发生在升序的数组上,也就是说,输入的数组已经被排过序了!的确,如果 A[0..n –1]是严格递增的数组,并且我们将A[0]作为中轴,从左到右的扫描会停在A[1]上,而从右到左的扫描会一直处理到A[0]为止,导致分裂点出现在0这个位置。


       所以,在进行了n+1次比较之后建立了划分,并且将A[0]和它本身进行了交换以后,快速排序算法还会对严格递增的数组A[1..n-1]进行排序。对规模减小了的严格递增数组的排序会一直继续到最后一个子数组A[n-2..n-1]。这种情况下,键值比较的总次数应该等于:

888.gif


源码


#include <stdio.h>
// 交换两个元素的值
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];
    // i指向小于基准值的最后一个元素
    int i = (low - 1);
    // 遍历数组,将小于基准值的元素放到左边,大于基准值的元素放到右边
    for (int j = low; j <= high - 1; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    // 将基准值放到中间
    swap(&arr[i + 1], &arr[high]);
    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);
    }
}
int main() {
    int arr[] = {10, 7, 8, 9, 1, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    quickSort(arr, 0, n - 1);
    printf("Sorted array: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}
相关文章
|
7月前
|
机器学习/深度学习 文字识别 监控
安全监控系统:技术架构与应用解析
该系统采用模块化设计,集成了行为识别、视频监控、人脸识别、危险区域检测、异常事件检测、日志追溯及消息推送等功能,并可选配OCR识别模块。基于深度学习与开源技术栈(如TensorFlow、OpenCV),系统具备高精度、低延迟特点,支持实时分析儿童行为、监测危险区域、识别异常事件,并将结果推送给教师或家长。同时兼容主流硬件,支持本地化推理与分布式处理,确保可靠性与扩展性,为幼儿园安全管理提供全面解决方案。
353 3
|
8月前
|
人工智能 API 开发者
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
500 27
|
8月前
|
供应链 项目管理 容器
深入探索 BPMN、CMMN 和 DMN:从定义到应用的全方位解析
在当今快速变化的商业环境中,对象管理组织(OMG)推出了三种强大的建模标准:BPMN(业务流程模型和符号)、CMMN(案例管理模型和符号)和DMN(决策模型和符号)。它们分别适用于结构化流程管理、动态案例处理和规则驱动的决策制定,并能相互协作,覆盖更广泛的业务场景。BPMN通过直观符号绘制固定流程;CMMN灵活管理不确定的案例;DMN以表格形式定义清晰的决策规则。三者结合可优化企业效率与灵活性。 [阅读更多](https://example.com/blog)
深入探索 BPMN、CMMN 和 DMN:从定义到应用的全方位解析
|
8月前
|
存储 弹性计算 安全
阿里云服务器ECS通用型规格族解析:实例规格、性能基准与场景化应用指南
作为ECS产品矩阵中的核心序列,通用型规格族以均衡的计算、内存、网络和存储性能著称,覆盖从基础应用到高性能计算的广泛场景。通用型规格族属于独享型云服务器,实例采用固定CPU调度模式,实例的每个CPU绑定到一个物理CPU超线程,实例间无CPU资源争抢,实例计算性能稳定且有严格的SLA保证,在性能上会更加稳定,高负载情况下也不会出现资源争夺现象。本文将深度解析阿里云ECS通用型规格族的技术架构、实例规格特性、最新价格政策及典型应用场景,为云计算选型提供参考。
|
8月前
|
数据采集 机器学习/深度学习 存储
可穿戴设备如何重塑医疗健康:技术解析与应用实战
可穿戴设备如何重塑医疗健康:技术解析与应用实战
322 4
|
8月前
|
人工智能 自然语言处理 算法
DeepSeek大模型在客服系统中的应用场景解析
在数字化浪潮下,客户服务领域正经历深刻变革,AI技术成为提升服务效能与体验的关键。DeepSeek大模型凭借自然语言处理、语音交互及多模态技术,显著优化客服流程,提升用户满意度。它通过智能问答、多轮对话引导、多模态语音客服和情绪监测等功能,革新服务模式,实现高效应答与精准分析,推动人机协作,为企业和客户创造更大价值。
732 5
|
8月前
|
机器学习/深度学习 JSON 算法
淘宝拍立淘按图搜索API接口系列的应用与数据解析
淘宝拍立淘按图搜索API接口是阿里巴巴旗下淘宝平台提供的一项基于图像识别技术的创新服务。以下是对该接口系列的应用与数据解析的详细分析
|
8月前
|
机器学习/深度学习 人工智能 自然语言处理
DeepSeek 实践应用解析:合力亿捷智能客服迈向 “真智能” 时代
DeepSeek作为人工智能领域的创新翘楚,凭借领先的技术实力,在智能客服领域掀起变革。通过全渠道智能辅助、精准对话管理、多语言交互、智能工单处理、个性化推荐、情绪分析及反馈监控等功能,大幅提升客户服务效率和质量,助力企业实现卓越升级,推动智能化服务发展。
353 1
|
8月前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
JSON API 数据格式
淘宝商品评论API接口系列的应用与数据解析
在电商平台中,用户评论是了解商品质量、服务水平和用户满意度的重要数据来源。淘宝作为中国最大的电商平台,提供了商品评论API接口,帮助开发者获取和分析用户评价数据。本文将介绍淘宝商品评论API接口系列的作用、使用方法,并通过示例展示如何调用API并解析返回的JSON数据。

推荐镜像

更多
  • DNS