关于中位数的时间复杂度为什么是O(n)

转载自:http://ilovers.sinaapp.com/article/快速排序和寻找中位数


寻找中位数

之所以,起“快速排序和寻找中位数”这个题目,并不是因为寻找中位数的时候使用了快速排序,而是这两个算法使用了一个同一个预处理结构 —— 划分,然后都是递归解决!中位数的也是根据一个数把原来的数划分一下,形成两部分。如果前半部分足够长,就在前部分找,否则在后半部分找!(这不仅适合中位数,实际上适合寻找第 k 大的数!!而 select_middle 其实不是来寻找中位数,是在寻找第 nth 大的数,如果 nth == (n+1)/2,这就是中位数!)

select_middle(int *data, int start, int last, int nth); 说明:data 是数据,start 是起始位置,last 是最后一个数据的下一个位置,nth 指定要寻找第 nth 大的数!划分和快速排序是一模一样的,递归那部分也很简单,如果左半部分长就在左半部分找,如果右半部分长,就在右半部分找剩下的小一部分,比如 nth == 10,如果左边个数是 4,那么就在右边找第 6th 大的数!跟快速排序不同的是,递归只需要针对一部分处理!

复杂度分析

blog 还不能到此结束!O__O"…快速排序写起来不容易,插入排序、冒泡儿排序和简单选择排序,都很容易写出来丫,那 me 们为什么要花这么长时间写个快速排序呢?时间复杂度低?低在哪里?还有就是寻找中位数的程序,不,是寻找第 k 大数的程序,那样写有神马好处?它的复杂度能低于 O(nlogn) 吗?!基于划分的求 nth 大的数的那个程序,最坏情况是 O(n^2),平均是 O(n) ! O__O"…

严格的分析是 me 不喜欢的,但是 me 也不希望太过于“想当然”。先看快速排序 —— 先划分再递归排序。当然有极端情况,有木有!比如 1 2 3 4 5 这样的,每次划分,一部分只有一个数据,另外一部分还是特别多,这样的话,递归要多少次呢?差不多 n 次吧?每递归一次对于数据还很多的那一部分差不多还需要 n 的重新划分吧,那么复杂度上限就是 O(n^2) 有木有!所以快速排序最坏情况的时间复杂度是 O(n^2) 。但是,最坏的情况,要么就是正向有序,要么就是逆向有序,而多数情况,可以想象(就权当是吧),每次划分,分成差不多相等的两部分,然后每一部分再处理,直到每一部分只有 1 个元素为止!如果用递推公式描述复杂度,可以用下图的第三个表示:

T(n) = T(n/2)

T(n) = 2T(n/2)

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

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

如果最初是 8 个元素,第一次划分,大体是 4+4,第二次划分大体是 2+2,第三次是 1+1,递归深度是 log n 有木有!每次重新划分,就按 n 算,时间复杂度 O(nlogn) !那 O(nlogn) 是不是选择中位数的那个程序的时间复杂度呢?

前面的四个式子,实际反应了四种情况,虽然看上去都是分治,然后递归解决!第一种情况是个神马情况呢?意思是处理 100 个数据,和处理其中 50 个数据是一样的!处理 50 个和处理其中的 25 个一样的!而这种划分,竟然没有代价,因为后面没有 + 任何东西!这样的话,想象一下,对于所有的 n,问题都可以转化为处理 1 个数据的情况,而且几乎不增加额外开销,那么复杂度就是 O(1) 丫,有木有!再看第三个式子,反映的是,需要 100 个工作量将 100 化成 50+50 的两部分,每一部分的 50 都要递归求解,所以是 2 倍丫!上面说了,复杂度是 O(nlogn),如果用式子看:T(8) = 2T(4) + 8 = 4T(2) + 2*4 + 8 = 8T(1) + 4*2 + 2*4 + 8 = 8 + 8 + 8 + 8 + 8 = 4*8,更通用有点:

T(2^n) = 2^n + 2 (2^ n-1) + 4() + 8 () + ... + 2^n = (n+1)2^n,也就是 T(n) = (logn+1)n

上面虽然是近似计算,但是已经能反映问题了。还有就是第二个式子和第四个式子反映的是神马情况?第二个式子反映,划分不需要代价,划分成两部分,两部分工作量再加在一起,O__O"… !给人感觉,这样的话,T(n) = n ! 有木有!比如 n = 8,T(8) = 2T(4) = 4T(2) = 8 T(1) = 8 ,这貌似是个线性时间!O__O"…

第四个式子反映,需要 n 步将一个工作量为 n 的划分成两部分,后续只需要处理两部分中的一部分!没有 2 倍关系有木有!将递推式子迭代下去:

T(n) = n + n/2 + n/4 + n/8 + ... + 1 = 2n !O__O"…,

这是神马情况?!线性时间?系数是 2 ?!好吧,也就是说,如果真的能均匀划分的话,上面求中位数的程序的时间复杂度就是 O(n) ! 当然,实际上常量系数要高一些,不会仅仅只有 2 !

后话

上面的程序和复杂度分析是 me 写的,而主要的算法思想等来自数据结构、算法(算法导论)和程序设计语言(c程序设计语言)。对于程序和复杂度分析,或是 blog 有其他错误的地方,不吝赐教丫,O__O"…对了,编程之美上有一道题,这里作为最后一个补充呈献上来:n 个数中,已知某个数出现的次数多于一半,请找出来这个数!为嘛留这个题了,貌似要找的数,一定是中位数有木有!!当然还有其他解法,而且复杂度可以降到 O(n),O__O"…

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值