分治---输出前m大的数

题目描述:

给定一个数组包含n个元素,统计前m大的数并且把这m个数从大到小输出

代码:

#include<iostream>
using namespace std;
typedef int ElementType;
//分治处理  O(n+mlog(m))
//用O(n)把m大个数挪到右边,然后对这m个数快速排序再输出

//快速排列法
void Qsort(ElementType a[], int left,int right)
{
	if (left >= right)
		return;
	int low=left, high=right;
	int pivot = a[left];
	while (low<high)
	{
		while (a[high] >= pivot && low < high){ high--; }
		swap(a[low], a[high]);
		while (a[low] <= pivot && low < high){ low++; }
		swap(a[low], a[high]);
	}
	Qsort(a, left, low - 1);
	Qsort(a, low + 1, right);
}

//把数组前k大的都弄到最右边
void arrangeRight(ElementType a[], int left, int right, int k)
{
	if (left >= right)
		return;
	if (k == right - left + 1)  //要弄的数组元素的个数不能等于 k(因为 0 也算一个位置,所以要 +1 )
		return;
	int low = left, high = right;
	int pivot = a[low];
	while (low < high)         //停止循环后 low 和 high 处于同一位置
	{
		while (a[high] >= pivot && low < high){ high--; }
		swap(a[left], a[right]);
		while (a[low] <= pivot && low < high){ low++; }
		swap(a[low], a[high]);
	}
	if (right - low + 1 == k)				//右边的数刚好为e-i+1为k个
		return;
	else if (right - low + 1 > k)
		arrangeRight(a, low + 1, right, k);	//右边的数大于k个
	else
		arrangeRight(a, left, low-1, k-right+low-1);//右边的数小于k个,需要左边取出k - (right-low+1)个

}

void printM(ElementType a[],int n,int m)
{
	if (n < m)
		return;
	arrangeRight(a, 0, n - 1, m);	//O(N)时间内先把m大的都弄到数组最右边
	Qsort(a, n - m, n - 1);			//对这m个数排序
	for (int i = 0; i < m; i++, n--)
		cout << a[n - 1] << " ";
	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, 8);
	return 0;
}

我学到的:

C++使用swap()函数不用加头文件,因为其包含于std::标准名词空间中

解释一下本代码所用的快速排序法:
这种快速排序法与一般的没什么太大区别,一般的可以参考另一篇博客:快速排列法(简易版 → 复杂版),但主要的区别体现在代码的16至19行,它是while一次,swap一次,而一般的是先while两次,swap一次,相比较的话,本代码所用的比较慢,因为交换后可能存在还是不满足条件的情况,但这只能等下一次循环了,所以循环的此数会增加,所以还是先while两次,swap一次效率高 (所以本代码只是为了举例)

复杂度分析:

将前m大的都弄到数组最右边的时间:
T(n) = T(n/2) + a * n           //T(n/2)是当右边的数不等于k时继续分的情况, 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                     //最坏也不可能超过 2 * a * n   O(n);
而将前m大的元素排序,复杂度为O(mlog(m))

故整体的时间复杂度为:复杂度O(n+mlog(m))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值