从一个序列中获取前K大的数的一种方法

这个方法是利用快速排序的。在快速排序中,得到中间元素(pivot)之后,比较中间元素之前的元素个数和K的大小关系,从而确定后面该往哪个方向继续递归。如果中间元素前面的元素个数等于K,那就停止递归过程;如果中间元素前面元素个数小于K,那就再中间元素后面进行递归;否则就往中间元素前面进行递归。这样最终得到的是没有排序的前K大的元素,这样再对前K个元素进行一次真正的快速排序。这样就能得到排好序的前K大元素。我随机生成了一个100000个整型数据的文件进行测试,求前10000个元素。这样做用了0.984s,然后如果直接用快速排序对整个序列进行快速排序,再取前100个的话,用了1.05。这在某种程度上优化了这个问题。

#include<iostream>
#include<string>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<ctime>
using namespace std;
template<typename elem>
class Quicksort
{
	inline int static partition(elem a[],int l,int r,elem& pivot)
	{
		do
		{
			while(a[++l]<pivot) ;
			while(l<r&&pivot<a[--r]);
			swap(a[l],a[r]);
		}while(l<r);
		return l;
	}
public:
	static void sort(elem a[],int i,int j)//
	{
		if(i>=j) return;
		int pivotindex=(i+j)/2;//get the pivot
		swap(a[pivotindex],a[j]);//swap the pivot with the last one of the array
		int k=partition(a,i-1,j,a[j]);//get the correct index of the pivot after partition
		swap(a[k],a[j]);
		sort(a,i,k-1);//recursion
		sort(a,k+1,j);//recursion
	}
	static void TopN(elem a[],int i,int j,int n)//get the top N from a[i],...,a[j]
        {
 		 if(i>=j) return ;
  		int pivotindex=(i+j)/2;
  		swap(a[pivotindex],a[j]);
  		int k=partition(a,i-1,j,a[j]);
  		swap(a[k],a[j]);
  		int tem=k-i;
 		 if(tem==n||tem==n-1) return ;
  		else if(tem<n-1)TopN(a,k+1,j,n-tem-1);
  		else if(tem>n) TopN(a,i,k-1,n);
 	}
};
int a[100005];
int main()
{
 
	clock_t start=clock();
 	freopen("rand.txt","r",stdin);
 	for(int i=0;i<100000;i++) scanf("%d",&a[i]);
 	Quicksort<int>::TopN(a,0,99999,10000);
 	Quicksort<int>::sort(a,0,9999);
 	for(int i=0;i<9999;i++) printf("%d ",a[i]);
 	printf("\n");
 	cout<<"time used:"<<(double)(clock()-start)/CLOCKS_PER_SEC<<"s"<<endl;
}





时间: 2024-08-02 11:02:18

从一个序列中获取前K大的数的一种方法的相关文章

统计前k大的数x

我终于敲上了题目--记起来啦! 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000. 第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整数的绝对值不超过100000000. 第三行包含一个整数k.k < n. 输出 从大到小输出前k大的数,每个数一行. 样例输入 10 4 5 6 9 8 7 1 2 3 0 5 样例输出 9 8 7 6 5 //AC自动机x #include<iostream&

openjudge 7617:输出前k大的数

7617:输出前k大的数 查看 提交 统计 提问 总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000.第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整数的绝对值不超过100000000.第三行包含一个整数k.k < n. 输出 从大到小输出前k大的数,每个数一行. 样例输入 10 4 5 6 9 8 7 1

输出前 k 大的数

总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000.第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整数的绝对值不超过100000000.第三行包含一个整数k.k < n. 输出 从大到小输出前k大的数,每个数一行. 样例输入 10 4 5 6 9 8 7 1 2 3 0 5 样例输出 9 8 7 6 5 分

OpenJ_Bailian 7617 输出前k大的数

题目传送门 OpenJ_Bailian 7617 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000.第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整数的绝对值不超过100000000.第三行包含一个整数k.k < n. 输出 从大到小输出前k大的数,每个数一行. 样例输入 10 4 5 6 9 8 7 1 2 3 0 5 样例输出 9 8 7 6 5 解题思路: emmmmm直接sort排序然后输

无序数组中找第k大的数

类快排算法 由于只要求找出第k大的数,没必要将数组中所有值都排序. 快排中的partition算法,返回key在数组中的位置的cnt(相对于left的偏移量),如果cnt正好等于k,那么问题则得到解决:如果cnt小于k,去左边找第k个:如果cnt>k,则去右边找第k-cnt个.直到key的位置等于k-1,则找对问题的解. /*快排中的划分算法*/ int partition(int* input, int low, int high) { int tmp = input[low]; // 取一个

若干个(大量)数字中找前K大/小的元素--数值型

方法一:根据快速排序划分的思想 : (1) 递归对所有数据分成[a,b)b(b,d]两个区间,(b,d]区间内的数都是大于[a,b)区间内的数 : (2) 对(b,d]重复(1)操作,直到最右边的区间个数小于100个. 注意[a,b)区间不用划分 :因为[a,b)区间一定小于(b,d]区间: (3) 返回上一个区间,并返回此区间的数字数目. 如果个数大于100,对(b,d]重复(1)操作,直到最右边的区间个数小于100个: 如果个数小于100,对上一区间的左边进行划分,分为[a2,b2)b2(b

第k大的数,前k大的数

1.排序后去出前k个,o(n*log(n))    如果k<log(n),可以考虑直接选择排序,因为只需要执行找到第k个就可以结束 o(n*k) 2.o(nlog(k))快排把数分为了两个部分,所以考虑两个情况,如果大的部分的个数>k,说明只要继续在大的部分找就可以了, 如果大的部分的个数<k,先把这些数取了,然后继续在小的部分里面找剩下的数(k-大的部分的个数)就可以了. 3.o(nlog((maxv-minv)/delta)),平均为o(nlogn)   转化为找第k个,  假设最大

获取第K大的数

使用快速排序,从数组中随机找出一个元素X,把数组分成比X小和比X大的两部分,假设比X小的部分元素个数为B,则: (1)   如果B >= K,则递归从比X小的部分找第K大的元素. (2)   如果B < K,则递归从比X大的部分找第(K-B)大的元素. 2.      (1) 使用最小堆,类似笔试题中O(NlogM)的算法. (2)   使用最大堆,类似于笔试题中O(MlogN)的算法. int getparent(int begin,int end,int index){ int paren

通过ResultSet获取到rs的记录数的几种方法

方法一:利用ResultSet的getRow方法来获得ResultSet的总行数 ResultSet rs = ps.executeQuery(sql); rs.last(); //移到最后一行 int rowCount = rs.getRow();//得到当前行号,也就是记录数 rs.beforeFirst(); //如果还要用结果集,就把指针再移到初始化的位置 方法二:利用循环ResultSet的元素来获得ResultSet的总行数 ResultSet rs = ps.executeQuer