顾名思义:这篇文章讲解的就是如果用线性时间算法来作出元素选择问题。
问题描述:给定线性序集中n个元素和一个整数k,1<=k<=n.要求找出这n个元素中第k小的元素,即如果将这个n个元素依其线性序排列时,排在第k个位置的元素就是要找的元素,当k== 1时,要找的就是最小的元素;当k==n,就是最大的元素;当k=(n+1)/2,称为中位数。

问题分析:
在某些特殊的情况下,我们可以实现线性时间选择,对于找最大最小的元素O(n)内可以实现;当k<=n/logn,通过堆排序算法可以在O(n+klogn)=O(n)内实现;当k>=n-n/logn时也一样。
下面是给出的一般的选择问题,从渐近阶的意义上看,这个也可以在O(n)时间内完成。
下面的算法实现参考了《计算机算法与分析》和一些博客,是对其的一个整理。

方法一:
算法描述:用一个随机的序列中的数作为枢纽,用快速排序算法,进行一次快排,然后将枢纽值和k值进行比较,以此来确定k值,我并没有做任何的对比所以并不是清楚这种算法的效率有多少,但是搜到的结果表明,这种算法的最坏时间复杂度是O(n^2),相对与另一种是不太理想的。

解法:

1.首先大家都会想到的解法是排序,之后找出第k个元素,但是排序的时间复杂度不符合要求,或者需要额外的空间。

2.利用快排的思想,以枢纽(随机得到)为界,将数组分为2部分,一部分小于等于这个枢纽值,一部分大于这个枢纽值,与快排不同的是,我们只处理一部分,另一部分舍弃。

