http://user.qzone.qq.com/380171063/blog/1257414387
为什么平均复杂度有O(n) ?在等概率条件下,每次partition划分落在1/2处附近的可能性最高, 其递归公式近似于 T(n) = T(n/2) + O(n); 1)其中T(n/2)是等概率条件下的FindKthNumMax( a, start, i-1, k ); 或 FindKthNumMax( a, i+1, end, k-(i-start+1) ) 的时间; 2)O(n) 是partition() 时间 根据分治法的经典公式 S(n) = a * S( n/b ) + n^d ; 当 d> log b (a) 时 S(n) = n ^d ; 所以可以推出这里的T(n) = n^1 = O( n )
最坏情况下: 和QuickSort类似数组已经基本按照从到小的顺序排列,每次分治正好是i-- (i=partition())的这么一个过程。那么T(n) = T(n-1) + O(n) ; 这时候的T(n) = (1+n) * n / 2 = O( n^2 ); | |
| |
|
我的C++实现
void CTestFor2009::TestFindKthNumMax()
{
//int const len = 16 ;
int a[] = { 4,1,3,2,5,7,8,6,9,0,-7 }, k = 4, i = 10;
printf( "寻找数组第k大的元素,请输入k:" );
while ( scanf( "%ld", &k ) ){
int pivot_index = FindKthNumMax( a, 0, sizeof(a)/sizeof(a[0])-1, k ); //这个方法改变了a[]里面的顺序
printf( "数组的第%ld大的数是%ld /n",k, a[pivot_index] );
}
}
int CTestFor2009::FindKthNumMax( int a[], int start, int end, int k )
{
if ( end - start < 0 || start < 0 || k < 0 || a == NULL )
{
return -1; //表示出错了
}
if ( start == end || k == 0 )
{
return start;
}
int min, i, iKthIndex;
if ( end - start < k ) //k比数组下标小1, 当数组覆盖范围<k时候,直接返回里面最小的一个数字
{
min = a[ iKthIndex=start ];
i = start+1;
for ( ; i <= end; i++ )
{
if( a[i] < min ){ //输出最小的一个,它是第kth大的数
min = a[ iKthIndex=i ];
}
}
}
else{ //这部分是关键!
i = Partition( a, start, end, start+k-1 ); //pivot 可以自由选择,这里选取a[start+k-1] 为基准值
if ( k-1 < i-start ) //k比数组下标小1
{
iKthIndex = FindKthNumMax( a, start, i-1, k );
}
else if ( k-1 == i-start )
{
iKthIndex = i;
}
else { //k+1 > i-start
iKthIndex = FindKthNumMax( a, i+1, end, k-(i-start+1) );
}
}
return iKthIndex;
}
int CTestFor2009::Partition( int a[], int start, int end, int pivot )
{
int target = a[pivot]; //几乎和QuickSort的没有区别
int low = start, high = end;
a[pivot] = a[low];
while ( high > low )
{
for ( ; a[high] <= target && high > low; ) high--;
a[low] = a[high];
for ( ; a[low] >= target && high > low; ) low++;
a[high] = a[low];
}
a[low] = target;
return low;
}