博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法导论学习之线性时间求第k小元素+堆思想求前k大元素
阅读量:2227 次
发布时间:2019-05-09

本文共 2754 字,大约阅读时间需要 9 分钟。

对于以前,如果要我求第k小元素,或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,但是现在有了更好的思路。

一.线性时间内求第k小元素

这个算法又是一个基于分治思想的算法。其具体的分治思路如下:
1.分解:将A[p,r]分解成A[p,q-1]和A[q+1,r]两部分,使得A[p,q-1]都小于A[q],A[q+1,r]都不小于A[q];
2.求解:如果A[q]恰好是第k小元素直接返回,如果第k小元素落在前半区间就到A[p,q-1]递归查找,否则到A[q+1,r]中递归查找。
3.合并:这个问题不需要合并。
其对应的代码如下:

int RandomziedSelect(int *a,int p,int r,int k){    if(p==r)///如果当前区间只剩一个元素,那么这个元素一定就是我们要求的        return a[p];    int q=RandomParatition(a,p,r);  ///随机划分函数    int x=q-p+1;///求出a[p,q]之间的长度    if(x==k) ///a[q]恰好是第k小元素        return a[q];    if(x>k)  ///x小于k说明第k小元素在a[p,q-1]之间        return RandomziedSelect(a,p,q-1,k);    else  ///x大于k说明第k小元素在a[q+1,r]之间,而且是这个区间的第k-x小元素        return RandomziedSelect(a,q+1,r,k-x);}

其实这个过程很类似于快排,但是为什么快排的时间复杂度是O(nlgn),而这个算法的时间复杂度只有O(n)?主要的原因在于这个算法每次只要处理分解以后一半的区间,而不像快排那样两边都要处理。当然这只是一个简单的分析,更具体数学分析在这里就不说了。其实我们也可以利用堆的性质来求出第k小元素,只要我们建立一个最小堆后然后再调整k-1次就行了,这样时间复杂度是O(n)+O((k-1)lgn)。

下面给出一份完整的代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;int Paratition(int *a,int p,int r){ int key=a[r]; int i=p-1; for(int j=p;j
k) ///x小于k说明第k小元素在a[p,q-1]之间 return RandomziedSelect(a,p,q-1,k); else ///x大于k说明第k小元素在a[q+1,r]之间,而且是这个区间的第k-x小元素 return RandomziedSelect(a,q+1,r,k-x);}int main(){ int b[100]; ifstream fin("lkl.txt"); int n,k; //cout<<"请输入n,k: "; fin>>n>>k; //cout<<"请输入"<
<<"个元素: "<
>b[i]; int ans=RandomziedSelect(b,1,n,k); sort(b+1,b+n+1); for(int i=1;i<=n;i++) cout<
<<" "; cout<

二.利用堆求前k大元素

这个算法的思想比较简单: 如果我们要求n个元素中前k大的元素,我们就先将这n个元素中的前k个元素建立一个最小堆,然后从k+1。。。n依次判断,如果某个元素大于堆中最小的元素,我们就将其替代堆中的最小元素,并且调整一下堆。这样将所有元素都检查完了之后,堆中的k个元素也就是这n个元素中的前k大元素了。时间复杂度O(k)+O((n-k)lgk)。

代码如下

#include
#include
#include
#include
#include
using namespace std;#define maxn 100///最小堆调整函数void MinHeadfly(int *a,int i,int HeadSize){ int l=i*2,r=2*i+1; int largest; if(a[i]>a[l]&&l<=HeadSize) largest=l; else largest=i; if(a[largest]>a[r]&&r<=HeadSize) largest=r; if(largest!=i) { swap(a[i],a[largest]); MinHeadfly(a,largest,HeadSize); }}///最小堆建立函数void MinHeadBuild(int *a,int n){ for(int i=n/2;i>=1;i--) MinHeadfly(a,i,n);}///最小堆排序函数,从大到小排序void MinHeadSort(int *a,int HeadSize){ int k=HeadSize; for(int i=HeadSize;i>=2;i--) { swap(a[i],a[1]); k--; MinHeadfly(a,1,k); }}///求b数组的前k大元素void prek(int *a,int *b,int n,int k){ MinHeadBuild(a,k); for(int i=k+1;i<=n;i++) if(b[i]>a[1]) { a[1]=b[i]; MinHeadfly(a,1,k); } MinHeadSort(a,k); cout<<"前"<
<<"大元素为:"<
>n>>k; //cout<<"请输入"<
<<"个元素: "<
>b[i]; if(i<=k) a[i]=b[i]; } prek(a,b,n,k); return 0;}

转载地址:http://yurfb.baihongyu.com/

你可能感兴趣的文章
怎么根据Comparable方法中的compareTo方法的返回值的正负 判断升序 还是 降序?
查看>>
理解事务的4种隔离级别
查看>>
常用正则匹配符号
查看>>
建议42: 让工具类不可实例化
查看>>
Java 异步机制与同步机制的区别
查看>>
hibernate的对象三种状态说明
查看>>
什么是N+1查询?
查看>>
Spring 接管 Hibernate 配置 延迟加载
查看>>
找出不在预定数组中的自然数
查看>>
String常见面试题
查看>>
直插,快排,堆排,归并排序的分析
查看>>
二叉树的各种操作(面试必备)
查看>>
oracle
查看>>
泛型与通配符详解
查看>>
BaseServiceImpl中的实现关键点
查看>>
Struts2中的session、request、respsonse获取方法
查看>>
如何理解MVC模型
查看>>
SpringMVC中乱码解决方案
查看>>
SpringMVC中时间格式转换的解决方案
查看>>
post和get请求相关知识点
查看>>