快速排序算法的时间复杂度分析[详解Master method]

经常听人谈起各种排序算法的时间复杂度,这个是O(n2)的,那个是O(n)的,这些人讲起来可谓滔滔不绝,但是你停下来问问他为什么这个是这个复杂度,他是怎么算出来的?往往没几个人能说出来。这个是一个浮躁的社会,大家都追求速度,到处复制,粘贴代码,拿人家的代码跑一便,就说自己会了这个,会了那个..

也许有人觉得算法分析的太深没有用,但是笔者认为,有时候了解细节很重要,比如快速排序算法的时间复杂度,有时候是O(nlgn), 有时候就是O(n2), 在你不知道自己数据特性的情况下,很难选择是否使用快速排序,因为他并不总是最快的。

说了些没用的,让我们进入正题吧:

为了分析快速排序的时间复杂度,请先看下面的主定理:

主定理: T [n] = aT[n/b] + f (n)

其中 a >= 1 and b > 1 是常量 并且 f (n) 是一个渐近正函数, 为了使用这个主定理,您需要考虑下列三种情况:

想必大家都知道快速排序的过程,如果对这个过程有什么不了解,请参考下文:

http://www.cnblogs.com/pugang/archive/2012/06/27/2565093.html

快速排序的每一次划分把一个 问题分解成两个子问题,其中的关系可以用下式表示:

T[n] = 2T[n/2] + O(n) 其中O(n)为PARTITION()的时间复杂度,这里是分解成两个相等规模的子问题,对比主定理,

T [n] = aT[n/b] + f (n)

我们的快速排序中:a = 2, b = 2, f(n) = O(n)

那么为什么还有最坏情况呢?

考虑如下极端情况,

T[n] = T[n-1] + T[1] + O(n),这里是分解成一个n-1规模的子问题和一个1规模的子问题

问题来了,这一次的划分白玩了,划分之后一边是一个,一边是n-1个,这种极端情况的时间复杂度就是O(n2).

快排代码

+(NSInteger)partition:(NSMutableArray *)arr

{

NSNumber *split = arr.firstObject;

NSInteger i = 0;

NSInteger j = arr.count-1;

while (i!=j) {

while ([arr[j]integerValue]>=split.integerValue) {

j--;

}

while ([arr[i]integerValue]<=split.integerValue) {

i++;

}

if (i>=j) {

break;

}

[self swapeArr:arr index:i andIndex:j];

}

NSNumber *num = arr[j];

arr[j] = split;

arr[0] = num;

return j;

}

+(NSInteger)partition1:(NSMutableArray *)arr

{

NSNumber *firstN = arr.firstObject;

NSInteger i = 0;

NSInteger j = 1;

NSInteger len = arr.count;

while (j<len-1) {

j++;

if ([arr[j]integerValue]<[firstN integerValue]) {

[self swapeArr:arr index:j andIndex:++i];

}

}

[self swapeArr:arr index:i andIndex:0];

return i;

}

快速排序是一个最差时间复杂度为O(n²)的排序算法,这种情况通常出现在选择的轴值(pivot)不能将数组划分为两个长度相等的子数组的时候,比如数组逆序排列的时候,如果选择第一个数作为轴值,划分的子数组的大小分别为0和n-1,此时算法的性能最差。

一个较好的办法是“三数取中”,查看当前数组的第一个、中间一个和最后一个位置的数组,取其中位数,以此来降低轴值选择得不好的可能性。

//将开头、中间、结尾位置的中间一个元素交换到开头

+(void)swap:(NSMutableArray *)arr start:(NSInteger)start end:(NSInteger)end

{

var mid = Math.floor(start+(end-start)/2);

if(this[start]>this[end])

{

this.swap(start,end);

}

if(this[mid]>this[end])

{

this.swap(mid,end);

}

if(this[mid]>this[start])

{

this.swap(mid,start);

}

}

//先进行三数取中,其余地方不变,性能提升非常显著

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 今天是运动过后,非常疲惫的一天,然后我给自己非常多的时间休息,跟自己的身体非常非常好的相处,拥抱她,因为她是我的功...
    茶语丝享阅读 194评论 0 0
  • “孩子的妈妈呢?”这是过去一周我被问到的最多的问题,无论是巧遇的中国旅客,或者是当地人。 必须承认,人类男性在原始...
    自证预言的Sam阅读 1,578评论 0 1
  • 今天早上的分析问题冥想意识昏沉、散乱,意识到是自己曾打扰过他人的宁静,回顾过往,马上想到昨天早上的冥想中要帮助(升...
    福田妙果_2114阅读 255评论 0 0