前言

上次分享的冒泡排序虽然比较简单、容易理解,但每一次冒泡的过程都需要依次比较相邻的元素,然后交换,可见性能还是有很大的优化空间,只要能减少比较次数,性能自然就上去啦;快速排序便是一个很不错的选择~~~

正文

1.1 快速排序算法思想

快速排序(Quicksort)是对上一次分享的冒泡排序算法的一种改进,主要是减少比较次数,以此来提高排序性能;也属于交换排序的一种。

算法思想

  • 在待排序列表中任取一个元素作为基准值

  • 将剩下的元素和基准值依次比较,小于的放左边,大于的放右边,最后通过一趟排序将待排序列表分为左右两部分,这个过程称为一次“划分”

  • 然后用同样的方法分别在左右两部分中取基准值进行排序,依次递归,直到划分的每部分内只有一个元素或空为止,则排序结束。

1.2 快速排序算法实现与解析

  • 算法实现

    划分代码实现,每一次取对应部分的首位元素作为基准值,然后通过依次比较,将对应数据又在细分为左右两部分,如下实现:

    image-20210506133026759

    使用递归进行划分排序,直到只有一个元素或为空为止:

    image-20210506133313691
  • 运行效果

    image-20210506133449121
  • 步骤解析(升序)

    image-20210506135153320

    上图步骤说明:

    上图演示是针对数组array进行升序排序,第一次以全部数据为一组,low为0,high为5,选择low位元素2为基准值(即第一个元素),开始进行比较:

    第1.1步:由于刚开始选择low位的元素为基准值(可以认为这个位置空了),所以接下来开始从high位开始遍历比较,high位元素3大于2,不用交换位置,high减1,继续比较;

    第1.2步:此时low为0,high为4,high位元素9大于2,不用交换位置,high减1,继续比较;

    第1.3步:此时low为0,high为3,high位元素1小于2,需要将high位元素1放到基准值的左边,则将元素1放到low指向的位置;

    第1.4步:此时low为0,high为3,由于high位已经交换过了(可以认为这个位置空了),所以这次开始到low位进行遍历比较,low位元素是刚交换过来的,所以不用交换位置;low加1继续比较,此时low为1,对应位置的元素5大于基准值2,所以需要将元素5放到基准值的右边,则将元素5放到high指向位置;

    第1.5步:此时low为1,high为3,由于low位已经交换过了(可以认为这个位置空了),所以这次又回到high位进行遍历比较,high位元素是刚交换过来的,所以不用交换位置;high减1继续比较,此时high为2,对应位置元素6大于基准值2,所以不用交换位置,high减1,继续比较;

    第1.6步:此时low为1,high为1,此时代表第一次划分排序完成,则将基准值放到这个位置;最终将原始数据分为左右两部分,左部分只有一个元素1,不用再划分了,右部分有6,5,9,3四个元素,继续对于右部分进行划分

    第2.1步:由于右部分是从索引位2开始,所以此时low为2,high为5,基准值为low为的元素6;

    第2.2步:由于刚开始选择low位的元素为基准值(可以认为这个位置空了),接下来从high为开始遍历比较,high为元素3小于基准元素6,需要将其放到基准元素的左边,则将元素3放到low指向的位置。

    第2.3步:此时low为2,high为5,由于high位已经交换过了(可以认为这个位置空了),所以这次开始到low位进行遍历比较,low位元素是刚交换过来的,所以不用交换位置;low加1继续比较,此时low为3,对应位置的元素5小于6,不需要交换元素,则low加1,继续比较;

    第2.4步:此时low为4,high为5,low位对应的元素9大于基准值6,所以需要将其放到基准元素的右边,则将元素9放到high指向的位置。

    第2.3步:此时low为4,high为5,由于low位已经交换过了(可以认为这个位置空了),所以这次开始到high位进行遍历比较,high位元素是刚交换过来的,所以不用交换位置;high减1继续比较,此时high为4,此时low和high都为4,找到此次划分基准值的位置,则将基准元素6的放到4位置;到这又将原来的右部分6,5,9,3四个元素划分为左右两部分,右边只有一个元素9,不用继续划分;左边有元素3和5,继续划分排序;(这里就不重复演示)

    最终通过递归划分排序的方式,直到每个划分部分内只有一个元素或空为止,即可获得最后的排序结果。

1.3 快速排序算法分析

时间复杂度

从上面解析步骤得知,每一次排序都是只需要处理剩下未排序的元素,每一次排序时间复杂度不会超过O(n),但由于是通过递归进行划分排序,所以快速排序的整体时间复杂度和递归层数有关,即总的时间复杂度为O(n*递归层数)

通过上面演示得知,其实最终将待排序数据划分为一个二叉树结构,在这二叉树的高度就代表递归的层数(后续会专门分享这块内容),如下图:

image-20210506143932543

关于n个元素的二叉树的最小高度为(log2n)+1,最大高度为n,如果待排序数据已经有序或逆序,如果每次都选择每部分的首个元素为基准值,这样就会导二叉树高度增加,即递归深度就会增加;所以快速排序的时间复杂度最好为O(nlog2n),最坏为O(n2)

这样以为快速排序就不行了吗?当然不是,可以随机选一个元素做为基准值,这样不管待排序数据为有序还是逆序,都不会导致递归深度太深。所以最后快速排序的平均时间复杂度为O(nlog2n)

空间复杂度

空间复杂度在每次递归当中,用到的变量都是固定的(pivot,low,high),则最终影响空间复杂度的因素还是递归层数,则快速排序空间复杂度为O(递归层数), 最好为O(log2n),最坏为O(n)。

稳定性

由于是用待排序数据和基准值进行比较,所以最终元素交换位置不是固定的,则不能保证两个相等元素原有顺序不变,则快速排序是不稳定的。如下图:

