算法导论学习之线性时间求第k小元素+堆思想求前k大元素
对于曾经,假设要我求第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<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<fstream>
using namespace std;
int Paratition(int *a,int p,int r)
{
int key=a[r];
int i=p-1;
for(int j=p;j<r;j++)
if(a[j]<key)
{
i++;
swap(a[i],a[j]);
}
swap(a[i+1],a[r]);
return i+1;
}
int RandomParatition(int *a,int p,int r)
{
int x=rand()%(r-p+1)+p;///产生[p,r]之间的随机数
swap(a[x],a[r]); ///交换a[x]和a[r]的值,事实上就是将a[x]作为划分的关键值
return Paratition(a,p,r);
}
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);
}
int main()
{
int b[100];
ifstream fin("lkl.txt");
int n,k;
//cout<<"请输入n,k: ";
fin>>n>>k;
//cout<<"请输入"<<n<<"个元素: "<<endl;
for(int i=1;i<=n;i++)
fin>>b[i];
int ans=RandomziedSelect(b,1,n,k);
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
cout<<b[i]<<" ";
cout<<endl;
cout<<"第"<<k<<"小元素为: "<<ans<<endl;
return 0;
}
二.利用堆求前k大元素
这个算法的思想比較简单: 假设我们要求n个元素中前k大的元素。我们就先将这n个元素中的前k个元素建立一个最小堆,然后从k+1。
。。
n依次推断。假设某个元素大于堆中最小的元素,我们就将其替代堆中的最小元素,并且调整一下堆。
这样将全部元素都检查完了之后,堆中的k个元素也就是这n个元素中的前k大元素了。时间复杂度O(k)+O((n-k)lgk)。
代码例如以下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<fstream>
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<<"前"<<k<<"大元素为:"<<endl;
for(int i=1;i<=k;i++)
cout<<a[i]<<" ";
cout<<endl;
}
int a[maxn],b[maxn];
int main()
{
ifstream fin("lkl.txt");
int n,k;
//cout<<"请输入n,k: ";
fin>>n>>k;
//cout<<"请输入"<<n<<"个元素: "<<endl;
for(int i=1;i<=n;i++)
{
fin>>b[i];
if(i<=k)
a[i]=b[i];
}
prek(a,b,n,k);
return 0;
}
算法导论学习之线性时间求第k小元素+堆思想求前k大元素的更多相关文章
- 算法导论 第八章 线性时间排序(python)
比较排序:各元素的次序依赖于它们之间的比较{插入排序O(n**2) 归并排序O(nlgn) 堆排序O(nlgn)快速排序O(n**2)平均O(nlgn)} 本章主要介绍几个线性时间排序:(运算排序非比 ...
- 算法导论学习---红黑树具体解释之插入(C语言实现)
前面我们学习二叉搜索树的时候发如今一些情况下其高度不是非常均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜 ...
- 算法导论学习-Dynamic Programming
转载自:http://blog.csdn.net/speedme/article/details/24231197 1. 什么是动态规划 ------------------------------- ...
- 算法导论学习-binary search tree
1. 概念: Binary-search tree(BST)是一颗二叉树,每个树上的节点都有<=1个父亲节点,ROOT节点没有父亲节点.同时每个树上的节点都有[0,2]个孩子节点(left ch ...
- 算法---数组总结篇2——找丢失的数,找最大最小,前k大,第k小的数
一.如何找出数组中丢失的数 题目描述:给定一个由n-1个整数组成的未排序的数组序列,其原始都是1到n中的不同的整数,请写出一个寻找数组序列中缺失整数的线性时间算法 方法1:累加求和 时间复杂度是O(N ...
- "《算法导论》之‘线性表’":基于静态分配的数组的顺序表
首先,我们来搞明白几个概念吧(参考自网站数据结构及百度百科). 线性表 线性表是最基本.最简单.也是最常用的一种数据结构.线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外, ...
- 算法导论学习-prim算法
一. 关于最小生成树 对于无向连通图G=(V,E),其中V表示图的顶点,E表示图的边,对于每条边都有一个权值,可以理解为边a->b的权值C为从a走到b要走的路程为C.现在我们希望找到一个无回路的 ...
- 算法导论学习-RED-BLACK TREE
1. 红黑树(RED-BLACK TREE)引言: ------------------------------------- 红黑树(RBT)可以说是binary-search tree的非严格的平 ...
- 算法导论学习-heapsort
heap的定义:如果数组a[1,....n]满足:a[i]>a[2*i] && a[i]>a[2*i+1],1<=i<=n/2,那么就是一个heap,而且是ma ...
随机推荐
- PyTorch的十七个损失函数
本文截取自<PyTorch 模型训练实用教程>,获取全文pdf请点击: tensor-yu/PyTorch_Tutorialgithub.com 版权声明:本文为博主原创文章,转载请附上 ...
- 【牛客练习赛 25】A 因数个数和
题目地址:https://www.nowcoder.com/acm/contest/158/A 参考博客:https://blog.csdn.net/zzcblogs/article/details/ ...
- PowerShell(PHPStorm terminal with PowerShell)运行git log中文乱码
解决方案: 1)以管理员身份运行PowerShell 2)新建一个针对PowerShell的Pofile文件 New-Item -Path $Profile -ItemType file -Force ...
- hdu3094 A tree game
题目描述 题解: 树上删边. $SG[u]$^=$SG[son[u]]+1$ 代码: #include<cstdio> #include<cstring> ; template ...
- MySQL存储过程实践
对employees数据库建立存储过程 创建不含有输入输出变量的存储过程 DELIMITER // -- 设定语句结束分隔符 DROP PROCEDURE IF EXISTS GetEmployees ...
- Windows环境下安装 mysql-8.0.11-winx64 遇到的问题解决办法
下载mysql安装包,我的是下载mysql-8.0.11-winx64,解压到你想安装的目录下,然后配置环境(window环境下,mac本还没试过), 1.首先,配置环境:右击此电脑->属性-& ...
- 关于Servlet一些东西
---- 概念 Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面. 它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器响应(HTTP服务器 ...
- winfor应用程序打印报表清单
最近一周竟然有2位以前的同事问我在winfor应用程序里面打印怎么搞,所以才有了写这篇文章的打算,索性现在没事就写出来 在窗体上简单的布局设置一下如图 定义一个Model 我在里面放了属性之外还从写了 ...
- [Go]条件语句
package main import ( "io/ioutil" "fmt" ) //条件语句 //if的条件语句不需要括号 //if的条件里可以赋值,if的 ...
- POJ1201:Intervals【差分约束】
题目大意:给出N个闭区间,每个区间给出一个ci值,让你找出最小的数集Z使得每个闭区间都有不少于ci个Z中的元素,求card(Z) 思路:06年集训队论文<浅析差分约束系统>有详细的解题,设 ...