算法导论学习之线性时间求第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 ...
随机推荐
- POJ-1011(sticks,深搜)
Description George took sticks of the same length and cut them randomly until all parts became at mo ...
- 聊聊svg
来源:SVG的用法 补充 CANVAS产生的dom数量比SVG要少 SVG可以使用css设置动画样式 对于动画性能来说,不能说svg或canvas谁更优,而是要看情况: SVG 是一种使用 XML 描 ...
- Numpy的基本操作和相关概念(一)
基础操作 np.random.randn() 符合正态分布的数据 np.vstack((a,b)) 矩阵水平拼接 np.hstack((a,b)) 矩阵垂直拼接 np.dot(a,c) 点阵积 A@B ...
- JSP菜鸟之困
我一直想把java一套系统学好... 之前寒假学了android......feel good 大四又把jsp补习了一边.....85 但是苦于没有做过实例..... 暑假学PS之间想恶补一下jsp. ...
- 【转】Entity Framework6 with Oracle(可实现code first)
Oracle 已在2014年底提供对EF6的支持.以前只支持到EF5.EF6有很多有用的功能 值得升级.这里介绍下如何支持Oracle 一.Oracle 对.net支持的一些基础知识了解介绍. 1 ...
- struts2拦截器加自定义注解实现权限控制
https://blog.csdn.net/paul342/article/details/51436565 今天结合Java的Annotation和Struts2进行注解拦截器权限控制. 功能需求: ...
- POJ-2590-Steps题目详解,思路分析及代码,规律题,重要的是找到规律~~
Steps Time Limit: 1000MS Memory Limit: 65536K http://poj.org/problem?id=2590 Description One ...
- asp.net 引发类型为“System.OutOfMemoryException”的异常
asp.net 引发类型为“System.OutOfMemoryException”的异常通常发生在IIS进程获取不到内存时. 临时解决方法是: 回收IIS的应用程序池. 如果要比较好的解决办法是: ...
- 【ZJOI2017 Round1练习】D2T3 counter(线段树)
题意: 思路: 预处理出b[i]代表i位置之前比a[i]小的数的个数 以每个数为结尾的组数是线段树中(1,a[i]-1) 对于a[i]换到最后,相当于线段树中(a[i]+1,n)-- 交换后b[i]又 ...
- BZOJ1126: [POI2008]Uci
$n \leq 100,m \leq 100$,$n*m$的01矩形,问从左下角开始往上走,每次转弯只能向右,不能经过重复点,不能撞到1,到达点$(x,y)$的方案数,$mod \ \ k$. 感人肺 ...