【算法设计与分析】4.3 分治策略 4.4 快速排序

2023-05-16

说明:参考书目为《Computer Algorithms --- Introduction to Design and Analysis》(第三版)Sara Baase, Allen Van Gelder

部分内容参考自大工林晓惠老师的课程【算法设计与分析】讲解。林老师讲算法非常细致,让人很容易理解,推荐一波~

(如部分内容涉及侵权,请联系我删除,谢谢)

 

之前的文章请见:

【算法设计与分析】如何分析一个算法

【算法设计与分析】4.1 插入排序

【算法设计与分析】(习题4.2-4.5) 冒泡排序

本篇文章目录

4.3 分治策略

1. 概念

2. 用分治法求解的条件

3. 步骤

4. 伪代码描述

 

4.4 快速排序

1. 定义

2. 排序过程示例

3. 算法代码

4. 分析 W(n), A(n)

5. 算法改进

1)pivot的选择

2)小排序问题

3)栈空间优化


4.3 分治策略

1. 概念

将一个大问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。

2. 用分治法求解的条件

①小规模时,问题容易求解
②问题可以分解成若干个规模较小的相同问题,子问题的解可以合并为该问题的解
③子问题相互独立,即不包含公共的子问题

3. 步骤

①划分(divide):将原问题分解成若干规模较小、相互独立、与原问题形式相同的子问题。
②解决(conque):若子问题规模较小,则直接求解;否则递归求解个子问题。
③合并(combine):将各子问题的解合并为原问题的解。

4. 伪代码描述

solve(I)    // 解决I问题的函数
    n = size(I);    // n是I这个问题的大小
    if(n <= smallSize)    // 问题规模小直接解决
        solution = directlySolve(I);
    else
        divide I into I1,...,Ik.    // 问题规模大划分成k个子问题
        for each i in {1,...,k}:
            Si = solve(Ii);    // 递归调用
            solution = combine(S1,...,Sk);    // 合并k个子问题的解
    return solution;

 

4.4 快速排序

1. 定义

每趟排序从待排序的数组中取一个值作为pivot,该趟排序后pivot左边的数全部<=pivot,pivot右边的数全部>pivot,由此将数组划分为<=pivot和>pivot两部分,对这两部分迭代地用上述方法继续排序,直到所有数据元素均排好序。(n个数据元素的排序经过n-1次比较,划分为2个与原问题形式相同的排序子问题)

注意:一次比较可能不止消除一对逆序

2. 排序过程示例

3. 算法代码

void QSort(Element[] E, int first, int last)
{
    int t;
    if(first < last)
    {
        t = partition(E, first, last);
        QSort(E, first, t-1);
        QSort(E, t+1, last);
    }
}

int partition(Element[] E, int first, int last)
{ 
    E[0]=E[first];    // 此种方法选择待排序数组的第一个元素作为pivot
    while(first<last)
    {
        while((first < last) && (E[last] >E[0])) last--;
        if (first < last) 
        {
            E[first]=E[last];
            first++;
        }
        while((first < last) && (E[first]<=E[0])) first++;
        if(first < last)
        {
            E[last]=E[first];
            last--;
        }
    }
    E[first]=E[0];
    return first;
}

4. 分析 W(n), A(n)

空间:使用快速排序时,会将待排序的子数组放入栈中,栈的大小取决于划分的子数组大小。在最坏情况下,空间复杂度就是\Theta (n)

时间:

1)最坏情况:W(n)=\frac{n(n-1)}{2}【待排序的数组已经是升序,如果每次取子数组的第一个元素作为pivot,那么数组每次都会被划分为含有0个元素的左区域和n-1个元素的右区域】

推理过程如下图 ↓

2)平均情况:

假定所有划分情况都是等可能的,

目前A(n)只是一个递推公式,我们需要进一步得到以n为自变量的公式,才能得到A(n)的时间复杂度。

现在有两种方法可以求解A(n):①先猜A(n)的估计值,然后证明这个值;②直接推理计算

方法①:

首先估计一下A(n)大致的公式:Q(n)\approx n+2Q(n/2)      第一个n是划分需要的比较次数;假设每一次划分都得到两个大小一样的子域 -> 2Q(n/2)

根据定理3.17可以估计出Q(n)\in \Theta (n log(n)),具体推导过程如下图 ↓

