求数组第k小的元素 要求复杂度在O(n)

 http://user.qzone.qq.com/380171063/blog/1257414387

 



 通常情况下,这个比快速排序要高效: 因为快速排序要同时处理被分割的2段, 而此方法只需要处理一段; 
*/

原理类似与quicksort,都是分治。不同在与,FindKthNumMax()只需要对其中一个分组进行递归
 该方法最坏复杂度为O(n^2), 但是平均复杂度有O(n)
 复杂度取决于进行partition()的时候基准值pivot的选择,可以使用随机选择基准值

 

为什么平均复杂度有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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值