BFPRT算法C++实现

BFPRT算法是求数组中第k小(大)的数,时间复杂度为O(n)
其算法思路与快排类似。
只不过选择标杆值不一样,BFPRT是选择中位数组的中位数来当pvalue,而快排是随机选择。
选择之后,进行递归调用,
具体实现,请看代码:
#ifndef BFPRT_H
#define BFPRT_H
//BFPRT算法是在不排序的情况下,找到第k小,或者第k大的数
//这里以第k小的数为例,进行算法实现
//1、首先对数组进行分组,5个为1组,最后不足5个的为1组,一共有num/5或者1+num/5组
//2、对每组进行插入排序,排好序后,取每个组的中位数,组成中位数数组mediums[n]
//3、然后,求出mediums数组中的上中位数pvalue,这里递归调用BFPRT算法
//求mediums数组中的上中位数,就是求该数组中,第mediums.size()/2个数
//4,此时pvalue,就是得到的划分值。然后进行与快排里面的partition函数一样的划分区域
//小于pvalue的在小于区,等于的在等于区,大于的在大于区。如果要求得第k小的数,在等于区
//也就是说k-1作为下标,在等于区的下标范围内,那么直接返回pvalue,
//如果k-1小于等于区的左边界下标,说明在小于区内,继续partition,同理,大于区内也一样。
//这里,因为确定了在小于区,就不用管大于区,所以递归只走一边,时间复杂度比快排小

#include
#include
using namespace std;
#define MIN(x,y) x &a, int l, int r);//插入排序
int getmedium(vector&a, int l, int r);//获取数组的上中位数
int getmidofmedium(vector&a, int l, int r);//获取中位数组的中位数
int findKthMin(vector &a, int l, int r, int i);//找数组中第i小的数
vector partition(vector &a, int l, int r,int pvalue);//利用pvalue进行划分区域
int KthMin(vector &a, int k);//数组中第k小的数
void swap(int &a, int &b)//交换函数
{
	int temp = a;
	a = b;
	b = temp;
}
void InsertSort(vector&a, int l, int r)//插入排序
{
	if (l = r)
		return;
	for (int i = l + 1; i <= r; ++i)
	{
		for (int j = i; j > l; --j)
		{
			if (a[j - 1] > a[j])
				swap(a[j], a[j - 1]);
		}
	}
}
int getmedium(vector&a, int l, int r)//获取数组的上中位数
{
	InsertSort(a, l, r);
	return a[l + (r - l) / 2];
}
int getmidofmedium(vector &a, int l, int r)//获取中位数组的中位数
{
	int num = r - l + 1;//总数目
	int offset = num % 5 ==0? 0 : 1;
	vectormedium(num / 5 + offset);//建立中位数数组
	for (int i = 0; i != medium.size(); ++i)
	{
		int ibegin = l + i * 5;//从l开始,5个一组。分组
		int iend = ibegin + 4;
		medium[i] = getmedium(a, ibegin, MIN(iend, r));//把每个小组的中位数填入中位数组中
	}
	return findKthMin(medium, 0, medium.size() - 1,medium.size()/2);//返回中位数组的中位数
}

int findKthMin(vector &a, int l, int r, int k)//求第k小的数
{
	if (l == r)
		return a[l];//数组中就一个数
	int pvalue = getmidofmedium(a, l, r);//pvalue是数组的中位数组的中位数,
	vectorpvaluerange = partition(a, l, r,pvalue);//利用pvalue来划分partition
	if (k >= pvaluerange[0] && k <= pvaluerange[1])//pvaluerange数组中的元素是等于pvalue的两个下标。
		return pvalue;
	else if (k < pvaluerange[0])
		return findKthMin(a, l, pvaluerange[0] - 1, k);
	else
		return findKthMin(a, pvaluerange[1] + 1, r,k);
}
vector partition(vector &a, int l, int r, int pvalue)
{
	int less = l - 1;//小于区的边界
	int more = r+1;//大于区的边界
	int curr = l;
	while (curr< more)
	{
		if (a[curr] < pvalue)//当前值 pvalue)//当前值>pvalue
			swap(a[--more], a[curr]);//当前值与大于区边界交换,但是index不用后移,因为换来的不知道是不是大于等于还是小于pvalue
		else
			++curr;//当前值=pvalue,看下一个
	}
	vector pvaluerange{ less + 1,more-1 };//返回了等于区的边界下标,此数组中就2个元素
	return pvaluerange;
}
int KthMin(vector &a, int k)
{
	if (k<1||k>a.size())
		return NULL;
	else
		return findKthMin(a,0,a.size()-1,k-1);//第k小的数,在下标上是k-1,
}
#endif // !BFPRT_H

#include"BFPRT.h"
#include
#include
using namespace std;

void main()
{
	vectora{ 0,1,2,4,53,8,7,10,33,22,100 };
	cout<



你可能感兴趣的:(算法)