• 再谈大于指定正整数的最小“不重复数”问题


      对于“大于指定正整数的最小“不重复数”问题”,最初,在 算法:求比指定数大且最小的“不重复数”问题的高效实现 中,我给出了一个递归写法,之后在同一篇博文中给出了一个非递归写法。

      后来在 对Alexia(minmin)网友代码的评论及对“求比指定数大且最小的‘不重复数’问题”代码的改进 中对我的写法进行了更详细的说明,并进行了重要改进。使之适合范围更大。

      在 评playerc网友的"求比指定数大且最小的“不重复数”问题"  中评论了playerc的写法。

      playerc的思路没问题,但代码复杂且存在错误。现在我按照这个思路给出我的写法。

         详细的分析求解过程,就不在正文中描述了。代码中有详尽的注释,在前几篇博文中也进行了说明。这次写法与前面的主要不同点的是,实现了只一次加0101……。 

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 #define SIZE(x) (sizeof (x) / sizeof (x)[0])
      5 #define BE_DIG(x) ( '0' <= x && x <= '9' ) 
      6 #define MAX 128  
      7 
      8 typedef  struct
      9          { 
     10             unsigned char digs[ MAX + 1 ] ;//从低位到高位存储各位数字 
     11                                            //并为可能发生的进位预留一个位置  
     12             unsigned char * p_high ;       //记录最高位数字位置 
     13          }  
     14 Number ; 
     15   
     16 void input( Number * ); 
     17 void reverse( unsigned char * , unsigned char * );
     18 void exchange( unsigned char * , unsigned char * ); 
     19 void squeeze( unsigned char * , unsigned char * * );
     20 void output( const unsigned char * , const unsigned char * ) ;  
     21 void seek( unsigned char * , unsigned char * * );
     22 void add_1( unsigned char * , unsigned char * * );
     23 unsigned char * search ( unsigned char * , unsigned char * );
     24 
     25 int main( void ) 
     26 {
     27    Number num ;
     28    
     29    input( & num );                    //输入正整数
     30    seek( num.digs , & num.p_high );   //求不重复数
     31    output( num.p_high , num.digs );   //输出
     32     
     33    return 0; 
     34 } 
     35 
     36 /*
     37   输入数字到 p_n -> digs数组 ,p_high 记录最高位位置 
     38 */
     39 void input( Number * p_n )
     40 {
     41    int c ;
     42    size_t max = SIZE(p_n -> digs) - 1u ;        //预留进位位置,最多输入数字位数 
     43    
     44    p_n -> p_high = p_n -> digs ;
     45    
     46    while ( c = getchar() , BE_DIG( c ) && max -- > 0u ) 
     47       * p_n -> p_high ++ = c - '0' ; 
     48    
     49    if( p_n -> p_high == p_n -> digs )               //没有输入数字
     50       exit( 1 );
     51    
     52    -- p_n -> p_high ;
     53    reverse( p_n -> digs ,   p_n -> p_high );       //颠倒次序
     54    squeeze( p_n -> digs , & p_n -> p_high );       //去掉开头的0 
     55 }
     56 
     57 /*
     58   将从p_b指向的数字到p_e指向的数字逆序排列。123 -> 321 
     59 */
     60 void reverse( unsigned char * p_b , unsigned char * p_e )
     61 { 
     62    while ( p_e > p_b )
     63       exchange( p_b ++ , p_e -- );
     64 } 
     65 
     66 void exchange( unsigned char * p1 , unsigned char * p2 ) 
     67 { 
     68    unsigned char c = * p1 ; 
     69    * p1 = * p2 ; 
     70    * p2 = c ; 
     71 } 
     72 
     73 /*
     74   去掉多余的高位0。00123 -> 123 
     75 */
     76 void squeeze( unsigned char * p_b , unsigned char * * pp_e )
     77 { 
     78    while ( * pp_e > p_b && * * pp_e == 0 )
     79       -- * pp_e ;
     80 } 
     81 
     82 /*
     83    * p_l指向最低位,* pp_h指向最高位
     84    
     85    (A)首先最左位加1           (left) 2 2 1 1 => 3 2 1 1  
     86    由高到低查找重复位         3 2 (1) 1
     87    新的区间为                 (left)(1) 1
     88    转到(A)                    3 2 (2) 1
     89    (2) 1间没有重复数字,循环结束
     90    
     91    从 left-1 到 p_l 写010101……    
     92 */ 
     93 void seek( unsigned char * p_l , unsigned char * * pp_h )
     94 {
     95    unsigned char * break_p = p_l ;
     96    unsigned char * left ;      
     97    
     98    do
     99    {
    100       left = break_p ;          
    101       add_1( left , pp_h );                         //[left , *pp_h]区间内最左位加1
    102    }
    103    while ( ( break_p = search ( left , * pp_h ) ) != NULL );//NULL:不能找到重复数字 
    104    
    105    //从 left-1 到 p_l 写010101…… 
    106    while ( left > p_l )
    107    {
    108       left[-1] = ! * left ;
    109       left -- ; 
    110    }
    111 }
    112 
    113 /*
    114   加1。处理了可能的进位,以及pp_h所指向的记录最高位位置指针可能的改变  
    115 */ 
    116 void add_1( unsigned char * p_l , unsigned char * * pp_h )
    117 {
    118    ++ * p_l ;                                     //最低位加1
    119    while ( p_l < * pp_h )                         //进位处理
    120    {
    121       * ( p_l + 1 ) += * p_l / 10 ;
    122       * p_l ++ %= 10 ; 
    123    }
    124    if ( * * pp_h > 9 )                            //最高位有进位 
    125    {
    126       * ( * pp_h + 1 ) = * * pp_h / 10 ;
    127       * (* pp_h) ++  %= 10 ;
    128    }
    129 }
    130 
    131 /*
    132   搜索p_h到p_l所指向数字中第一个重复数字的位置,如无则返回NULL 
    133 */ 
    134 unsigned char * search ( unsigned char * p_l , unsigned char * p_h )
    135 {
    136    if ( p_h == p_l )      //一位数情形 
    137       return NULL ;
    138 
    139    while ( p_l + 1 < p_h )                        
    140    {
    141       if ( * p_h ==  p_h[-1] )
    142          return p_h - 1 ;
    143       p_h -- ;
    144    }
    145    
    146    if ( * p_l ==  p_l[1] )
    147       return p_l ;
    148 
    149    return NULL ;      
    150 }
    151 
    152 /*
    153   输出p_h指向的数字到p_l指向的数字 
    154 */
    155 void output( const unsigned char * p_h , const unsigned char * p_l )
    156 { 
    157    while ( p_h > p_l )
    158       printf( "%u" , * p_h -- );
    159 
    160    printf( "%u" , * p_l );
    161    putchar('
    ');
    162 } 
  • 相关阅读:
    腾讯云挂载文件服务器节点
    OpsManage 安装
    centos7 安装mysql
    vs code 新建vue项目
    Centos7 安装supervisor
    腾讯云Centos7 安装nginx
    django 生成pdf
    VM安装虚拟机
    ACM/ICPC 之 Floyd练习六道(ZOJ2027-POJ2253-POJ2472-POJ1125-POJ1603-POJ2607)
    ACM/ICPC 之 Floyd范例两道(POJ2570-POJ2263)
  • 原文地址:https://www.cnblogs.com/pmer/p/3367318.html
Copyright © 2020-2023  润新知