image-20210506150331140

如果取low位置的元素3作为基准值,最终会和元素2进行交换,最后就不能保证原来相等元素的前后顺序了。

综上所述,快速排序的时间复杂度为O(nlog2n),空间复杂度为O(log2n),是不稳定算法;

总结

快速排序有效的解决了冒泡排序的缺陷,减少了比较次数,提升了排序性能。但当待排序列表为有序或逆序时,如果单纯的取第一个元素或最后一个元素作为基准值,排序性能并没有提升。所以实现排序算法的关键是需要选个好的基准值,比如可以随机选择,也可以定义一个规则选择,看小伙伴的实现方式咯。

感谢小伙伴的:点赞收藏评论,下期继续~~~

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~~~

快速排序的性能和名字一样优秀相关推荐

  1. 数据结构(八):排序 | 插入排序 | 希尔排序 | 冒泡排序 | 快速排序 | 简单选择排序 | 堆排序 | 归并排序 | 基数排序 | 外部排序 | 败者树 | 置换-选择排序 | 最佳归并树

    文章目录 第八章 排序 一.排序的基本概念 (一)什么是排序 (二)排序的应用 (三)排序算法的评价指标 (四)排序算法的分类 (五)总结 二.插入排序 (一)算法思想 (二)算法实现 (三)算法效率 ...

  2. java jdk实现快速排序_Java实现快速排序过程分析

    快速排序过程 没有既不浪费空间又可以快一点的排序算法呢?那就是"快速排序"!光听这个名字是不是就觉得很高端呢. 假设我们现在对"52 39 67 95 70 8 25 5 ...

  3. Go 编码建议——性能篇

    文章目录 常用数据结构 1.反射虽好,切莫贪杯 1.1 优先使用 strconv 而不是 fmt 1.2 少量的重复不比反射差 1.3 慎用 binary.Read 和 binary.Write 2. ...

  4. C语言——十四种内部排序算法【直接插入排序-冒泡排序-选择排序-插入排序-希尔排序-归并排序-快速排序-堆排序-折半插入排序-二分查找-路插入排序-表插入排序-简单选择排序-直接选择排序-树形选择】

    目录: 一:插入排序 A:直接插入排序 1.定义: 2.算法演示 实例1: 3.基本思想 4.排序流程图 实例1: B:希尔排序 1.定义: 2.算法演示 实例2: C:其他插入排序 a:折半插入排序 ...

  5. c语言的qsort快速排序函数

    目录 qsort的介绍 测试 排序int类型 排序char类型 排序结构体类型 qsort的介绍 c语言中有很多排序,比如常见的选择排序,冒泡排序,插入排序,但是c语言的库函数中,有一个qsort() ...

  6. 《数据结构与算法》(二十五)- 排序算法:快速排序

    目录 前言 1. 快速排序 1.1 快速排序算法 1.2 快速排序算法复杂度分析 1.3 快速排序优化 2. 总结 原文地址:https://program-park.github.io/2021/1 ...

  7. 快速排序算法(基于Java实现)

    title: 快速排序算法(基于Java实现) tags: 快速排序算法 快速排序算法的原理与代码实现: 一.快速排序算法的原理 快排算法的思想是: 如果需要排序数组中下标从p到r之间的一组数据,我们 ...

  8. Android性能优化之运算篇

    原文转自 Techfox IT技术论坛 运算篇 1) Intro to Compute and Memory Problems Android中的Java代码会需要经过编译优化再执行的过程.代码的不同 ...

  9. UWA官方Demo新增《小米超神》,全面揭秘重度手游的性能表现!

    还记得UWA[博观约取]专栏推荐的<小米超神>吗?作为一款重度的MOBA手游,它在不同配置的移动设备上,无论是画面表现力,还是性能开销都非常优秀.我们曾公布过该游戏的主要性能数据,当然其出 ...

最新文章

  1. 利用PHP-ExcelReader实现PHP导入Excel数据[不通过CSV]
  2. 理解Android Binder机制(1/3):驱动篇
  3. 100亿人口会挨饿吗?人工智能迎击全球粮食问题
  4. LeetCode 885. 螺旋矩阵 III
  5. 程序员为什么想进大厂,看看年终奖你们就知道了
  6. 被卡性能的时候要care数据类型(洛谷P5594TLE+RE的经历,Java语言描述)
  7. ElementUI table组件,表格组件,单击单元格可编辑逻辑
  8. tensorflow: 图像处理模块 tf.image
  9. 国产计算机设备,国产计算机报价
  10. ES查询结果全局高亮
  11. 电脑开机没反应如何解决?
  12. 搭建自己的存储服务器NAS
  13. 【仿真建模】第四课:AnyLogic入门基础课程 - 轨道交通仿真入门讲解
  14. 网鼎杯半决赛 pwn1
  15. 如何在 MacOS Monterey 菜单栏上显示电池百分比
  16. Vcc、Vee、Vdd、Vss傻傻分不清楚?
  17. C语言程序设计Bjarne特别版,C语言程序设计(2013深色背景).ppt
  18. MTK原厂,MT6771参考设计最新资料
  19. fdsfdsfdsfsd
  20. hibernate的快照更新

热门文章

  1. PHP IE中下载附件问题
  2. BZOJ4314 倍数?倍数!
  3. cookies和session区别
  4. (转)WebSphere的web工程中怎么获取数据源
  5. 08.15《CEP职业发展规划课》
  6. js实现排序去重计算字符次数
  7. MVC-控制器向View传值的三种方法
  8. 使用Flow快速开发Teams小应用
  9. 在Firefox中结合Wolfram Alpha和Google搜索结果
  10. 如何让程序跑起来――第三章