BFPRT实现
来源:互联网 发布:pc蛋蛋连中20期算法 编辑:程序博客网 时间:2024/06/11 01:46
这里自己实现了一下BFPRT算法,并与别人的实现版本进行效率对比,以及与C++标准库中的sort排序后选取top-k进行效率对比。发现,C语言版本的效率更高一些,在数据量不是海量数据时,sort的速度竟然比BFPRT要快。
原因猜想:O(nlgn),就算是n=50000000,lgn也才25.5754,而bfprt的常数因子要比这个大,再加上stl做了大量的优化,速度上就更快了。
//// BFPRT.cpp// NowCoder//// Created by soybeanmilk on 2017/7/22.// Copyright © 2017年 soybeanmilk. All rights reserved.//#include <iostream>#include <vector>#include <ctime>#include <cstdlib>using namespace std;void insertsort(vector<int> &vi, int b, int e){//包含e for(int i=b+1;i<=e;++i){ int temp=vi[i]; int j=i-1; for(;j>=b && vi[j]>temp;--j){ vi[j+1]=vi[j]; } vi[j+1]=temp; }}int getMidIndex(vector<int> &vi, int b, int e){//包含e //找中位数,最后返回找到的元素的下标 if(b==e) return b; int i=b; int index=0; for(;i<=e-4;i+=5){//e-(e-4)+1=5 insertsort(vi, i, i+4); //vi[b+index]=vi[i+2];//这个会使数组乱掉! swap(vi[b+index],vi[i+2]);//应该是交换元素,而不仅仅是将中位数移动到一块。 ++index; } if(i<=e){//剩余的不足5个的元素 insertsort(vi,i,e); //vi[b+index]=vi[i+(e-i)/2];//这个会使数组乱掉! swap(vi[b+index],vi[i+(e-i)/2]);//i~e可能为偶数个数,取中间两位低的一位为是位数,跟二分查找中取低位一样。 ++index;//与上面的情况保持一致,index表示中位数的个数 } return getMidIndex(vi, b, b+index-1);//继续找中位数的中位数,最后返回找到的元素的下标}int partition(vector<int> &vi, int b, int e, int val){//包含e while(b<e){ while(b<e && vi[e]>val) --e; if(b<e) vi[b]=vi[e]; while(b<e && vi[b]<=val) ++b; if(b<e) vi[e]=vi[b]; } vi[b]=val; return b;}int BFPRT(vector<int> &vi, int b, int e, int k){//包含e,这里在调用BFPRT时,需要先对k做一下转换, //找前10个最小的,那么这里传的下k为9,因为下标从0开始,0~9正好是10个数。 if(k<b || k>e)//表示k不符合规则 return -1; int midindex=getMidIndex(vi, b, e); int realindex=partition(vi, b, e, vi[midindex]); if(realindex==k) return realindex;//返回此realindex,在此之前(包含此下标)的元素即为要找的全部元素。 //这个函数需要返回值,主要是为了返回-1这个错误情况。 if(realindex<k) return BFPRT(vi, realindex+1, e, k);//其实就是一直找下标k else return BFPRT(vi, b, realindex-1, k);//其实就是一直找下标k}double random(double start, double end){ return start+(end-start)*rand()/(RAND_MAX + 1.0);}//别人的实现:http://blog.csdn.net/acdreamers/article/details/44656295#include <iostream>#include <string.h>#include <stdio.h>#include <time.h>#include <algorithm>using namespace std;const int N = 100000005;int a[N];//插入排序void InsertSort(int a[], int l, int r){ for(int i = l + 1; i <= r; i++) { if(a[i - 1] > a[i]) { int t = a[i]; int j = i; while(j > l && a[j - 1] > t) { a[j] = a[j - 1]; j--; } a[j] = t; } }}//寻找中位数的中位数int FindMid(int a[], int l, int r){ if(l == r) return a[l]; int i = 0; int n = 0; for(i = l; i < r - 5; i += 5) { InsertSort(a, i, i + 4); n = i - l; swap(a[l + n / 5], a[i + 2]); } //处理剩余元素 int num = r - i + 1; if(num > 0) { InsertSort(a, i, i + num - 1); n = i - l; swap(a[l + n / 5], a[i + num / 2]); } n /= 5; if(n == l) return a[l]; return FindMid(a, l, l + n);}//寻找中位数的所在位置int FindId(int a[], int l, int r, int num){ for(int i = l; i <= r; i++) if(a[i] == num) return i; return -1;}//进行划分过程int Partion(int a[], int l, int r, int p){ swap(a[p], a[l]); int i = l; int j = r; int pivot = a[l]; while(i < j) { while(a[j] >= pivot && i < j) j--; a[i] = a[j]; while(a[i] <= pivot && i < j) i++; a[j] = a[i]; } a[i] = pivot; return i;}int BFPTR_other(int a[], int l, int r, int k){ int num = FindMid(a, l, r); //寻找中位数的中位数 int p = FindId(a, l, r, num); //找到中位数的中位数对应的id int i = Partion(a, l, r, p); int m = i - l + 1; if(m == k) return a[i]; if(m > k) return BFPTR_other(a, l, i - 1, k); return BFPTR_other(a, i + 1, r, k - m);}int main(){ //生成测试数据 vector<int> vi; srand(unsigned(time(0))); int nums=50000000; for(int i=0;i<nums;i++) vi.push_back(int(random(0., 10.)*1000)); vector<int> vitp(vi);//备份测试数据,给sort函数使用 int k=666%nums;//随机取k值 cout<<nums<<" "<<k<<endl; //我的实现 clock_t start=clock(); cout<<"my BFPRT: "<<endl; BFPRT(vi, 0, (int)vi.size()-1, k);//注意这里(int)vi.size()-1 clock_t end=clock(); cout<<"used time: "<<(double)(end-start)/CLOCKS_PER_SEC<<"s"<<endl; sort(vi.begin(),vi.begin()+k);//为了与下面的直接排序进行结果对比,所以排序一下。 //别人的实现 cout<<"other BFPRT: "<<endl; for(int i=0;i<nums;i++) a[i]=vitp[i]; start=clock(); BFPTR_other(a, 0, nums - 1, k); end=clock(); cout<<"used time: "<<(double)(end-start)/CLOCKS_PER_SEC<<"s"<<endl; //直接使用sort排序再选top-k cout<<"direct sorted and select top-k: "<<endl; start=clock(); sort(vitp.begin(),vitp.end());//不使用vi,而使用vitp,因为vi经过BFPRT后,大部分都是有序的了 end=clock(); cout<<"used time: "<<(double)(end-start)/CLOCKS_PER_SEC<<"s"<<endl; //这里只验证我的结果是否正确 int isok=true; for(int i=0;i<k;i++){ if(vi[i]!=vitp[i]){ isok=false; break; } } if(isok) cout<<"ok!"<<endl; else cout<<"wrong!"<<endl; return 0;}结果如下:
50000000 666my BFPRT: used time: 4.48627sother BFPRT: used time: 3.4281sdirect sorted and select top-k: used time: 3.25237sok!
阅读全文
0 0
- BFPRT实现
- BFPRT算法Python实现
- BFPRT 算法java实现
- BFPRT算法C++实现
- BFPRT算法过程分析和实现
- BFPRT算法
- BFPRT算法
- BFPRT算法
- BFPRT 算法
- bfprt算法
- bfprt算法
- BFPRT 算法
- BFPRT算法
- BFPRT算法
- BFPRT算法
- BFPRT算法
- BFPRT算法(求前k个小的数)-Java实现
- BFPRT(线性查找)算法
- 大话理解网络传输
- Android.mk介绍
- 欢迎使用CSDN-markdown编辑器
- 数据归一化和两种常用的归一化方法
- React中的高阶组件(HOC)
- BFPRT实现
- http协议技能树
- RenderTarget在虚幻4的应用【1】之用虚幻4表白
- 深入理解Docker(镜像、容器、服务、swarm、stack)
- Java编程获取自己主机的IP地址简单案例
- 管理感言_人员培养看人品
- 机房合作——总结
- ZigBee 网络层
- 使用 Canvas 的Xfermode 实现 ImageView 圆形图片的实际步骤