得到第K个大的数算法研究

第一种算法是最容易想到的,就是利用快速排序的思想,将一个数组分成以某一个数X为轴,左边的所有的数都比X小,而右边的数都比X大。但我快速排序不同的是,在这个算法中只考虑X的一边,而不是两边都考虑。

   如果X的位置是i,那么要得到第k个数,如果k<=i, 那么这个数一定在i的左边,否则在i的右边。

源码如下:

#include  < stdio.h >
#include 
< stdlib.h >
int  new_random( int  min,  int  max)
{
    
return  (min  +  ( int )((( float )rand() / RAND_MAX) * (max  -  min)));
}
void  swap( int   * a,  int   * b)
{
    
int  c  =   * a;
    
* =   * b;
    
* =  c;
}

int  partition( int  A[],  int  p,  int  r)
{
    
int  i  =  p  -   1 , j;
    
for (j  =  p; j  <  r; j ++ )
    {
        
if (A[j]  <=  A[r])
        {
            i
++ ;
            swap(
& A[i],  & A[j]);
        }
    }
    swap(
& A[i  +   1 ],  & A[r]);
    
return  i  +   1 ;
}

int  randomize_partition( int  A[],  int  p,  int  r)
{
    
int  i  =  new_random(p, r);
    swap(
& A[i],  & A[r]);
    
return  partition(A, p, r);
}

// 第一种算法
int  randomized_select( int  data[],  int  p,  int  r,  int  k)
{
    
if (k  >  (r  -  p  +   1 ))  return   0 ;
    
if (p  ==  r)  return  data[p];
    
int  i  =  randomize_partition(data, p, r);
    
// int i = partition(data, p, r);  // 不好使,死循环, 必须用随机数,在第二步时总是在最大数处划分

    
int  count  =  i  -  p  +   1 ;
    
if (k  <=  count)
        
return  randomized_select(data, p, i, k);
    
else
        
return  randomized_select(data, i  +   1 , r, k  -  count);
}


    另外一种对这种算法做了一下改进,即将数组每5个数一组进行排序,然后取得它的中位数,再对这些中位数进行排序。然后先出的轴X最比较好的,因此X的左边和右边的数总是很平均,所以平均查找速度更快。算法如下:

void  quicksort( int  data[],  int  b,  int  e)
{
    
if (b  <  e)
    {
        
int  k  =  partition(data, b, e);
        quicksort(data, b, k 
-   1 );
        quicksort(data, k 
+   1 , e);
    }
}

int  partition1( int  A[],  int  p,  int  r,  int  x)
{
    
int  i  =  p  -   1 , j;
    
for (j  =  p; j  <=  r; j ++ )
    {
        
if (A[j]  <=  x)
        {
            i
++ ;
            swap(
& A[i],  & A[j]);
        }
    }
    A[i 
+   1 =  x;
    
return  i  +   1 ;
}
// 第二种算法
int  select_new( int  data[],  int  p,  int  r,  int  k)
{
    
if (r  -  p  <   75 )
    {
        quicksort(data, p, r);
        
return  data[p  +  k  -   1 ];
    }   
    
int  i;
    
for (i  =   0 ; i  <=  (r  -  p  -   4 /   5 ; i ++ )
    {
        quicksort(data, p 
+   5   *  i, p  +   5   *  i  +   4 );
        swap(
& data[p  +   5   *  i  +   2 ],  & data[p  +  i]);
    }
    
int  x  =  select_new(data, p, p  +  (r  -  p  -   4 /   5 , (r  -  p  -   4 ) / 10 );  //  得到更好的轴X
    i  =  partition1(data, p, r, x);
    
int  count  =  i  -  p  +   1
    
if (k  <=  count)
        
return  select_new(data, p, i, k);
    
else
        
return  select_new(data, i  +   1 , r, k  -  count);
}

int  main()
{
    
int  data[]  =  { 3 1 7 34 8 11 678 12 - 1 100 };
    printf(
" %d\n " , randomized_select(data,  0 9 2 ));
    
int  data1[]  =  { 3 1 7 34 8 11 678 12 - 1 100 };
    printf(
" %d\n " , select_new(data1,  0 9 2 ));
   
     
return   0 ;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值