看动画学算法之:排序-快速排序
简介
快速排序也采用的是分而制之的思想。那么快速排序和归并排序的区别在什么地方呢?
归并排序是将所有的元素拆分成一个个排好序的数组,然后将这些数组再进行合并。
而快速排序虽然也是拆分,但是拆分之后的操作是从数组中选出一个中间节点,然后将数组分成两部分。
左边的部分小于中间节点,右边的部分大于中间节点。
然后再分别处理左边的数组合右边的数组。
快速排序的例子
假如我们有一个数组:29,10,14,37,20,25,44,15,怎么对它进行快速排序呢?
先看一个动画:
我们再分析一下快速排序的步骤。
我们选择的是最左边的元素29作为中间点元素,然后将数组分成三部分:[0, 14, 15, 20, 25],[29],[44, 37]。
中间节点29已经排好序了,不需要处理。
接下来我们再对左右分别进行快速排序。最后就得到了一个所有元素都排序的数组。
快速排序的java代码实现
我们先来看最核心的部分partition,如何将数组以中间节点为界,分成左右两部分呢?
我们的最终结果,是要将array分割成为三部分。
首先我们选择最左侧的元素作为中间节点的值。然后遍历数组中的其他元素。
假如m=middleIndex,k=要遍历的元素index
考虑两种情况,第一种情况是数组中的元素比中间节点的值要大。
这种情况下,m不需要移动,k+1继续遍历即可。
第二种情况下,数组中的元素比中间节点的值要小。
因为m左边的元素都要比中间节点的值要小,所以这种情况下m需要+1,即右移一位。
现在m+1位置的元素要么还没有进行比较,要么就是比中间节点的值要大,我们可以巧妙的将m+1位置的元素和k位置的元素互换位置,这样仍然能够保证m左侧的元素要比中间节点的值要小。
将上面的分析总结成java代码如下:
private int partition(int[] array, int i, int j) { //选择最左侧的元素作为中心点,middleValue就是中心点的值 int middleValue = array[i]; int middleIndex = i; //从i+1遍历整个数组 for (int k = i+1; k <= j; k++) { //如果数组元素小于middleValue,表示middleIndex需要右移一位 //右移之后,我们需要将小于middleValue的array[k]移动到middleIndex的左边, // 最简单的办法就是交换k和middleIndex的值 if (array[k] < middleValue) { middleIndex++; //交换数组的两个元素 swap(array, k , middleIndex); } //如果数组元素大于等于middleValue,则继续向后遍历,middleIndex值不变 } // 最后将中心点放入middleIndex位置 swap(array, i, middleIndex); return middleIndex; }
最后我们需要将最左侧的元素和中间节点应该在的index的元素互换下位置,这样就将中间节点移动到了中间位置,并返回中间位置。
再来看下divide的代码:
public void doQuickSort(int[] array, int low, int high) { //递归的结束条件 if (low < high) { //找出中心节点的值 int middleIndex = partition(array, low, high); //数组分成了三部分: // a[low..high] ~> a[low..m–1], pivot, a[m+1..high] //递归遍历左侧部分 doQuickSort(array, low, middleIndex-1); // a[m] 是中心节点,已经排好序了,不需要继续遍历 //递归遍历右侧部分 doQuickSort(array, middleIndex+1, high); log.info("QuickSort之后的数组:{}",array); } }
divide的代码就很简单了,找到中间节点的位置之后,我们再分别遍历数组的左右两边即可。最后得到排好序的数组。
随机快速排序的java实现
上面的例子中,我们的中间节点的选择是数组的最左元素,为了保证排序的效率,我们可以从数组中随机选择一个元素来作为中间节点。
private int partition(int[] array, int i, int j) { //随机选择一个元素作为中心点,middleValue就是中心点的值 int randomIndex=i+new Random().nextInt(j-i); log.info("randomIndex:{}",randomIndex); //首先将randomIndex的值和i互换位置,就可以复用QuickSort的逻辑 swap(array, i , randomIndex); int middleValue = array[i]; int middleIndex = i; //从i遍历整个数组 for (int k = i+1; k <= j; k++) { //如果数组元素小于middleValue,表示middleIndex需要右移一位 //右移之后,我们需要将小于middleValue的array[k]移动到middleIndex的左边, // 最简单的办法就是交换k和middleIndex的值 if (array[k] < middleValue) { middleIndex++; //交换数组的两个元素 swap(array, k , middleIndex); } //如果数组元素大于等于middleValue,则继续向后遍历,middleIndex值不变 } // 最后将中心点放入middleIndex位置 swap(array, i, middleIndex); return middleIndex; }
上面的代码,我们在分区的时候,先选择出一个随机的节点,然后将这个随机的节点和最左侧的元素交换位置,后面的代码就可以重用上面的QuickSort的代码逻辑了。
快速排序的时间复杂度
从上面的分析我们可以看出,每次分区的时间复杂度应该是O(N),而divide又近似二分法,所以总的时间复杂度是O(N logN)。
本文的代码地址:
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/algorithm-quick-sort/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
八种经典排序算法总结,妈妈再也不用担心我不会了
思维导图 文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary 前言 算法和数据结构是一个程序员的内功,所以经常在一些笔试中都会要求手写一些简单的排序算法,以此考验面试者的编程水平。下面我就简单介绍八种常见的排序算法,一起学习一下。 一、冒泡排序 思路: 比较相邻的元素。如果第一个比第二个大,就交换它们两个; 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素就是最大的数; 排除最大的数,接着下一轮继续相同的操作,确定第二大的数... 重复步骤1-3,直到排序完成。 动画演示: 实现代码: /** * @author Ye Hongzhi 公众号:java技术爱好者 * @name BubbleSort * @date 2020-09-05 21:38 **/ public class BubbleSort extends BaseSort { public static void main(String[] args) { BubbleSort sort = new BubbleS...
- 下一篇
写在 Dubbo go 的第五年
作者 |于雨 阿里巴巴云原生公众号后台回复“915”即可查看 dubbogov1.5.1项目管理图清晰大图! 引语 dubbogo 项目已进入第五个年头。 项目发展的前两年,我们把 hessian2 协议库、网络库和整体基础框架搭建一番。从 2018 年项目被 Dubbo 官方接纳开始,依托阿里平台,社区开始形成并快速发展。与社区同学们齐心合力之下,如今全面兼容 Dubbo v2.7.x 的 Dubbo-go v1.5.1 已经发布。 立项 一个项目整体必须提炼出核心目标,指明其存在的意义和价值。有了初心,项目发展过程中产生困惑时,才能明确答复 “我是谁?从哪里来?到哪里去”。 1. dubbogo dubbogo 项目有其自身的 milestone 要求,大致规划了每个阶段的关键里程碑,在项目发展初期仅仅是实现 Dubbo 的某个功能,但在发展过程中会不断结合当下的技术发展潮流,不断修正其未来发展方向。 其发版计划是通过“开发当前版本、规划新版本、根据反馈修正新版本”的模式定义当前版本的开发内容和下一个版本的发展方向。每次发版后会根据社区使用反馈对下一代的发展目标进行修正。 站在吃瓜...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2全家桶,快速入门学习开发网站教程
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8安装Docker,最新的服务器搭配容器使用
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2更换Tomcat为Jetty,小型站点的福音