根据上面我们的估计Q(n)\in \Theta (n log(n)),可以做出如下假设(同时也是书中定理4.2):

接下来使用数学归纳法证明A(n)<=cnlnn:

因为lnn\approx 0.693lgn,所以有推论4.3:平均来说,假设所有输入是等概率的,那么在大小为n的序列上使用快速排序所需的比较次数大概是1.386nlgn(n足够大)。

 

方法②:

5. 算法改进

1)pivot的选择

为了避免最坏情况的发生,即选择的pivot是当前数组最大或最小值,我们需要改变选择pivot的策略:

①随机选择

②在E[first],E[last]和E[(first+last)/2]这三个数中取中值

2)小排序问题

因为快排采用递归的方式排序,当待排序数较少时,递归调用函数就比直接迭代排序(如插入排序)的开销大。所以在排序数较少时,可以采用插入排序。

设待排序数<=smallSize时为小排序,有两种情况涉及到小排序:

①原本待排序数<=smallSize

②经过快排的分治策略,将原数组不断划分,子数组的大小<=smallSize

// 针对小排序问题,修改原递归程序
void QSort(Element[] E, int first, int last)
{
    int t;
    if(last - first > smallSize)
    {
        t = partition(E, first, last);
        QSort(E, first, t-1);
        QSort(E, t+1, last);
    }
    else
    {
        smallSort(E, first, last);    // 小排序使用的排序方法(如插入排序)
    }
}

3)栈空间优化

在递归调用时,会将子数组存入栈中,如果子数组过大,栈所需空间过大,频繁做pop或push的压力大。

因此改进算法:①原本两个递归只保留第一个(由于第二个递归的代码位于程序的最后一行,所以依照前面插入排序的shiftVac将递归改为迭代 → 用while循环处理)

②每次递归处理的比迭代处理的子数组要小

