【算法】5 快速排序

(由于markdown的草稿箱十分“危险”所以就不存在草稿箱了,直接将这篇没有完成的博客发表出来了,今天晚些时候和明天会继续修改)

快速排序Quicksort由Tony Hoare在1962年发明。 这是一个分治算法,而且它就在原地排序。 所谓原地排序,就是指在原来的数据区域内进行重排,就像插入排序一般。而归并排序就不一样,它需要额外的空间来进行归并排序操作。为了在线性时间与空间内归并,它不能在线性时间内实现就地排序,原地排序对它来说并不足够。而快速排序的优点就在于它是原地的,也就是说,它很节省内存。

由于快速排序采用了分治算法,所以:

一、分解:本质上快速排序把数据划分成几份,所以快速排序通过选取一个关键数据,再根据它的大小,把原数组分成两个子数组:第一个数组里的数都比这个主元数据小或等于,而另一个数组里的数都比这个主元数据要大或等于。

二、解决:用递归来处理两个子数组的排序。 (也就是说,递归地求上面图示中左半部分,以及递归地求上面图示中右半部分。)

三、合并:有了上面这两步就足够了,并不需要合并。因为上图中的两个数组分别排序好后整体也排序好了。

所以快速排序的主要思想是递归地划分。

当然最重要的是它的复杂度是线性的,也就是Θ(n)个划分的子程序。

Partition(A,p,q)   // A[p,..q]
1   x=A[p]   // pivot=A[p] 主元
2   i=p
3   for j=p+1 to q
4       do if A[j]<=x
5          then i=i+1
6             exch A[i]<->A[j]
7   exch A[p]<->A[i]
8   return i // i pivot 

这就是划分的伪代码,基本的结构就是一个for循环语句,中间加上了一个if条件语句。

刚开始时i等于p,j等于p+1。在这个循环中查找i下标的数据,如果它比x大,那就将其存放到“>=x”区域并将j加1后进行下一次循环。而如果它比x小,那就要做些动作来维持循环不变量了。将i的下标加1后将下标i对应的数据和下标j所对应的数据互换位置。然后再移动区域的界限并开始下一次循环。

那么这个算法在n个数据下的运行时间大约是O(n),因为它几乎把每个数都比较了一遍,而每个步骤所需的时间都为O(1)。

上面这幅图详细的描述了Partition过程,每一行后也加了注释。

有了上面这些准备工作,再加上分治的思想实现快速排序的伪代码也是很简单的。

Quicksort(A,p,q)
1   if p<q
2     then r<-Partition(A,p,q)
3          Quicksort(A,p,r-1)
4           Quicksort(A,r+1,q) 

我们会这样初始调用快速排序:Quicksort(A,1,n) 。

分析

假设所有元素都不同。我们将会证明当你有重复元素时这些代码运行的状况并不好。

最坏情况分析:

1)输入的元素以及排序或逆向排序

2)每个划分的一边都没有元素

T(n)=T(0)+T(n?1)+\Theta(n)=Θ(1)+T(n?1)+Θ(n)=Θ(n?1)+Θ(n)=Θ(n2)

等差级数,就和插入排序一样。它并不比插入排序快。而快速排序仍旧是一个优秀的算法,这是因为在平均情况下它已经很高效。

我们为最坏情况花一个递归树。

这是一课高度不平衡的递归树,图中左边的那些T(0)的运行时间都为Θ(1),而总共有n个。

所以算法的中运行时间为:

T(n)=Θ(n)+Θ(n2)=Θ(n2)

最优情况分析:

当Partition将数组分为n/2和n/2两个部分时是最高效的。此时有:

T(n)=2T(n/2)+Θ(n)=Θ(nlgn)

随机化快速排序的好处:

1)其运行时间不依赖与输入序列的顺序

2)无需对输入序列的分布做任何假设

3)没有 一种特别的输入会引起最差的运行情况

4)最差的情况由随机数产生器决定

时间: 2024-08-03 09:31:13

【算法】5 快速排序的相关文章

排序算法 之 快速排序

快速排序是基于分治思想的一种排序算法,就像该方法的名字一样,速度比较快,所以叫做快速排序:它的平均时间复杂度为O(N*logN),最坏时间复杂度为O(n2),由于快速排序在序列元素数量多的时候速度比较快,所以很多语言内置的排序方法也是用快速排序实现的.快速排序也有很多优化的版本,比如在排序时基数的选择等等-下面就说一下一般的快速排序的实现. 基本思想: 快速排序的基本思想就是,先从待排序的序列中任选一个元素作为基数,然后将序列中的其他小于基数的元素放在基数的左边,大于或等于基数的元素放在基数的右

