排序算法之快速排序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法之快速排序相关的知识,希望对你有一定的参考价值。
快速排序是一种基于分治技术的重要排序算法,顺便提一下什么是分治:
分治法是按照以下方案工作:
1.将一个问题划分为同一类型的若干子问题,子问题规模相同或相近
2.对这些子问题进行求解(一般使用递归方法)
3.最后合并子问题的解,得到原问题的答案
知道了什么是分治法,就很好理解快速排序算法了。因为快排是按照元素的值对它们进行划分,即对于一个数组A,对数组中的元素重新排列,使得A[s]左边的元素都小于或等于A[s],所有A[s]右边的元素都大于等于A[s]。
在一次划分之后,A[s]所在的位置就是它在我们想得到的有序数组中的最终位置,接下来我们只需要使用相同的方法对A[s]前和A[s]后的子数组分别进行排序,直到原数组有序。
感受一下算法伪代码
Quicksort(A[l...r])
//用Quicksort对子数组进行排序
//输入:数组A[0...n-1]中的子数组A[l...r],l和r分别代表子数组的左右下标
//输出:非降序排列的子数组A[l...r]
if l<r
s ← Partition(A[l...r] ) //s表示数组的分裂位置
Quicksort(A[l...s-1] )
Quicksort(A[s-1...r] )
Java实现快排
public static void quicksork(int[] array){ //该函数的作用是直接输入一个数组即可返回排序结果 quickSort(array,0,(array.length-1)); } //利用递归思想进行排序 static void quickSort(int[] ary,int low,int high){ if(low<high){ int segment = partition(ary,low,high); quickSort(ary,low,segment-1); quickSort(ary,segment+1,high); } } //找到分割元素最终的位置 static int partition(int[] arr,int low,int high){ int pivot = arr[low]; while(low<high){ while(low<high && pivot<=arr[high]) high--; arr[low] = arr[high]; while(low<high && pivot>=arr[low]) low++; arr[high] = arr[low]; } arr[low] = pivot; return low; }
个人觉得最快理解上述过程的方法是自己在纸上写下一组数列,然后按照程序走一遍,要比盯着代码苦想更简单,毕竟递归方法对于我这种菜鸟来说比较抽象。
算法复杂度分析
1.最优情况:所有的分割点都位于相应子数组的中点,此时键值的比较次数为:
Cbest(n) = 2Cbest(n/2) + n ,Cbest(1)=0
根据主定理,此时的算法复杂度为:O(nlog2n)
2.最坏情况:所有的分割点都趋于极端,即分割点左右的两个子数组有一个为空,而另外一个子数组仅比原数组少一个元素,此时的键值比较次数为:
Cworst(n) = (n+1)+n+...+3,此时算法复杂度为:O(n^2)
3.平均效率:平均情况下的效率才能体现快排的实用性。算这个平均效率有点麻烦,所以直接上结果:
Cavg(n) = 2nlnn = 1.39nlog2n
由此可见,快排在平均情况下仅比最优情况多执行39%的操作,它的最内层循环效率很高,使得在处理随机排列的数组时速度要比合并排序快。
快速排序的优化
1.更好的中轴选择方法:三平均划分法。它以数组最左边、最右边和最中间的元素的中位数作为中轴
2.当子数组足够小时,该用插入排序方法,或者不再对小数组排序,而是在快排结束后在使用插入排序的方法对整个几乎有序的数组进行排序
快速排序的缺点
快排不稳定,而且它需要一个堆栈来存储那些还没有被排序的子数组的参数。它的堆栈大小最小为O(log n),但还是要比堆排序O(1)的空间效率差。
本文出自 “卫莨” 博客,请务必保留此出处http://acevi.blog.51cto.com/13261784/1980772
以上是关于排序算法之快速排序的主要内容,如果未能解决你的问题,请参考以下文章