算法导论学习之线性时间求第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 ...
随机推荐
- image的resizeMode属性
Image组件必须在样式中声明图片的宽和高.如果没有声明,则图片将不会被呈现在界面上. 我们一般将Image定义的宽和高乘以当前运行环境的像素密度称为Image的实际宽高. 当Image的实际宽 ...
- Delete 语句带有子查询的sql优化
背景: 接到开发通知,应用页面打不开,让我协助... (开发跟我说,表GV_BOOKS一直有锁,锁了有1个多小时了,问我能不能把锁释放掉,我回答他们说,这肯定是sql性能问题,表上有锁是正常现象,不是 ...
- ubuntu修改网卡名称ensX为eth0
1.sudo nano /etc/default/grub 找到GRUB_CMDLINE_LINUX="" 改为GRUB_CMDLINE_LINUX="net.ifnam ...
- LeetCode(21)Merge Two Sorted Lists
题目 Merge two sorted linked lists and return it as a new list. The new list should be made by splicin ...
- 杭电 1069 Monkey and Banana
Description A group of researchers are designing an experiment to test the IQ of a monkey. They will ...
- 转载:better-scroll的相关api
格式:var obj = new BScroll(object,{[option1,],.,.}); 注意:1.要确保object元素的高度比其父元素高 2.使用时,一定要确保object所在的dom ...
- IDEA+Tomcat热部署自动编译
https://www.cnblogs.com/1024zy/p/6344000.html 之前太傻瓜了,一直以为用了IDEA改了类或者js的时候全都要手动构建发布,其实不用,IDEA这么好的工具怎么 ...
- 杭电ACM省赛集训队选拔赛之热身赛-How Many Tables,并查集模板题~~
How Many Tables Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- C. The Smallest String Concatenation-C++sort排序~~
C. The Smallest String Concatenation time limit per test 3 seconds memory limit per test 256 megabyt ...
- Codeforces 892 A.Greed
A. Greed time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...