例题:输出前m大的数
题目描述
给定一个数组包含n个元素,统计前m大的数并且把这m个数从大到小输出。
输入
第一行包含一个整数n,表示数组的大小。n < 100000。
第二行包含n个整数,表示数组的元素,整数之间以一个空格分开。每个整数的绝对值不超过100000000。第三行包含一个整数m。m < n。
输出
从大到小输出前m大的数,每个数一行。
题目分析
思路:用分治处理,把前m大的都弄到数组最右边,然后对这最右边m个元素排序,再输出。关键就是如何在O(n)时间内把前m大的都弄到数组最右边。
引入操作arrangeRight(k): 把数组前k大的都弄到最右边。
- 设key=a[0], 将key挪到适当位置,使得比key小的元素都在key左边,比key大的元素都在key右边(线性时间完成)
- 选择数组的前部或后部再进行arrangeRight操作
- a = k done
- a > k 对最右边a-1个元素再进行arrangeRigth(k)
- a < k 对左边b个元素再进行arrangeRight(k-a)
代码实现
#include<iostream>
using namespace std;
typedef int ElementType;
//用治处理 O(n+mlog(m))
//用O(n)把m大个数挪到右边,然后对这m个数排序再输出
void QuickSort(ElementType a[], int left, int right)
{
if (left >= right)
return;
int privot = a[left];
int low = left, high = right;
while (low != high)
{
while (high > low && a[high] >= privot) --high;
swap(a[low], a[high]);
while (low < high && a[low] <= privot) ++low;
swap(a[low], a[high]);
}
QuickSort(a, left, low - 1);
QuickSort(a, low + 1, right);
}
//把数组前k大的都弄到最右边
void arrangeRight(ElementType* a, int left, int right, int k)
{
if (left >= right)
return;
if (k == right - left + 1)
return;
int low = left;
int high = right;
int privot = a[left];
while (low != high)
{
while (low < high && a[high] >= privot) --high;
swap(a[low], a[high]);
while (low < high && a[low] <= privot) ++low;
swap(a[low], a[high]);
}
if (right - low + 1 == k) //如果右边的数刚好为e-i+1为k个
return;
else if (right - low + 1 > k) //右边的数大于k个
{
arrangeRight(a, low + 1, right, k);
}
else //右边的数小于k个,需要左边取出k - (e-i+1)个
{
arrangeRight(a, left, low - 1, k - right + low - 1);
}
}
void printM(ElementType* a, int n, int m)
{
arrangeRight(a, 0, n - 1, m); //O(N)时间内先把m大的都弄到数组最右边
QuickSort(a, n - m, n - 1); //对这m个数排序
while (m--)
{
cout << a[--n] << " ";
}
cout << endl;
}
int main()
{
int a[] = { 11, 4, 14, 6, 1, 12, 8, 9, 3, 13, 7, 10, 0, 5, 2, 15 };
int len = sizeof(a) / sizeof(a[0]);
printM(a, len, 6);
return 0;
}
复杂度分析:
将前m大的都弄到数组最右边的时间:
T(n) = T(n/2) + a*n
= T(n/4) + a*n/2 + a*n
= T(n/8) + a*n/4 + a*n/2 + a*n
= …
= T(1) + … + a*n/8 + a*n/4 + a*n/2 + a*n
< 2*a*n
即O(n)
将前m大的元素排序,复杂度为mlogm,所以整体的时间复杂度为:复杂度O(n+mlogm)