排序之快速排序
来源:互联网 发布:js select改变事件 编辑:程序博客网 时间:2024/05/16 19:21
排序之快速排序
接着归并排序继续整理,我们知道了归并排序的关键在于归并,分解的部分很微小,因而被称为归并排序,这是一种“先享受后付出代价”的思维方式,同时归并排序还存在一个缺点,那就是它是一个异地排序,即在排序的过程中需要一个额外的存储空间。与之相对的,在1962年由C.A.R Hoare提出了另一种思路的排序算法——快速排序。该算法也被誉为计算史上的伟大算法,应用十分广泛。
快速排序算法的思路是:在把一个序列分开时,不是从中间位置分解,而是按照元素的大小分开为两个一大一小的子序列,即一个子序列的所有元素均大于另一个子序列的所有元素。这样的话,因为这两个子序列之间的相对次序已经正确,因而在合并的时候就不需要任何的时间,这是一种“先付出再享受”的思维方式。显然,快速排序也使用了分治算法,同时快速排序属于原地排序,即不需要额外的存储空间。
快速排序的过程大体分为四步:1.选取分界点 2.分解:把小于分界点的数字全部都移动到分界点的左边,把大于分界点的数字全都移动到分界点右边 3.治之:递归的对两个子序列进行快速排序 4.合并:将排好序的子序列合并为一个大的序列。
快速排序的关键显然在于分解,在这里给出一种可行的做法,先给出代码,再做具体解释:
//获得调整后分界点位置的函数,初始时把分界点置为数组的第一个元素
int AdjustArray(int *s,int l, int r){ inti,j; i=l; j=r; intx = s[l]; while(i< j) { while(i< j && s[j] > x) j--; if(i< j) { s[i]= s[j]; i++; } while(i< j && s[i] < x) i++; if(i< j) { s[j]= s[i]; j--; } } s[i]= x; returni;}
上述代码中,我们假定序列的第一个数字为分界点,首先,我们要先把它的值取出来保存,(即x=s[l]),以便于我们最后把它放到一个合适的位置上。我们还要取两个指针,分别指向序列的头部和尾部,接下来我们先从序列的尾部逐个向前寻找一个比x小的数字,直到找到为止,此时,我们把该数取出,把它的值覆盖到序列的第一个数字;接下来该指针的位置保持不动,把指向头部的指针的位置后移一个单位,并不断向后逐个搜寻一个比x大的数,直到找到为止,此时把该数取出,覆盖到对应的从尾部搜寻到的第一个数字的位置上。至此,第一次交换完成,然后在i<j的前提下,进行循环的操作即可,直到i=j。看明白没?简单的说,就是先取定第一数字为分界点,保存起来,然后从后往前搜寻比x小的数,再从前往后搜寻比x大的数,如此交替进行,同时把找到的值依次覆盖到上一次找到的值的位置上,最后把保存的x值覆盖到i=j的位置上即可。下面举例来看一下:
初始序列: 3 2 4 5 1 6 (先把3赋给x)
第一次搜寻后结果: 1 2 4 5 1 6
第二次搜寻后结果: 1 2 4 5 4 6
第三次搜寻后结果: 1 2 3 5 4 6(此时把3放到合适的位置,以3为分界点的序列,左边均比三小,右边均比三大,此时一次分解完成)
接下来我们要返回该分界点的位置,然后再分别对分界点的左边与右边序列进行递归,直到每个序列只有一个数字时,递归结束,此时该序列即满足有序的要求了。代码如下:
void sort_quick(int *s, int l,int r){ if(l < r) { int i =AdjustArray(s,l,r); sort_quick(s,l,i-1); sort_quick(s,i+1,r); } }
最后,再来blabla有关时间复杂度的问题,不同于归并排序的时间复杂度是稳定的,即在最好、最差或平均情况下归并排序的时间复杂度均为O(nlogn)。快速排序在最坏情况下时间复杂度为O(n^2)在最好和平均情况下时间复杂度均为O(nlogn),而且可以证明,只要在分解时不产生空的子序列,则不管产生的两个子序列长度差异有多大,哪怕是1%对99%,其时间复杂度仍未O(nlogn),也就是说快速排序具有很强的韧性,只要给他一丁点的机会,它都会取得最好的结果,这也正是它的优势所在。(注:时间复杂度的证明有兴趣可以具体证明)
- 排序之快速排序
- 排序之 快速排序
- 排序之快速排序
- 排序之------快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之-----快速排序
- 排序之快速排序
- 排序之快速排序
- 排序之快速排序
- 代码面试最常用的10大算法
- HTML Entities & Charset & URL Encode
- Android布局之LinearLayout与TableLayout的嵌套使用
- 黑马程序员:查表法解决进制转换
- 学习笔记_web——表单验证
- 排序之快速排序
- 使用myeclipse搭建struts2环境
- 10 个 lsof 命令行的使用示例
- 【LeetCode】Decode Ways
- HDU - 3450 Counting Sequences
- 关于 win8.1 激活问题
- Android WebView自定义处理错误页面显示(404等)
- NGUI 基础 -- 功能组件
- 网络负载均衡