获取第N小的值

template <class value_t>
int partition(value_t *arr, int first, int last)
{
	--last;
	int i = first - 1;
	int x = arr[last];
	for(int j = 0; j < last; ++j)
	{
		if(arr[j] <= x)
			++i, std::swap(arr[j], arr[i]);
	}
	std::swap(arr[i + 1], arr[last]);
	return i + 1;
}

template <class value_t>
int GetNthLeast(value_t* arr, int first, int last, int nth)
{
	assert(nth <= last);
	int pivot = partition(arr, first, last);

	if(pivot + 1 == nth)
		return arr[pivot];

	if(pivot + 1 < nth)
		GetNthLeast(arr, pivot + 1, last, nth);
	else
		GetNthLeast(arr, first, pivot, nth);
}

直接看上去,上面的代码貌似在last-first为0的时候,也会运行,实际上并不是如此。如果序列为0,说明上次是一个极差的划分,如果要找的元素不在povit上,那么它也一定不会在0区间里面。比如说,N长度的序列,被划分为[0,N),和[N+1,……],这样的区间。第二个区间是空的,那么找到的array[N]就是第N小的值,而且其左边的区间,也就是[0,N)里面的值都比它要小。如果要找比array[N]大的值,是找不到的,因为此时的array[N]已经是最大的值。在N长度的序列中找第N+1小的值,显然是不现实的(或者报错,或者返回第N小的值)。


下面来看一下算法的时间复杂度。当每次划分都是最糟时,一共需要n次划分,每次划分的复杂度为O(N),因此为O(N^2)。

在一般情况下,计算它的期望复杂度,如下图:

因此,平均情况下,任何的顺序统计量都可以在线性时间得到。

 

posted @ 2012-09-10 10:07  Gallagher  阅读(203)  评论(0)    收藏  举报