算法:快速排序

原理: 在一个数组中,选一个元素(通常是第一个元素或者数组的中间元素)与剩余的其它元素进行比较:建立两个分组(左组和右组),比当前元素小的放在左组,比当前元素大的放在右组.这样一来,将左组,中间组合右组合并起来就形成一个已经“排好序”的数组.实际上,左组和右组中的元素并不一定已经排好序,调用自己去排序,只有左右数组的元素个数大于1,就需要排序,如果元素个数等于一个,就不再调用函数. 使用递归实现(步骤): 1.实现从数组中取出一个元素:将小的放左边数组,大的放右边数组,最后返回合并结果 2. 

十大基础实用算法之快速排序和堆排序

快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来. 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists). 算法步骤: 1 从数列中挑出一个元素,称为 "基准"(pi

经典白话算法之快速排序

[分析] [伪代码] [运行过程] [代码] /********************************* * 日期:2014-04-01 * 作者:SJF0115 * 题目:快速排序 **********************************/ #include <iostream> #include <stdio.h> using namespace std; //对子数组array[p...r]就地重排 int Partition(int array[],i

啊哈!算法之快速排序与桶排序

啊哈!算法之快速排序与桶排序 1.快速排序算法 快速排序由 C. A. R. Hoare(东尼·霍尔,Charles Antony Richard Hoare)在1960 年提出,之后又有许多人做了进一步的优化.在数列种随机找出一个基准数,因为数列是杂乱的,所以取首项为基准数.从后往前找到比基准数大的位置,再从前往后找到比基准数小的位置,交换元素:右游标向前移动与左游标向后移动,它们相遇时用基准数的位置与相遇的位置交换.此时原来数列以相遇的位置被划分为了两个需要排序的数列,再次执行上述过程:当左

排序算法 一 快速排序

算法:快速排序 思想:通过一趟排序,确定了一个data的最终确切位置.(通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列)  特点:不稳定算法. 代码实现:

算法之快速排序

这里简单的介绍下快速排序的伪代码实现和示意图: QuickSort(A,p,r) if p<r q=Partition(A,p,r) QuickSort(A,p,q-1) QucikSort(A,q+1,r) 算法的关键部位为Partition函数的实现,它实现了对数组A(p,r)的原址排序: Partition(A,p,r) x=A[r] i=p-1 for j=p to r-1 if a[j]<=x i=i+1 exchange a[i] with a[j] exchange A[i+1]

常用排序算法之——快速排序(C语言+VC6.0平台)

经典排序算法中快速排序具有较好的效率,但其实现思路相对较难理解. #include<stdio.h> int partition(int num[],int low,int high) //以key为基准 将待排数列“高”.“低 ”两部分,“高”部分的所有数据比key大,“低”部分的数据都比key小 { int left,right,key; left=low;right=high;key=num[low]; while(left<right) { while(left<right

常用排序算法之——快速排序

快速排序的原理: 首先找一个标兵值,等于某一个元素值:遍历数组,将数组分为小于标兵值和大于标兵值的两部分:然后分别对两个部分采用快速排序,递归. 分开数组时,维持一个指针,指向已找到小部分的最后一个元素:一个指针用于遍历. 不稳定排序算法.当数组已经有序时,时间复杂度最差,为O(N2),平均.最优情况下都为O(N lgN). 代码如下: 1 #include <iostream> 2 using namespace std; 3 4 template<typename T> 5 v

排序算法系列——快速排序

记录学习点滴 快速排序算法是一种很有趣的算法,短小精悍,性能强劲,对于大部分情况都可以胜任,但对极端环境难以应付. 快速排序我理解为:这是一个“以自我为中心的”+“分治法”思想的算法. 分治法不必多说,化繁为简,那就是逐个击破. 那什么是“以自我为中心”?顾名思义,就是每次都一个“我”,每个人都要围绕“我”行事,比“我”小的都去左边站着,比“我”他大的都去右边站着,而且“我”不去关心每一边都有谁,反正你没“我”大或者小就行.一旦“我”落位了妥帖了,“我”就不动了.然后再在左右两边分别产生新“我”