该文章参考(代码参考进行修改已经验证)——来源作者博客

算法思想

1、将数组的 n 个元素划分为 [n/5](向下取整)组,每一组5个元素,且至多只有一组由剩下的 n mod 5 个元素组成
2、寻找这 [n/5]组中每一组的中位数: 首先对每组元素进行插入排序(插入排序对数据量较小的排序效率较高),然后确定每组有序元素的中位数(可以用一个临时数组进行存储)
3、对第2步中找出的 [n/5]个中位数,递归调用SELECT以找出其中位数 x(如果由偶数个中位数,为了方便,约定 x是较小的中位数)
4、利用修改过的 PARTITION版本,按中位数的中位数 x 对数组进行划分,让 k 比划分的低区中的元素数目多1,因此 x是第 k 小的元素,并且有 n-k个元素在划分的高区
5、如果i =k,则返回 x,如果i < k,则在低区递归调用SELECT来找出第 i 小的元素,如果i >k,则在高区递归查找第 i-k小的元素

#include<iostream>
#include<ctime>
using namespace std;//创建一个装有数组 arr 以每5个元素为1组共有 n/5组,每一组中的中位数存入到临时数组中,组成一组含有 n/5个中位数的数组Mid
//Find函数不仅能通过插入排序拍好每一个小组,并能返回 n/5个中位数的中位数
int Find(int arr[],int left,int right); int PARTITION(int arr[],int left,int right,int t){  //t 是传入的作为 划分主元的参数 int i = left -1;int k= 0;for(int j = left;j<=right;j++){if(arr[j]<t){  //将比主元更大的元素交换到数组arr 的右边,比主元小的交换到数组的左边i++;swap(arr[i],arr[j]); }if(arr[j]==t){k=j;  //记录下主元在数组 arr中的位置 }}swap(arr[i+1],arr[k]);return i+1;
}int SELECT(int arr[],int left,int right,int i){if(left>=right){return arr[left];}int t=Find(arr,left,right);  //返回的 t 代表的是 存储每一组中位数的临时数组的中位数int mid=PARTITION(arr,left,right,t);int k=mid-left+1;  //得到低区的元素个数if(i==k){  //表明已经找到该元素 return arr[mid];} else if(i<k){  //则要递归在 低区查找 return SELECT(arr,left,mid-1,i);}else{  //递归在高区查找 return SELECT(arr,mid+1,right,i-k);  //在整个数组中的第i小元素在高区应该是 第 i-k 小元素了 }
} void InsertSort(int arr[],int left,int right){int key;for(int i=left+1;i<=right;i++){key = arr[i];int j=i-1;while(j>=left&&arr[j]>key){arr[j+1]=arr[j];j--;}arr[j+1]=key;}
}int Find(int arr[],int left,int right){int num=right-left+1; //得到该区间元素个数int h=0;  //用来记录组数if(num%5==0){   //如果当前数组中元素个数恰好是5的倍数,则以每5个元素一组,没有余数那一组 h=num/5;} else{  //否则应该加上最后不足5个元素的一组 h=num/5+1; }//cout<<"h="<<h<<endl; int *Mid = new int[h];  //存放每组中位数的临时数组int p1=left;int p2=left+4;if(p2>right)  //防止第一次插入排序的数组不足5个元素 p2=right;for(int k=0;k<h;k++) { //5个一组,共 h组,分别进行插入排序 InsertSort(arr,p1,p2);p1=p2+1;if(p1>right)  //防止越界 p1=right;p2+=5; if(p2>right)  //防止越界 p2=right;} int k=0;for(int i=0;i<h&&k<h;i++){if(i<h-1){   //元素足够 5 个的组别 Mid[k]=arr[2+5*i+left];k++;continue;}if(num%5==0){  //如果当前数组中元素个数恰好是5的倍数,则这最后一组也是刚好有5个元素 Mid[k]=arr[2+5*i+left];}else{Mid[k]=arr[(num%5)/2+5*i+left];  //num%5 是余数,也就是这一组不够5个元素的组别的元素个数 }}if(h==1){return Mid[0];   //当 存储中位数的临时数组 Mid只有一个元素时,那么这个数就是中位数的中位数 }else{return SELECT(Mid,0,h-1,(h-1)/2+1);  //递归调用SELCET算法,选择 Mid数组中的中位数(即第 (h-1)/2+1)小的元素 }}int main(){int arr[30];srand((unsigned) time(0));for(int i=1;i<=30;i++){arr[i-1]=rand()%100;cout<<arr[i-1]<<" ";if(i%10==0)cout<<endl;}cout<<endl;cout<<"SELECT得到的第"<<5<<"小的数="<<SELECT(arr,0,29,5)<<endl;}

算法分析:

1、为了分析SELECT算法的运行时间,我们首先要确定大于划分主元 x 的元素的个数的下界——
在第2步找出的中位数中,至少有一半大于或等于中位数的中位数x。因此,在这[n/5]个组中,除了当n不能被5整除时产生的所含元素少于5个的那个组和包含x的那个组之外,至少有一半的组中有3个元素大于x,不计算这两个组,则当前数组中大于 x 的元素的个数至少为:*3 ([ 1/2 * [n/5] ] -2) >= 3n/10-6
类似的,至少有 3n/10-6 个元素小于x,因此,在最坏情况下,在第5步中,SELECT的递归调用最多作用于 7n/10+6个元素上。
2、设计一个递归式来推导 SELECT算法的最坏情况运行时间T(n)——

步骤1,2,4需要的时间为 O(n) (步骤2是对大小为O(1)的集合调用O(n)次插入排序)。步骤3所需要的时间为 T[n/5] (递归调用求中位数的中位数),步骤5所需时间至多为 T( 7n/10+6)。

这里我们假设T是单调递增的,此外我们还要做如下假设,即任何少于140个元素的输入需要 O(1)时间,后面会说明为什么是这个数字。

根据假设我们可以得到递归式——
T(n) = O(1) n<140
T(n)= T([n/5]) + T(7n/10+6) + O(n) n>=140

3、用替换法来证明这个运行时间是线性的,假设当 n> n0时,有常数c 使得T(n) <=cn,且存在一个常数,使得对所有的 n>0,上述递归式中的 O(n) 有上界 an。将这些假设代入:
T(n) <= c[n/5] + c(7n/10+6) + an <=cn/5 + c + 7cn/10 + 6c + an = 9cn/10 +7c+an =cn+(-cn/10 +7c+an)
如果 -cn/10 +7c+an <=0 成立,则上式 可转化为 T(n) = O(n)

当 n>70时,-cn/10 +7c+an <=0 可转化为 c >=10a(n/(n-70)), 因为这里假设n >140,所以有n/(n-70) <=2,因此,选择 c>=20a就能满足 -cn/10 +7c+an <=0 (但是这里的常数 140也可以使用其他何是的数来代替,然后再相应的选择 c 即可)

综上,T(n) = O(n)

最坏情况为线性时间的选择算法(SELECT)相关推荐

  1. 最坏情况为线性时间的选择算法

    最坏情况为线性时间的选择算法 参考:[算法]算法导论:https://www.bilibili.com/video/BV1Tb411M7FA?p=6 提出问题:从一个数组中找到第K个最大数字,即TOP ...

  2. 算法设计与分析——顺序统计量:期望为线性时间的选择算法

    分类目录:<算法设计与分析>总目录 相关文章: · 顺序统计量:最大值与最小值 · 顺序统计量:期望为线性时间的选择算法 · 顺序统计量:最坏情况为线性时间的选择算法 选择算法指的是在一个 ...

  3. 约束优化:低维线性时间线性规划算法(Seidel算法)、低维线性时间严格凸二次规划算法

    文章目录 约束优化:低维线性时间线性规划算法(Seidel算法).低维线性时间严格凸二次规划算法 带约束优化问题的定义 带约束优化问题的分类及时间复杂度 低维线性规划问题 定义 Seidel线性规划算 ...

  4. 找出数组中第i小元素(时间复杂度Θ(n)--最坏情况为线性的选择算法

    找出数组中第i小元素 期望时间复杂度:Θ(n) 最坏情况的时间复杂度Θ(n^2) int randomized_select(int *array,int start,int end,int inde ...

  5. Leapfrog Triejoin:最坏情况下的最优连接算法

    介绍 leapfrog triejoin是商业数据记录系统 LogicBlox® 采用的一种新颖的连接算法,在不同的基准测试中表现出色.leapfrog triejoin论文的写作者认为这个算法,即使 ...

  6. 算法练习——在有序序列(r1,r2,...,rn)中,存在序号i(1<=i<=n),使得ri=i。请设计一个分治算法找到这个元素。 要求算法在最坏情况下的时间性能为O(logn))

    算法练习 题目 答案 注意 题目 答案 #include<iostream> using namespace std; int find(int a[],int left,int righ ...

  7. 线性时间冰山查询算法(Linear-time Iceberg Query Algorithm )

    一.从面试题开始 在进入到枯燥的正文之前,先来看一道据说在很多面试过程中都会问到的题目: 已知一个长度为n的数组,求出现半数以上的元素. 这道题目看似简单,其实得到完美的答案并不容易.首先,不难想到, ...

  8. 线性时间查找固定频率的元素

    转自:http://blog.ibread.net/467/linear-time-iceberg-query-algorithm/ 一.从面试题开始 在进入到枯燥的正文之前,先来看一道据说在很多面试 ...

  9. 非确定性算法_使用最坏情况提高基于MPC的避障算法对参数不确定性的鲁棒性

    编者按:避障问题是AGV行驶过程中的一个重点,尤其是在未知和非结构化的环境中,没有关于环境的先验知识以及准确的车辆模型参数,难以充分发挥车辆的性能.作者在以前工作中,提出了在未知和非结构化环境中基于非 ...

最新文章

  1. 在pycharm里做echarts_用 ECharts 做出漂亮的数据统计图
  2. Acegi 安全框架
  3. C语言rand(),srand()函数真实性能分析
  4. 恶意软件盯上了加密货币,两家以色列公司受到攻击
  5. 20. 有效的括号 golang 堆栈
  6. 网络中典型协议--(DNS,输入url后, 发生的事情. ,ICMP,NAT)
  7. 【转】Elasticsearch5.0 安装问题集锦
  8. phpstudy安装ssl证书_给网站安装免费SSL证书
  9. 存储服务器格式化恢复方法
  10. jad反编译成java,Jad java反编译指令
  11. html吃豆豆小游戏源码,HTML5 Canvas吃豆豆动画
  12. lfs库下载_lua使用lfs.dll库进行文件操作
  13. catalina 无法验证macos_macOS Catalina 无法安装是什么原因?
  14. 威联通NAS实现定时任务
  15. 点餐系统-----数据库设计
  16. 隐藏服务器header与web软件版本信息
  17. Centos 8.0 安装图形化界面(超详细)
  18. OverlayScrollbars插件监听滚动条的用法
  19. JDBC-通用查询功能
  20. vfp读取oracle 图片,在VFP中读取SQL-Server数据库Image字段

热门文章

  1. 优达学城 深度学习 任务2
  2. 性能测试之Jmeter:使用代理录制脚本
  3. Spark使用RDD实现分组topN(八种方法)
  4. 你的职场身价值几何?
  5. 视频帧率对人眼主观感受的影响
  6. Acrel-3200远程预付费电能管理系统 在福州万宝产业园的应用
  7. 大数据 hadoop 应用案例
  8. Movie Studio 15 Platinum——Vegas带你一起开创新的纪元
  9. Xilinx ip核之FIFO和RAM
  10. 基于 Bootstrap 5 的多用途预定(酒店、航班、出租车、旅游)主题 HTML 网站模板