前言
排序算法很是多,几乎每一个人学的第一个排序算法都是冒泡算法,可是冒泡算法的时间复杂度是很高的,是一种效率很低的算法。而目前来讲,快速排序是相对比较好的一种算法:实现难度低,时间复杂度低。但快速排序在一些状况下也可能出现退化到和冒泡算法同样的时间复杂度,因此须要读者注意一下,下面我会讲到。那么接下来就来看看这个算法。java
笔者才疏学浅,有不一样观点欢迎评论区或私信讨论。如需转载请留言告知。
另外欢迎阅读笔者的我的博客一只修仙的猿的我的博客,更精美的UI,拥有更好的阅读体验。git
算法思路
递归算法的思路其实很简单:算法
- 从数据中取出一个数,即为mid
- 比mid小的数放在左边,比mid大的数放在右边
- 最后把mid放在中间
- 对左右两边的子数组进行递归排序,直到只剩下一个元素则所有排序完成。
具体的实现思路咱们举一个例子:数组
如今有一个数组:dom

这里细心的读者会发现诶第三个数怎么后面有一点,这个不是手滑打出来的。而是为了证实在排序的过程当中,两个3的顺序是否会发生颠倒,从得出这是不是一个稳定的排序。spa
-
首先咱们取出一个数,当成哨兵。这里咱们取第一个数
5
当成哨兵。而后咱们把这个数和最后一个数交换。为何须要交换呢?这样咱们就不须要去额外设置一个变量存储哨兵了。如图:code -
接下来咱们设置两个变量:
min
和max
们分别表示比mid小的数的最大的下标,和比mid大的数最小的坐标。排序举个例子以下图:递归
-
接下来咱们从左边开始,若是
min
指向的数比哨兵小,则min = min+1
,不然则停下来。执行完以后以下图:接口 -
而后从右边开始,若是
max
指向的数大于等于哨兵,则max = max-1
,不然则停下来,执行完成以后以下图: -
而后把min和max指向的数字进行交换:(这里能够看到两个3的顺序发生了颠倒,因此这是一个不稳定的排序)
-
重复3,4,5步骤直到
min==max
-
把下标为
min
的数字和哨兵进行交换,至此一轮的排序已经完成: -
对先后的子数组进行递归排序。完成排序。
快速排序的核心就是利用递归分治的思路来下降时间复杂度。若是咱们每次都恰好选到中位数,那么递归树的高度就是logn
(这里的n表明元素的个数),每一层递归都须要遍历一次数组,那么时间复杂度最好的状况就是:
O(logn)
可是,若是每次都取到最小或者最大的数,那么快排的递归树高度则为n,那么他的时间复杂度将退化为:
O(n^2)
因为只须要常量空间,因此空间复杂度为:
O(1)
代码示范
下面使用java语言作一个规范。接口参数为:整型数组,数组的开始下标,数组的结束下标。(因多是子数组因此须要下标参数)
private void fastSort(int[] nums,int start,int end) { // 终止条件:start>=end if(start>=end) return; // 记录原始的下标 int startRow = start; int endRow = end; // 采用随机数获取下标,能够下降退化到n^2的几率 int random = new Random().nextInt(end-start)+start; // 交换两个数 swap(nums,random,end); // 重复上述的3,4,5步骤 while(start<end){ // 记得这里的每一步都必须判断start<end while( nums[start]<nums[endRow] && start<end ){ start++; } while( nums[end]>=nums[endRow] && start<end ){ end--; } // 若是相同则把哨兵放到中间,排序结束 // 不然start和end交换位置,继续循环 if(start==end) swap(nums,start,endRow); else{ swap(nums,start,end); } } // 最后对子数组进行递归排序 paixu(nums,startRow,start-1); paixu(nums,start+1,endRow); } // 交换数组中的两个数 private void swap(int[] nums,int one,int two){ int temp = nums[one]; nums[one] = nums[two]; nums[two] = temp; }