一、实验问题简述及分析
- 实验问题:
求数组中第K小的元素.
- 问题实例:
通常我们需要在一大堆数中求前 K 大的数. 比如在搜索引擎中求当天用户点击次数排名前1000的热词; 在文本特征选择中求词频值从大到小排名的前k名问题.该问题也被称作TOP-K问题.
- 常规算法存在的问题:
常规算法即指利用快速排序算法进行排序,快速排序的平均时间复杂度为O(nlogn),但存在时间复杂度为O(n²)的情况. 而且其实只需要前K小/大的数即可,不需要对其他多余的数进行排序,快速排序算法浪费了多余的排序时间.
- 实验过程简述及时间复杂度分析
1. BFPTR算法
BFPTR算法,又称中位数算法. 根据算法分析,它的最坏时间复杂度最差仅为O(n).其与常规方法(即快速排序算法)差距仅在每次排序中选取的排序数字的有无规定上.在常规算法中,排序数字的选取是随机的,而在BFPRT算法中,先将数组每五个相邻的分成一组,如果最后有余下不足五个的也同样分为一组,将每组当中的中位数构成一个新数组,再求得新数组的中位数,作为选取的比较数字. 由此递归求解,保证每一次的比较数字都在数组的中间位置,最终将时间复杂度减小为O(n).
- 本实验步骤简述
①将原数组分组,分为五个一组,最终若有剩余不足五个的情况可以也算作一组.
②对得到的每个小组内部进行排序,取其中位数,存放在新数组中.
③找出新数组的中位数,并以该数作为比较数字m*进行partiton过程,即将比m*小的数字存在S1中,比m*大的数字放在S2中.
④判断情况一:若此时k恰好等于|m*|,输出
判断情况二:若此时k>|m*|,缩短递归 BFPRT(a, low, m.position-1, int key)
判断情况三:若此时k<|m*|,缩短递归 BFPRT(a, m.position+1,high, int key)
图1 BFPRT算法示意图
- 算法的时间复杂度分析
BFPRT算法的最坏时间复杂度为O(n). 设T(n)为时间复杂度,那么很容易有如下公式 :
(1)
② ③
其中 ① 来自寻找分组中的中位数, ② 则来自BFPRT()过程,最初选择的m*首先大于中位数数组中的1/2,即总数的(1/2)*(n/5),而在这n/10的数中,它们又一定大于等于原5个小组中的3个数字,因此,在最坏的情况下,每次都选到7/10的部分 ③c*n来自其他过程,如排序.
- 实验问题思考及新尝试:
在算法讲解中一直使用5为数组分组,但是为什么不使用其他数字进行分组,我在试验中用程序进行了比较.
因为偶数分组不方便取中位数,因此作不考虑 .在实验中,我选择7和9对原数组进行分组,发现在数组长度相同的情况下,以5分组的计算时间普遍好于以7、9进行分组的情况.
分析原因:
- 首先,每组的元素越多,数据的最坏情况越坏:比如7个一组,数据最坏被4:10分即2:5分,相比3:7的情况比例更高,更加不均匀.
- 会造成递归次数增多.
下图分别为200点情况下取5、7、9为分组的BFPRT算法结果
5分组
7分组
9分组
经过比较可以看出,5分组算法计算时间效率普遍最高,运行时间较快。
下图分别为500点情况下取5、7、9为分组的BFPRT算法结果
5分组
7分组
9分组
同样,经过比较可以看出,5分组算法计算时间效率普遍最高,运行时间较快。