算法导论学习之线性时间求第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 ...
随机推荐
- 12. KEY_COLUMN_USAGE
12. KEY_COLUMN_USAGE KEY_COLUMN_USAGE表描述哪些键列具有约束. KEY_COLUMN_USAGE表有以下列: CONSTRAINT_CATALOG :约束所属目录的 ...
- 9. InnoDB通用表空间
9. InnoDB通用表空间 通用表空间是InnoDB 使用CREATE TABLESPACE语法创建的共享表空间.本节中的以下主题描述了常规表空间功能和功能: 通用表空间功能 创建通用表空间 将表添 ...
- QEMU支持的几种常见的镜像文件格式
qemu-img支持非常多种的文件格式,可以通过"qemu-img -h"查看其命令帮助得到,它支持二十多种格式:blkdebug.blkverify.bochs.cloop.c ...
- win7下qt error: undefined reference to `_imp__getnameinfo@28'解决
_imp__getnameinfo@28对应着winsock2.h的getnameinfo函数 首先需要导入对应的头文件 #ifndef WIN32 #include <sys/socket.h ...
- 剑指Offer(书):剪绳子
题目:给你一根长度为n的绳子,请把绳子剪成m段,每段绳子的长度记为k[0],k[1]....,k[m].请问k[0]xk[1]x...,k[m]可能的最大乘积是多少.例如:长度为8剪成2 3 3 得到 ...
- LeetCode(10) Regular Expression Matching
题目 Implement regular expression matching with support for '.' and '*'. '.' Matches any single charac ...
- c#如何判断textbox中输入的数据是datatime型的
()你好,标准的方法是用一个验证控件:RangeValidator,把type设为DateTime,最大值设为'3000-1-1'或者别的,最小值最好设为'1900-1-1'. ()程序里面自己验证: ...
- Pychorm提示Unresolved reference 导入模块报错
最近使用Pychorm编写Python时,每次要引入自定义模块,就会报错,提示“Unresolved reference” Unresolved reference 'LoginClass' more ...
- PTA 02-线性结构3 Reversing Linked List (25分)
题目地址 https://pta.patest.cn/pta/test/16/exam/4/question/664 5-2 Reversing Linked List (25分) Given a ...
- HDU 4334 5-sum
题目大意: 从5个集合中个选取一个数出来,使5个数相加之和为0 , 判断是否存在这种可能 因为集合数目最多200,那么200^3 = 8000000 , 那么这里很明显要把5个数拆成2个和3个计算,因 ...