bfprt算法
1.将n个元素划分为 组,每组5个,至多有一组由n mod 5个元素组成
2.需找这 个组中每一个组的中位数 (插入排序找中间)
3.对这些中位数重复1,2直到只剩下一个数字
4.把这个数字作为基准,划分左右
5.判断基准坐标与k的关系,选择左边递归或者右边递归或者直接选择基准
时间复杂度:最坏O(n)
选择5个为一组插入排序,最坏4+3+2+1=10,O( )=O( ),
个数字选中位数,至少大于等于 个中位数,也就大于等于 个元素(因为都是选中位数)
所以最坏O( )
(c是常数)
设T(n)=tn(t是一个跟n有关的多项式,也可以是常数)
/**
* 插入排序
* @param arr 待排序数组
* @param left 开始位置
* @param right 结束位置
* @param cmp 小于
*/
template<typename T>
void insert_sort(T arr[], const int& left, const int& right, bool (*cmp)(const T&, const T&)) {
for (int i = left + 1; i <= right; ++i) {
T temp = arr[i];
int index = i - 1;
while (index >= left && cmp(temp, arr[index])) {
arr[index + 1] = arr[index];
--index;
}
arr[index + 1] = temp;
}
}
找中位数(其实找到了也不一定是中位数= =)
/**
* 找到中位数
* @param arr 待排序数组
* @param left 开始位置
* @param right 结束位置
* @param cmp 小于
* @return 中位数下标
*/
template<typename T>
int find_mid(T *arr, const int& left, const int& right, bool (*cmp)(const T&, const T&)) {
int i;
for (i = left; i + 4 <= right; i += 5) {
insert_sort(arr, i, i + 4, cmp);
swap(arr[i + 2], arr[left + (i - left) / 5]);
}
if (i <= right) {
insert_sort(arr, i, right, cmp);
swap(arr[(i + right) / 2], arr[left + (i - left) / 5]);
}
else {
i -= 5;
}
int remain = left + (i - left) / 5;
if (remain == left) {
return left;
}
return find_mid(arr, left, remain, cmp);
}
快排的划分基准
/**
* 找基准
* @param arr 待排序数组
* @param left 开始位置
* @param right 结束位置
* @param cmp 小于
* @return 基准位置
*/
template<typename T>
int partition(T arr[], const int& left, const int& right, bool (*cmp)(const T&, const T&)) {
int i = left;
int j = right;
T temp = arr[left];
while (i < j) {
while (i < j && !cmp(arr[j], temp)) {
--j;
}
if (i < j) {
arr[i] = arr[j];
++i;
}
while (i < j && !cmp(temp, arr[i])) {
++i;
}
if (i < j) {
arr[j] = arr[i];
--j;
}
}
arr[i] = temp;
return i;
}
bfprt算法
/**
* bfprt算法,找第k小数字
* @param arr 数组
* @param left 开始位置
* @param right 结束位置
* @param k 第k个数字
* @param cmp 小于
* @return 第k小数字
*/
template<typename T>
T bfprt(T *arr, const int& left, const int& right, const int& k, bool (*cmp)(const T&, const T&)) {
int mid_id = find_mid(arr, left, right, cmp);
if (mid_id != left) {
swap(arr[left], arr[mid_id]);
}
int pivot = partition(arr, left, right, cmp);
int num = pivot - left + 1;
if (num == k) {
return arr[pivot];
}
else if (num > k) {
return bfprt(arr, left, pivot - 1, k, cmp);
}
return bfprt(arr, pivot + 1, right, k - num, cmp);
}
测试
bool cmp(const int& a, const int& b) {
return a < b;
}
int main() {
random_device rd;
const int n= static_cast<int>(rd()%100+50);
int a[n];
for(int& c:a) {
c = static_cast<int>(rd() % 1000);
}
int b[n];
memcpy(b,a,sizeof(int)*n);
sort(b,b+n,cmp);
for(int& c:b)cout<<c<<' ';
cout<<endl;
cout<<bfprt(a,0,n-1,(n+1)/2,cmp)<<endl;
cout<<b[(n-1)/2]<<endl;
return 0;
}