解法一是最基本的排序算法,本文略过。
解法四依赖最大堆这个数据结构,多用于海量数据处理,本文略过。
重点实现了解法二和解法三。
解法二的思想是利用快排的以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;
}