编程之美找寻最大的K个数

解法一是最基本的排序算法,本文略过。

解法四依赖最大堆这个数据结构,多用于海量数据处理,本文略过。

重点实现了解法二和解法三。

解法二的思想是利用快排的以O(n)的时间得到某个数组中任意元素序号p,有A[i] <= A[x], r<=i<=p, A[j] > A[p], p<j<=r, 然后再配合二分查找,可以得到O(n*lgK)的算法。该算法比解法三要容易理解,但是在实际做的过程中,发现最大的问题在于边界条件的处理,即应注意数组下标和元素个数是两个不同的概念,两者混淆的话很容易把自己绕进去,另外从完备性的角度考虑还应考虑异常处理,如果数组中所有元素为同一数值,那么该解法会导致死循环,该如何处理?

解法三则从数值的角度采用了二分搜索。是一种不同的思路,相比较解法二,我认为这种方法是实现难度最低的。效率同样也是O(n*lgK)


// FindMaxK.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdlib.h>

void swap(int A[], int i, int j)
{
	int t = *(A + i);
	*(A + i) = *(A + j);
	*(A + j) = t; 
}

int partition(int A[], int r, int q)
{
	if(r < q)
	{
		int t = r + rand() % (q - r) + 1;
		swap(A, t, r);
		int j = r;
		for(int i = r + 1; i <= q; i++)
		{
			if(A[i] <= A[r])
			{
				j++;
				swap(A, i, j);
			}
		}
		swap(A, r, j);
		return j - r;

	}
	return -1;
}

void FindMaxK1(int A[], int r, int q, int k)
{
	int p = partition(A, r, q);
	if( p > k )
	{
		FindMaxK1(A, r, p,k);
	}
	else if( p < k )
	{
		FindMaxK1(A, p + 1, q,k - p );
	}

}


int count(int A[], int len, float v)
{
	int count = 0;
	for(int i = 0; i < len; i++)
	{
		if(A[i] >= v)
			count++;
	}
	return count;
}


int FindMax2(int A[], int len, int k)
{
	if(len <= 0)
		return -1;
	float min = A[0];
	float max = A[0];
	for(int i = 0; i < len; i++)
	{
		if(A[i] > max)
			max = A[i];
		if(A[i] < min)
			min = A[i];
	}

	float delta = 0.5;

	while ( max - min > delta )
	{
		float mid = min + (max - min) / 2;
		if(count(A, len, mid) > k)
		{
			min = mid;
		}
		else
		{
			max = mid;
		}
	}

	for(int i = 0; i < len; i++)
	{
		if(A[i] >= min && A[i] <= max)
			return A[i];
	}
	
}



enum {len = 6};

void Test()
{
	int A[] = {4,3,1,7,5,2};
	int k = 3;
	FindMaxK1(A, 0, len - 1, k);
	for(int i = 0; i < len; i++)
	{
		printf("%d ", A[i]);
	}
	int v = FindMax2(A, len, k);
	printf("%d ", v);
}

int _tmain(int argc, _TCHAR* argv[])
{
	Test();
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值