求数组第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
    评论
要求在O(n)的时间复杂度下找出整数数组的第k小元素,可以使用快速选择算法(QuickSelect)来实现。快速选择算法是基于快速排序算法的一种改进,它通过每次选择一个基准元素数组分为两部分,并根据基准元素的位置来确定第k小元素所在的区间,从而减少了排序的时间复杂度。 以下是使用Java实现快速选择算法找出数组的第k小元素的代码: ```java import java.util.Random; public class QuickSelect { public static int findKthSmallest(int[] nums, int k) { if (nums == null || nums.length == 0 || k <= 0 || k > nums.length { throw new IllegalArgumentException("Invalid input"); } return quickSelect(nums, 0, nums.length - 1, k - 1); } private static int quickSelect(int[] nums, int start, int end, int k) { if (start == end) { return nums[start]; } int pivotIndex = partition(nums, start, end); if (pivotIndex == k) { return nums[pivotIndex]; } else if (pivotIndex < k) { return quickSelect(nums, pivotIndex + 1, end, k); } else { return quickSelect(nums, start, pivotIndex - 1, k); } } private static int partition(int[] nums, int start, int end) { int pivotIndex = new Random().nextInt(end - start + 1) + start; int pivot = nums[pivotIndex]; swap(nums, pivotIndex, end); int i = start; for (int j = start; j < end; j++) { if (nums[j] < pivot) { swap(nums, i, j); i++; } } swap(nums, i, end); return i; } private static void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } } ``` 使用示例: ```java public class Main { public static void main(String[] args) { int[] nums = {3, 2, 1, 5, 6, 4}; int k = 2; int result = QuickSelect.findKthSmallest(nums, k); System.out.println("第" + k + "小元素是:" + result); } } ``` 输出结果为: ``` 第2小元素是:2 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值