BFPRT算法C++实现

本文介绍了BFPRT算法,一种寻找数组中第k小元素的算法,时间复杂度为O(n)。算法过程包括数组分组、插入排序、获取中位数、划分区域等步骤,并给出了详细的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<iostream>
#include<vector>
using namespace std;
#define MIN(x,y) x<y?x:y

void swap(int &a, int &b);//交换函数
void InsertSort(vector<int> &a, int l, int r);//插入排序
int getmedium(vector<int>&a, int l, int r);//获取数组的上中位数
int ge
线性时间选择算法通常指的是能在 $O(n)$ 时间复杂度内从无序数组中找到第 $k$ 小(或第 $k$ 大)元素的算法,例如随机选择算法和中位数的中位数(BFPRT算法。 ### 随机选择算法 随机选择算法的基本思想是随机选择一个基准元素,将数组划分为两部分,然后根据基准元素的位置与 $k$ 的大小关系,决定在左半部分或右半部分继续查找。在 C++ 实现中,该算法的空间复杂度为 $O(1)$。这是因为在算法执行过程中,只需要常数级的额外空间来进行元素交换和记录基准元素的位置等操作,不随输入规模 $n$ 的增长而增长。以下是一个简单的 C++ 代码示例: ```cpp #include <iostream> #include <vector> #include <cstdlib> #include <ctime> // 交换两个元素 void swap(int& a, int& b) { int temp = a; a = b; b = temp; } // 分区函数 int partition(std::vector<int>& arr, int left, int right) { int pivotIndex = left + rand() % (right - left + 1); int pivot = arr[pivotIndex]; swap(arr[pivotIndex], arr[right]); int i = left - 1; for (int j = left; j < right; j++) { if (arr[j] <= pivot) { i++; swap(arr[i], arr[j]); } } swap(arr[i + 1], arr[right]); return i + 1; } // 随机选择算法 int randomSelect(std::vector<int>& arr, int left, int right, int k) { if (left == right) return arr[left]; int pivotIndex = partition(arr, left, right); int rank = pivotIndex - left + 1; if (k == rank) return arr[pivotIndex]; else if (k < rank) return randomSelect(arr, left, pivotIndex - 1, k); else return randomSelect(arr, pivotIndex + 1, right, k - rank); } int main() { srand(time(0)); std::vector<int> arr = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; int k = 5; int result = randomSelect(arr, 0, arr.size() - 1, k); std::cout << "第 " << k << " 小的元素是: " << result << std::endl; return 0; } ``` ### 中位数的中位数(BFPRT算法 BFPRT 算法是一种确定性的线性时间选择算法,它通过一种特殊的方法选择基准元素,保证每次划分能将数组较好地分成两部分。在 C++ 实现中,该算法的空间复杂度同样为 $O(1)$。虽然在算法执行过程中可能会进行递归调用,但由于每次递归调用时,问题规模都会缩小,且递归栈的深度是常数级的,因此额外的空间开销仍然是常数级的。以下是一个简单的 C++ 代码示例: ```cpp #include <iostream> #include <vector> #include <algorithm> // 交换两个元素 void swap(int& a, int& b) { int temp = a; a = b; b = temp; } // 插入排序 void insertionSort(std::vector<int>& arr, int left, int right) { for (int i = left + 1; i <= right; i++) { int key = arr[i]; int j = i - 1; while (j >= left && arr[j] > key) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = key; } } // 找到中位数的中位数 int medianOfMedians(std::vector<int>& arr, int left, int right) { if (right - left < 5) { insertionSort(arr, left, right); return arr[(left + right) / 2]; } for (int i = left; i <= right; i += 5) { int subRight = std::min(i + 4, right); insertionSort(arr, i, subRight); swap(arr[left + (i - left) / 5], arr[(i + subRight) / 2]); } int newRight = left + (right - left) / 5; return medianOfMedians(arr, left, newRight); } // 分区函数 int partition(std::vector<int>& arr, int left, int right, int pivot) { for (int i = left; i <= right; i++) { if (arr[i] == pivot) { swap(arr[i], arr[right]); break; } } int i = left - 1; for (int j = left; j < right; j++) { if (arr[j] <= pivot) { i++; swap(arr[i], arr[j]); } } swap(arr[i + 1], arr[right]); return i + 1; } // BFPRT 算法 int bfprt(std::vector<int>& arr, int left, int right, int k) { if (left == right) return arr[left]; int pivot = medianOfMedians(arr, left, right); int pivotIndex = partition(arr, left, right, pivot); int rank = pivotIndex - left + 1; if (k == rank) return arr[pivotIndex]; else if (k < rank) return bfprt(arr, left, pivotIndex - 1, k); else return bfprt(arr, pivotIndex + 1, right, k - rank); } int main() { std::vector<int> arr = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; int k = 5; int result = bfprt(arr, 0, arr.size() - 1, k); std::cout << "第 " << k << " 小的元素是: " << result << std::endl; return 0; } ``` 综上所述,线性时间选择算法C++ 实现中的空间复杂度通常为 $O(1)$。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值