题目:求前k大的数
给定一个数组包含n个元素,统计前m大的数并且把这m个数从大到小输
出。
输入:
第一行包含一个整数n,表示数组的大小。n < 100000。
第二行包含n个整数,表示数组的元素,整数之间以一个空格分开
。每个整数的绝对值不超过100000000。
第三行包含一个整数m。m < n。
输出:
从大到小输出前m大的数,每个数一行
思路:
最直接的利用c++自己的快排函数,但是这里介绍一下自己写的快排如何优化。
优化点:将前k的数都移到数组的右边,但不需要保证这些前k大的数之间是有序的。然后再对右边的k个数进行快排。
如何将前k大的都弄到最右边 :arrangeRight操作
1)设key=a[0], 将key挪到适当位置(利用快排的思想),使得比key小的元素都在
key左边,比key大的元素都在key右边(线性时间完成)
2) 选择数组的前部或后部再进行 arrangeRight操作-----降低了快排里面的两边都要进行
void arrangeRight(int a[], int s, int e, int k)
{
if(s >= e)
return;
if(k == e-s+1)//判断区间是否为k,及时返回终止
return;
int i = s;
int j = e;
int key = a[s];//注意!!!!
while(i != j)
{
while(i < j && a[j] >= key)
--j;
swapM(a[i],a[j]);
while(i < j && a[i] <= key)
++i;
swapM(a[i],a[j]);
}//key值下标更换,但最后下标是i!!!!,可自己画图跟踪。
//如果右边的数刚好为e-i+1为k个
if(k == e - i + 1)
return;
//右边的数大于k个
else if(k < e - i + 1)
{
arrangeRight(a,i+1,e,k);
}
//右边的数小于k个,需要左边取出k - (e-i+1)个
else
{
arrangeRight(a,s,i-1,k-e+i-1);
}
}
快排代码:
void quicksort(int a[],int l,int r)
{
if(i==r)
return ;
int i=l,j=r,k=a[l];
while(i != j){
while(i<j&&a[i]<=k){
i++;
}
swap(a[i],a[j]);
while(j>i&&a[j]>=k){
j--;
}
swap(a[i],a[j]);
}
//每次排序都保证了一个数的位置i,使左边的数都比这个数小,右边的都比这个数大
quicksor(a,l,i-1);
quicksort(a,i+1,r);
}
**探讨:**快排和归并的区别
快排是从大到小(递归实现),归并是从小到大(递归实现),快排的定位,归并是捋顺