选择问题(selection problem)

/*
    本文是选择问题:

          选择一组N个数当中的第k小的数(第k大的数类似)
     集中方法的实现代码

*/
 
 
 
#include "sorting.h"
#include "fatal.h"
 
#define SORTING_BUBBLE  1
#define SORTING_INSERTION   2
#define SORTING_SELECTION   3
#define SORTING_SHELL       4
#define SORTING_QUICK       5
#define SORTING_HEAP        6
#define SORTING_MERGE       7
 
 
/*
    解法1: 我们可以对这个乱序数组按照从小到大先行排序,然后

     取出前k大,总的时间复杂度为O(n*logn + k)。

*/
 
int  select_by_sorting ( int  A [],  int  N ,  int  k ,  int  SortingMethod )
{
     if ( k  < 1  ||  k  >  N  )
     {
        fprintf  ( stderr ,  "error, k ??????\n" );
        exit  ( EXIT_FAILURE );
     }
     switch ( SortingMethod )
     {
     case  SORTING_BUBBLE  :
        bubble_sort  ( A ,  N , IntComp );
          return  A [  k - 1 ];
     case  SORTING_INSERTION  :
        insertion_sort  ( A ,  N , IntComp );
          return  A [  k - 1 ];
     case  SORTING_SELECTION  :
        selection_sort  ( A ,  N , IntComp );
          return  A [  k - 1 ];
     case  SORTING_SHELL  :
        shell_sort  ( A ,  N , IntComp );
          return  A [  k - 1 ];
     case  SORTING_QUICK  :
        quick_sort  ( A ,  N , IntComp );
          return  A [  k - 1 ];
     case  SORTING_HEAP  :
        heap_sort  ( A ,  N , IntComp );
          return  A [  k - 1 ];
     case  SORTING_MERGE  :
        merge_sort  ( A ,  N , IntComp );
          return  A [  k - 1 ];
     default :
        Error  ( "not a known sorting method!" );
     }
     return  0 ;
}
/*
    解法2: 先把前k个元素读进数组并排序(递增顺序),接着,将剩下

     的元素逐个读入。当新元素大于数组中的第k个元素是则忽略,否则将
     其放入正确的位置,旧的第k个元素将被挤掉!

*/
int  select2 ( int  A [],  int  N ,  int  k )
{
     // 可改进为前面k个数原地排序。
     int  * Ak  =  malloc ( sizeof ( int  )* k );
    Ak [ 0  ]  =  A [ 0 ];
     int  i , j  ;
     for ( i  =  1 ;  i  <  k ;  i ++)
     {
          for ( j  =  i -  1 ;  j  >=  0  ;  j --)
          {
              if ( A  [ i ]<  Ak [ j ])
                Ak  [ j +  1 ]  =  Ak [  j ];
              else
                  break ;
          }
        Ak  [ j +  1 ]  =  A [  i ];
     }
     for ( i  =  k  ;  i  <  N ;  ++ i  )
     {
          if ( Ak  [ k -  1 ]<=  A  [ i ])  continue ;
        
          for ( j  =  k -  2 ;  j  >= 0 ;  -- j )
          {
              if ( A  [ i ]  <  Ak [ j  ])
                Ak  [ j +  1 ]  =  Ak [  j ];
              else
                  break ;
          }
        Ak  [ j +  1 ]  =  A [  i ];
     }
     int  ret  =  Ak  [ k -  1 ];
    free ( Ak  );    
     return  ret  ;
}
 
/*
    解法3:利用选择排序或交互排序,K次选择后

     即可得到第k大的数。总的时间复杂度为O(n*k)

*/
 
int  select3 ( int  A [],  int  N ,  int  k )
{
     int  minIndex  ;
     int  tmp ;
     int  i , j  ;
     for ( i  =  0 ;  i  < k ;  ++ i )
     {
        minIndex  =  i ;
          for ( j  =  i +  1 ;  j  < N ;  ++ j )
              if ( A  [ minIndex ]  >  A  [ j ])
                minIndex  =  j ;
        tmp  =  A [  minIndex ];
        A  [ minIndex ]  =  A  [ i ];
        A  [ i ]  =  tmp ;
     }
     return  A  [ k -  1 ];
}
 
/*
    解法4:利用快速排序的思想,从数组S中随机找出一个元素X,

     把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素
     小于X。这时有两种情况:
          1. Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数;
          2. Sa中元素的个数大于等于k,则返回Sa中的第k大数。时间复杂度近似为O(n)

 
*/
int  partition ( int  A [],  int  p ,  int  q )
{
     // select a pivot
     // for simplicity select p as pivot
     int  i , j  ;
    i  =  p  ;
     int  tmp ;
     for ( j  =  p  + 1 ;  j  <=  q  ;  j ++)     
     {
          if ( A  [ j ]  <  A [ p  ])
          {
              ++ i ;
              if ( i  ==  j )
                  continue ;
            tmp  =  A [  i ];
            A  [ i ]  =  A [ j  ];
            A  [ j ]  =  tmp ;
          }
     }
    tmp  =  A  [ i ];
    A [ i  ]  =  A [ p ];
    A [ p  ]  =  tmp ;
     return  i  ;
}
int  findk (  int  A [],  int  p ,  int  q ,  int  k )
{
     int  r  =  partition  ( A ,  p , q );
     if ( k - 1  ==  r )
          return  A [  r ];
     else  if ( r  >  k  -  1 )
     {
          return  findk (  A , p , r  - 1 ,  k );
     } else
          return  findk (  A , r + 1  , q ,  k );
}
int  select4 ( int  A [],  int  N ,  int  k )
{
     return  findk  ( A ,  0 , N  - 1 ,  k );
}
 
 
#define ITEMNUM 5000
#define METHODNUM 10
int  main ()
{
     int  A [ METHODNUM  ][ ITEMNUM ];
     int  k  =  564 ;
     int  temp ;
     for ( int  i  =  0  ;  i  <  ITEMNUM ;  ++ i )
     {
        temp  =  rand ();
          for ( int  j  =  0 ;  j  <  METHODNUM ;  j ++)
            A  [ j ][  i ]  =  temp  ;
     }
    
     int  r1 , r2  , r3 ,  r4 , r5 , r6  , r7 ,  r8 ;
    r1  =  select_by_sorting  ( A [  0 ], ITEMNUM  , k ,  SORTING_BUBBLE );
    r2  =  select_by_sorting  ( A [  1 ], ITEMNUM  , k ,  SORTING_INSERTION );
    r3  =  select_by_sorting  ( A [  2 ], ITEMNUM  , k ,  SORTING_SELECTION );
    r4  =  select_by_sorting  ( A [  3 ], ITEMNUM  , k ,  4 );
    r5  =  select_by_sorting  ( A [  4 ], ITEMNUM  , k ,  5 );
    r6  =  select_by_sorting  ( A [  5 ], ITEMNUM  , k ,  6 );
    r7 =  select_by_sorting  ( A [  6 ], ITEMNUM  , k ,  7 );
    r8  =  select2  ( A [  7 ], ITEMNUM  , k );
     int  r9  =  select3  ( A [  8 ], ITEMNUM  , k );
    printf ( "%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n"  , r1 ,  r2 , r3 , r4  , r5 ,  r6 , r7 , r8  );
    printf ( "%d\n"  , r9 );
     int  r10  =  select4  ( A [  9 ], ITEMNUM  , k );
    printf ( "%d\n"  , r10 );
     return  0 ;
}

转载于:https://www.cnblogs.com/jimmysue/p/3815214.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值