#include<bits/stdc++.h>
using namespace std;int partition(vector<int> &vec,int left,int right)
{int i=left;int j=right;int temp=vec[left];while(i<j){while(vec[j]>=temp&&i<j)//处理i,j的先后顺序不能改变 {j--;}while(vec[i]<=temp&&i<j){i++;}swap(vec[i],vec[j]);}vec[left]=vec[j];vec[j]=temp;return j;
}
int  QuickSort(vector<int> &vec,int left,int right,int k)
{if(left==right)return vec[left];int mid=partition(vec,left,right);int j=mid-left+1;if(k<=j)return QuickSort(vec,left,mid,k);elsereturn QuickSort(vec,mid+1,right,k-j);}
void print(int x)
{cout<<x<<" ";
}int main()
{vector<int> vec={1,2,3,6,5,4,7,8,9};for_each(vec.begin(),vec.end(),print);cout<<endl;int k;cout<<"请输入K(要求找出这n个元素中第k小的元素):" ;cin>>k;int count=vec.size()-1;cout<<QuickSort(vec,0,count,k)<<endl;QuickSort(vec,0,count,k);for(auto a:vec){cout<<a<<" ";}cout<<endl;}


方法二:

这里我们就利用中位数来进行线性时间的选择算法!

中位数就是指将数据按大小顺序排列起来,形成一个数列,居于数列中间位置的那个数据就是中位数。

算法思路
(1)将输入的n个数划分成 ⌈n5⌉⌈n5⌉ 个组,当然最后一组的数目可能是小于5的!
(2)用任意的排序方法对他们进行排序,并取出一共 ⌈n5⌉⌈n5⌉ 个中位数。
(3)找出该 ⌈n5⌉⌈n5⌉ 个中位数中的中位数。(如果 ⌈n5⌉⌈n5⌉ 是偶数则取相对大的那个数)
(4)将全部的数划分为两个部分,小于基准的在左边,大于等于基准的放右边。

我们用小圆点表示元素,得到如下图:

说明:
图中中间白色圈表示各组数据的中位数,最中间灰色表示中位数的中位数! 箭头是从较小的数指向较大的数!

故我们可以使用该数作为划分的基准(比上一个随机基准的方法会好很多)!

图中

当n≥75时,3A1大于等于 14n14n。所以按此基准划分所得的左右2个子数组的长度都至少缩短 1414。

#include<bits/stdc++.h>
using namespace std;int partition(vector<int> &vec,int left,int right,int k)
{int i=left;int j=right;int temp=vec[k];while(i<j){while(vec[j]>=temp&&i<j)//处理i,j的先后顺序不能改变 {j--;}while(vec[i]<=temp&&i<j){i++;}swap(vec[i],vec[j]);}vec[k]=vec[j];vec[j]=temp;return j;
}void print(int x)
{cout<<x<<" ";
}int  Select(vector<int> &vec,int left,int right,int k)
{if(right-left<75){return vec[left+k-1];}for(int i=0;i<=(right-left-4)/5;i++){}int x=Select(vec,left,left+(right-left-4)/5,(right-left-4)/10);int i=partition(vec,left,right,x);int j=i-left+1;if(k<=j)return Select(vec,left,i,k);elsereturn Select(vec,i+1,right,k-j);}int main()
{vector<int> vec={1,2,3,6,5,4,7,8,9};for_each(vec.begin(),vec.end(),print);cout<<endl;int k;cout<<"请输入K(要求找出这n个元素中第k小的元素):" ;cin>>k;int count=vec.size()-1;cout<<Select(vec,0,count,k)<<endl;Select(vec,0,count,k);for(auto a:vec){cout<<a<<" ";}cout<<endl;} 

算法设计与分析——递归与分治策略——线性时间选择相关推荐

  1. 算法设计与分析——递归与分治策略——全排列

    算法设计与分析--递归与分治策略--全排列 全排列问题的解决是通过分治与递归思想来解决的 首先判断是否递归到了最后一位,如果递归到了最后一位,则输出他当前的全排列序列. 如果没有到达最后一位,则循环的 ...

  2. 算法设计与分析——递归与分治策略——最接近点对问题

    [问题描述] 最近对问题要求在包含有n个点的集合S中,找出距离最近的两个点.设 p1(x1,y1),p2(x2,y2),--,pn(xn,yn)是平面的n个点. 严格地将,最近点对可能不止一对,此例输 ...

  3. 算法设计与分析——递归与分治策略——棋盘覆盖

    问题描述 棋盘覆盖问题要求在2^k * 2^k 个方格组成的棋盘中,你给定任意一个特殊点,用一种方案实现对除该特殊点的棋盘实现全覆盖. 建立模型如图: 解决方案就是利用分治法,将方形棋盘分成4部分,如 ...

  4. 算法设计与分析——递归与分治策略——循环日程赛

    问题描述: 非递归方案一:代码 #include<bits/stdc++.h> using namespace std;void gameTable(vector<vector< ...

  5. 算法设计与分析——递归与分治策略——快速排序

    快速排序--递归算法 处理i,j的先后顺序不能改变 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达 ...

  6. 【算法设计与分析】16 分治策略:快速排序(快速排序的时间复杂度计算)

    上一篇文章学习了:[算法设计与分析]15 分治策略:芯片测试 文章目录 1. 快速排序的基本思想 1.2 时间复杂度的计算 1.21 最坏情况时间复杂度计算 1.22 最好情况时间复杂度 1.23 平 ...

  7. 【算法设计与分析】15 分治策略:芯片测试

    上一篇文章学习了[算法设计与分析]14 分治算法的一般描述和分析方法 文章目录 1. 芯片测试 1.1 一次测试的过程 1.2 如何测试一块芯片的好坏 1.3 蛮力算法 1.4 分治算法设计思想 1. ...

  8. 【算法设计与分析】13 分治策略的设计思想

    算法中很多方法都是可以采用分治策略进行设计与优化,那么什么是分治策略?如何使用分治策略进行算法的设计与分析? 文章目录 1. 分治策略的基本思想 1.1 二分检索的设计思想 1.2 二分归并排序的设计 ...

  9. 算法设计与分析——递归与分治——归并排序

    归并排序采用的是一种分治的思想,如下图,先将要排序的元素分为两块,每个块又开始分裂,然后逐个按照特定顺序合并,合成最后我们需要的数组. 归并排序的复杂度: 时间复杂度:O(nlogn) 空间复杂度:O ...

最新文章

  1. NAT技术和代理服务器
  2. 分享一个监控MFS的nagios插件
  3. oracle SQL 命令行(四.安全性自主控制)
  4. python装饰器原理-python装饰器原理与用法深入详解
  5. matlab 添加环境变量,CentOS 添加环境变量的三种方法
  6. no.6 _扔鸡蛋问题
  7. Mysql日志-RedoLog、UndoLog和BinLog的关系捋顺
  8. ios kb转m_iOS 音频录音和格式转换
  9. 2008一打开项目就闪退_UE4[C++]项目编译相关的坑
  10. 通过修改然后commit的方式创建自己的镜像
  11. linux 开机启动设置密码,Linux下Redis设置密码及开机自启动
  12. 《实施Cisco统一通信管理器(CIPT1)》一2.7 总结
  13. 安科瑞电力监控系统在上海平凉街道23街坊商办项目的应用
  14. ubuntu虚拟机使用笔记——9、vmware卸载,重新安装ubuntu,重安后不能共享文件
  15. 二阶滤波器原理及算法程序
  16. 验证码漏洞汇总(一)
  17. 马虎词汇教程21-25(转载)
  18. java中int不兼容_mvn install命令时,一直报错:不兼容的类型 [ERROR] 找到: java.lang.Object [ERROR] 需要: int...
  19. PHP登入网站抓取并且抓取数据
  20. [Web3.0]什么是Web3.0/时代

热门文章

  1. 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]
  2. dotnet core 开发体验之Routing
  3. 【广州/深圳 活动】 MVP社区巡讲
  4. 利用F#库canopy进行UI测试
  5. h5外卖源码php_校园食堂外卖APP走红 更多APP定制开发上一品威客网
  6. [转]ES7、ES8、ES9、ES10新特性大盘点
  7. Visual Studio 2019 16.3.10 初体验
  8. 介绍一款python类型检查工具pyright
  9. TextView的部分点击事件和点击事件
  10. C++之delete常见错误总结