• 快速排序


    昨天通宵,早上四点的时候就开始写博客.结果五点的时候电脑罢工,自动重启.我写的东西也就都没有了,都怪自己平时没有保存的习惯。

    下次一定要注意,要养成保存的习惯,要不然再发生这样的情况,那就只能笑话自己还是个马马虎虎的小孩子了.

    刚才自己列了一下文章中需要讲到的部分,很庆幸,今天的状态还不错,自己还是很满意的.

    说到排序算法,首先来搞清楚一个问题,内排序和外排序指的是什么?要想解释这个问题,需要将内排序和外排序比较区分.

    内排序: 需要比较的数据数量相比较外排序少,排序的数据可以一次装入内存中,在内存中进行排序.

    外排序: 需要比较的数据数量相比较内排序多,数据无法一次装入内存进行排序操作.数据一般存储在较慢的外存储器.而且一般借助临时

                 文件完成排序操作.

    快速排序算法也是基于分治模式.分治模式怎么解释?

    所谓分治模式,来自算法的一种思想-- 分治思想.分治算法的基本思想就是将一个规模为N的问题分解为K个规模较小的子问题,且子问题

    与原问题相互独立而且性质相同,所以求出子问题的解,就可一得到原问题的解.

    分治算法的解题步骤:

    1. 分解: 将需要解决的问题划分为相互独立且性质相同的若干子问题.

    2. 求解: 求解每一个子问题的解.

    3. 合并:  合并子问题的解得到原问题的解.

    从分治算法的解题步骤可以看出,分治的思想突出的就是分开治理,从局部到整体.用个不恰当的例子来理解一下分治,就像是生活中我们

    遇到复杂棘手的问题,仔细分析,然后按照步骤一个个解决,从简单到复杂.

    为什么要浪费这么多的语言来说明一下分治算法思想,因为<<算法导论>>中对于快速排序的描述是用分治模式来描述的.

    快速排序算法的描述:(<<算法导论>>)

    分解:  数组A[p..r]被划分成为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A(q),而且小于等于A[q+1..r]

              中的元素,下标q也在划分的过程中进行计算.

    解决: 通过递归调用快速排序,对子数组A[p..q-1],A[q+1..r]排序.

    合并: 因为两个子数组是就地排序的,将他们的合并不需要操作:整个数组A[p..r]已排序.

    就地排序是什么? 怎么理解呢? -,-,先别急,先来看看对于快速排序过程的伪代码描述,让我们清晰的理解一下快速排序的过程.

    QUICKSORT(A,p,r)

    1  if p < r

    2     then q <-- PARTITION(A,p,r)

    3      QUICKSORT(A,p,q-1)

    4      QUICKSORT(A,q+1,r)


    QUICKSORT函数中三个参数的意义: A 待排序数组  p 排序开始标志位  r 待排序数组A的长度.

    如果想要给一个完整的数组A排序,那么就需要执行QUICKSORT(A,1,length[A]).

    从上面的排序过程可以看出3,4都是递归调用解决子问题,而就地排序的过程在PARTITION中进行。所以重点理解PARTITION。

    PARTITION(A,p,r)

    1  x <-- A[r]

    2  i  <-- p-1

    3  for j <-- p to r-1

    4        do if A[j] <= x

    5              then  i <-- i+1

    6                 exchange A[i] <--> A[j]

    7 exchange A[i+1] <--> A[r]

    8 return i+1

    上述就地排序的过程是:选取数组最后一个元素作为主元,然后循环遍历A(p) to A(r-1) 将数组分为左右两个部分,

    左边部分的元素都是小于等于A(r),右边的元素都大于A(r).注意交换的元素索引,是i而不是j,所以在最后执行一步操作

    exchage A[i+1] <--> A[j],将此次排序的基准主元移动到分界点,然后返回索引,用于下面对于划分后的左右两个部分的

    递归排序,也就是上面

    3      QUICKSORT(A,p,q-1)

    4      QUICKSORT(A,q+1,r)

    操作.

    对于快速排序的概念解释的差不多了,下面来说说快速排序的性能.

    快速排序的最坏性能:

         最坏的情况发生子划分的过程中,产生的两个区域分别包含N-1个元素和1个0元素.那么运行时间就可以递归的表示

         为T(n) = T(n-1)+ T(0)+O(n)= T(n-1) + O(n) = O(n^2)

    快速排序的最佳性能:

         快速排序就地排序的过程中划分出的两个子问题都不可能大于n/2(因为主元已经被划分出,不需要放在任意一个子问题中

         重复求解).如果每次的划分总是两边对称的,那么就会得到最佳运行情况:

                  T(n) <= 2T(n/2)+ O(n)    T(n) = O(nlgn)

    快速排序的平衡性能:

          快速排序的性能接近最佳性能而不是接近最坏性能。当划分情况是按照常数比例划分的时候,得到的性能指标是O(nlgn)

    上面只是说了一些快速排序的性能指标,按照我的层次也不能去证明这些. 另外也没有必要,只要知道在什么情况下是最好情况,

    什么情况下是最坏情况. 证明的事情就留给有想法的人去做吧.

    至于快速排序的源码实现:

    看了网上很多网友在博客中给出的快速排序源码,不发表评论.但是我还是比较相信标准,所以将看一下glibc和libstd++中GNU对

    C和C++两个不同版本的快速排序的源码实现.将会在下篇文章中给出.

     
     
  • 相关阅读:
    解决input 输入框频繁请求问题,如果拿取最后一次接口返回的值
    记录两个小问题
    axios 如何取消请求
    给vue组件绑定原生事件
    Vue3 与 Vue2的不同之处一 简单介绍 Vue 核心最基本的功能
    js将数组对象中,以某个值相同的对象合并成一个;即把某个值相同的对象内容合并成一个
    postcss-preset-env
    webpack5 tree shaking
    深拷贝
    webpack 性能优化
  • 原文地址:https://www.cnblogs.com/respawn/p/2716100.html
Copyright © 2020-2023  润新知