BFPRT算法
BFPRT算法
算法目的
在无序数组中找到第K小的数,时间复杂度O(N)
基于partition思路的算法
和快速排序中partition的思想有些相像。比如说我们要在长度为1000的数组中找到第n小的数,于是我们现在数组中随机找一个数进行partition的过程,小于它的放左边,等于它的放中间,大于它的放右边。完成后的情况如下图所示,等于区域范围为500-600
因为我们要找第n小的数,因此:
- 如果500 < n < 600,因此这个第n小的数就在等于区域,即我们进行partition的基准元素。
- 如果n < 500, 那么这个第n小的数肯定在小于区域,我们继续对小于区域进行partition过程。
- 如果n > 600,那么这个第n小的数肯定在大于区域,我们继续对大于区域进行partition过程。
该算法的平均时间复杂度基于概率,其长期期望为:O(N)
BFPRT算法
BFPRT算法的时间复杂度不基于概率,严格O(N)
BFPRT与上述算法的唯一区别在于:选择partition基准元素的这一步不是随机选取的。一旦选好了这个基准元素,之后的过程和上述算法相同。
选择基准元素的方式:
- 先将长度为N的数组进行分组,每5个元素一组
- 在每一组的组内进行排序(组间不排序),也即将每一个长度为5的小组排序,小组内排序的时间复杂度为O(1),一共有N/5个小组,因此这一步的时间复杂度为O(N)
- 将每一小组的中位数拿出来,构成一个长度为N/5的新数组
- 递归调用BFPRT算法,找到新数组中的中位数num
- 将这个元素num作为基准元素,进行partition
为什么要这么选基准元素:
num在长度为N/5的新数组中是中位数,因此这个新数组中有N/10个数比num大,这N/10个数中的每个数a在它的原数组里又是中位数,即长度为5的原数组中有2个数比a大。因此,所有比num大的数统计起来,至少有$3N/10$个,也即最多有$7N/10$个数比num小.
同理,如果统计比num小的数,发现至少也有$3N/10$个数比它小,即最多有$7N/10$个数比num大.
那么我们用这个num做划分进行partition,会发现最多就有$7N/10$个数比它大,也最多有$7N/10$个数比它小。因此,下一步partition的范围最多也就是$7N/10$。
代码
选基准元素的代码部分
1 |
|
获得基准元素pivot后,以它为基准进行partition操作,并进入BFPRT流程。
1 |
|