quickSortTRO(E, first, last)
    int first1, last1, first2, last2, t;

    first2 = first; last2 = last;
    while(last2 - first2 > 1)
        t = partition(E, first2, last2);
        if(t < (first2 + last2) / 2)
            first1 = first2; last1 = t - 1;
            first2 = t + 1; last2 = last2;
        else
            first1 = t + 1; last1 = last2;
            first2 = first2; last2 = t - 1;
        quickSortTRO(E, first1, last1);    // first1->last1是递归部分,即子数组中较小的部分
    return;

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【算法设计与分析】4.3 分治策略 4.4 快速排序 的相关文章

  • 最优控制理论(一)基本概念

    1 概念 在军事 航空航天 导航制导 生产 经济活动以及人类其他有目的的活动中 xff0c 常需要对被控系统 被控过程施加某种控制作用 xff0c 使某个性能指标达到最优 xff0c 这种控制作用称为最优控制 使控制系统的性能指标实现最优化
  • ROS学习笔记--cv_bridge

    cv bridge是在ROS图像消息和OpenCV图像之间进行转换的一个功能包 一 xff09 在ROS图像和OpenCV图像之间转换 xff08 C 43 43 xff09 xff11 xff0e Concepts xff08 概念 xf
  • stm32+esp8266+onenet (MQTT)

    使用stm32采集温湿度 MQ2的数值用过 esp8266 43 mqtT协议把数据传输给onenet平台 并且能通过onenet下发指令控制led灯的亮灭 打开onenet平台 xff0c 使用旧版MQTT协议 xff0c 选择多协议接入
  • Hadoop The Definitive Guide:Hadoop权威指南-PART 1

    简介 xff1a Hadoop起源于Nutch 当人们试图构建一个开源网络搜索引擎 xff0c 但在管理在少数计算机上运行的计算时遇到了麻烦 后来Google发表了GFS和MapReduce相关介绍 xff0c 路线就变得清晰了 他们设计了
  • 【计算机图形学】绘制一个基于GDI的图形程序

    这学期选修了计算机图形学这门课 xff0c 该合集用来记录课程所学知识 概念类的内容来自于百度文库 xff1a https wenku baidu com view c3c5b36048d7c1c708a145a2 html 概念介绍 GD
  • Ubuntu 18.04 安装无人机开发环境 PX4+ROS+Gazebo

    Ubuntu 18 04 安装无人机开发环境 PX4 43 ROS 43 Gazebo 本教程基于纯净的Ubuntu 18 04 配置上述环境 由于国内网络环境问题 xff0c 无法正常从github下载文件的请用代理 代理网站 xff1a
  • docker命令详解及参数作用

    下载镜像 docker pull 镜像名 标签 查看本地镜像 docker images 删除镜像 xff1a docker rmi 镜像名 标签 启动容器 docker run d name 61 mynginx resrart 61 a
  • Mac sourcetree连接gitee码云仓库

    一 复制自己的ssh key 添加到gitee的ssh 共钥中 二 添加后 xff0c 在终端输入 ssh T git 64 gitee com gt gt 出现下面的successfully就代表关联成功了 三 sourcetree中选择
  • 路径规划与避障算法(一)---DWA算法概述

    版权声明 xff1a 本文为博主原创文章 xff0c 转载请联系博主 https mp csdn net mdeditor 82764989 DWA 动态窗口算法 算法概述 算法原理可见 https blog csdn net heyiji
  • 路径规划与避障算法(七)---DWA算法流程之三---碰撞检测评价函数

    版权声明 xff1a 本文为博主原创文章 xff0c 原创不易 转载请联系博主 本篇博客主要介绍DWA算法所采用的评价函数中障碍物相关的评价函数 评价函数 轨迹主要依据以下三条准则进行评分 综合评分后选取分数最小的路径作为下一时刻选择路径
  • 彻头彻尾理解JVM系列之九:不会JVM调优怎么进互联网大厂

    大家好 我是慕枫 前阿里巴巴高级工程师 InfoQ签约作者 阿里云专家博主 一直致力于用大白话讲解技术知识 在这里和大家分享一线互联网大厂面试经验 技术人成长路线以及Java技术 分布式 高并发 架构设计方面的经验总结 感恩遇见 希望我们都
  • CVPR代码和论文链接目录大全

    最新 xff01 CVPR 2021 语义分割论文大盘点 xff08 39篇论文 xff09 xff1a https blog csdn net amusi1994 article details 118426626 CVPR代码和论文链接
  • Ubuntu 桌面被删除,恢复

    step1 在桌面上打开终端 xff0c cd 到自己的home文件夹 step2 ls la 出现隐藏的文件及文件夹 step3 找到 config文件夹中的user dirs dirs 如图 图是找的图片 将最后vim user dir
  • 在Linux中编译带有自己编写的头文件的C程序

    有三个文件callback c xff0c callback h xff0c demo c 其中callback h是自己编写的头文件 在Linux中编译运行demo c的时候注意也要编译callback c文件 xff0c 否则会报错 引
  • Anaconda和TensorFlow开发环境搭建

    参考链接 xff08 MOOC大学 深度学习应用开发 TensorFlow实践 第二讲 xff09 xff1a https www icourse163 org course ZUCC 1206146808 一 Anaconda下载 官网下
  • 【wxPython导入失败】Failed building wheel for wxPython

    导入包wxPython失败 xff1a Failed building wheel for wxPython 错误原因 xff1a 根据错误提示发现我的电脑上有两个版本的Python xff0c 一个是最开始学Pyhton的时候装的3 7版
  • 【PEP 484】什么是.pyi文件?

    在PyCharm中查看源代码的时候 xff0c 发现有些代码行有星号 标识 xff0c 鼠标移上去会提示在某个 pyi文件中有其存根程序 xff0c 点击星号会跳转到对应的存根程序处 那什么是存根程序呢 xff1f 我第一次看到这个概念是在
  • 【timeout error】导入手写体识别数据(MNIST)超时

    问题起因 xff1a 想要用TensorFlow做手写体识别 xff0c 在导入数据的时候出现了超时的问题 解决方法 xff1a C Users Desny Anaconda3 pkgs tensorflow 1 2 1 py35 0 Li
  • 【深度学习】如何计算AP(平均精度)和mAP(平均精度均值)?

    起因 xff1a 最近导师给买了本书 xff0c 叫做 智能计算系统 xff08 陈云霁等人编著 xff09 xff0c 让我上b站看看教材对应的视频 不得不说这书写的确实不错 xff0c b站上的视频讲的也还可以 书和视频的内容可以相互补
  • 【TensorBoard】进入TensorBoard方法

    1 打开Anaconda Prompt xff0c 切换目录 必须切换到 log 文件夹所在的盘 xff0c 也可以进一步切换到 log 文件夹的位置 xff08 注 xff1a 如果没有切换到 log所在的盘 xff0c 比如 log放在

随机推荐