【问题标题】:Recursive function in C to determine if digits of an integer are sorted ascending, descending or neitherC中的递归函数,用于确定整数的数字是否按升序、降序或两者都不排序
【发布时间】:2020-04-04 04:47:55
【问题描述】:

我需要编写一个递归函数,如果整数的数字是升序(从左到右),则返回 1,如果降序则返回 -1,否则返回 0。

我的解决方案尝试每次都返回 0,我知道原因,但我不知道如何解决。

这是我的代码:

#include <stdio.h>

int check_order(int n)
{
    if (n % 10 > n / 10 % 10)
    {
        return check_order(n / 10);
        if (n == 0)
        {           
            return 1;
        }
    }
    else if (n % 10 < n / 10 % 10)
    {
        return check_order(n / 10);
        if (n == 0)
        {
            return -1;
        }
    }
    else
    {
        return 0;
    }
}

int main()
{
    int n;
    printf("enter a whole number (n > 9):");
    scanf_s("%d", &n);
    printf("function returned: %d\n", check_order(n));
}

【问题讨论】:

  • return check_order(n / 10); if (n == 0)。这显然是个问题。 return 之后的任何代码都不会被执行。
  • 请注意,if (n == 0) { return 1; } 后面的代码 return check_order(n / 10); 根本不会被执行。
  • 建议你在调试器中运行你的程序并逐行逐行查看它在做什么。从最简单的10 输入开始。
  • 在函数的第一行添加printf("n%%10=%d n/10%%10=%d\n", n%10, n/10%10);,紧跟在{之后。您可能会发现结果很有趣。
  • 你在错误的地方很少有回报。如果 n ≤ 9,你期望什么结果?

标签: c function recursion


【解决方案1】:

这是一个简单的递归:

int f(int n){
  if (n < 10)
    return 0;

  int dr = n % 10; // rightmost digit
  n = n / 10;
  int dl = n % 10; // second digit from the right 
  int curr = dl < dr ? 1 : -1; // current comparison 
  if (dl == dr) curr = 0; // keep strict order

  if (n < 10)
    return curr;

  return curr == f(n) ? curr : 0; // are the comparisons consistent?
}

【讨论】:

    【解决方案2】:

    解释你的算法?

    假设您使用以下内容:

    • 给你一个号码。
    • 您需要将该数字转换为数字序列。
      • 如果给您一个数字,您可以将该数字转换为数字序列。
      • 如果给定一个数字序列,请使用 那个。
    • 比较每对数字 -> 升序、降序或两者都不进行。
    • 按顺序/递归方式组合每对的结果。

    我们可以使用字符串来简化数字比较,并接受很长的数字序列。

    我们可以使用 enum(erated) 类型来表示排序。

    你如何组合结果?定义一个函数,将两个相邻重叠对的顺序组合起来,然后就可以组合结果。

    #include <stdio.h>
    #include <string.h>
    
    typedef enum { descending=-1, other=0, ascending=1 } order_t;
    
    order_t pair_order(int a, int b) {
        if( a < b ) return ascending;
        if( a > b ) return descending;
        return other;
    }
    
    //strict (increasing/decreasing)
    order_t strict_order( order_t x, order_t y ) {
        if( x == y ) return x;
        return other;
    }
    
    //monotone (increasing/decreasing)
    order_t monotone_order( order_t x, order_t y ) {
        if( x == y ) return x;
        if( other == x ) return y;
        if( other == y ) return x;
        return other;
    }
    
    order_t check_order( char* p, int remain ) {
        //printf("p:%s\n",p); //uncomment to watch progress
        if( remain<2 ) return other;
        if( remain==2 ) return pair_order(p[0], p[1]);
        return strict_order( pair_order(p[0], p[1]), check_order(p+1, remain-1) );
        //return monotone_order( pair_order(p[0], p[1]), check_order(p+1, remain-1) );
    }
    
    char* order_name[] = {
        "descending",
        "other",
        "ascending"
        ""
    };
    
    int main()
    {
        char line[666] = "none";
        while ( strlen(line) > 0 ) {
        printf("enter a number (at least 2 digits):");
        fgets(stdin,line,sizeof(line)-1);
        if( strlen(line) > 0 && line[strlen(line)-1] == '\n' )
            line[strlen(line)-1] = '\0';
        order_t order = check_order(line);
        printf("function returned: (%d)%s\n", order, order_name[order+1]);
        }
    }
    

    【讨论】:

      【解决方案3】:

      我认为您的开始是正确的,但需要更多地充实您的代码。我的解决方案借鉴了@ChuckCottrill 的解决方案,因为我喜欢他的enum,但我不喜欢他不打球(即转换为字符串而不是处理int。)我也借用@ggorlen 的很好的测试示例,但我也不喜欢该解决方案,因为它可能需要多次通过数字才能在只需要一次通过时找出答案:

      #include <stdio.h>
      
      typedef enum { descending=-1, other=0, ascending=1 } order_t; // a la @ChuckCottrill
      
      order_t check_order(int n)
      {
          if (n > 9) {
              int right = n % 10;
              int left = n / 10 % 10;
      
              if (right > left) {
                  n /= 10;
      
                  if (n > 9) {
                      return (ascending == check_order(n)) ? ascending : other;
                  }
      
                  return ascending;
              }
      
              if (right < left) {
                  n /= 10;
      
                  if (n > 9) {
                      return (descending == check_order(n)) ? descending : other;
                  }
      
                  return descending;
              }
          }
      
          return other;
      }
      
      int main() { // a la @ggorlen
          printf("12345: %d\n", check_order(12345));
          printf("54321: %d\n", check_order(54321));
          printf("54323: %d\n", check_order(54323));
          printf("454321: %d\n", check_order(454321));
          printf("1: %d\n", check_order(1));
          printf("12: %d\n", check_order(12));
          printf("21: %d\n", check_order(21));
      }
      

      输出

      > ./a.out
      12345: 1
      54321: -1
      54323: 0
      454321: 0
      1: 0
      12: 1
      21: -1
      > 
      

      【讨论】:

      • 我认为担心多次传递有点愚蠢——整数永远不能超过 10 位,因此非常值得对性能造成的极小的影响来极大地提高函数的可读性。即使数字很大,理论上都是线性时间复杂度。性能并不是使用 OP 尝试将所有内容打包到一个函数中的可疑设计的充分理由。
      • 请注意,OP 发布了一个 X-Y 问题 - 通常情况下,新程序员在被告知处理“数字”时会假设类型......挑战假设。
      【解决方案4】:

      适用于任何长度的版本,因为它将字符串作为参数。 并且为递归函数提供先前的状态(升序或降序)允许一些更短的代码和更少的函数。

      int check_order(char *str, int index, int previous) {
           char current = str[index];       // char at index
           char next = str[index+1];        // char at index+1
           if (current == 0 || next == 0) {
                return previous;            // End of string
           }
           // Ascending or descending?
           int status = next > current ? 1 : (next < current ? -1 : 0); 
           if (status == 0 || index > 0 && status != previous) {
                // If neither -1/1 nor status == previous (while not initial call)
                return 0;
           }
           return check_order(str, index+1, status); // Check from next index
      }
      

      main 函数必须确保字符串至少为 2 个字符

      int main(int argc, char **argv) {
           char *str = *++argv;
           // Some optional checks on str here... (like this is a number)
           int status = 0; // Default value if string length < 2
           if (strlen(str) >= 2) {
              status = check_order(str, 0, 0);
           }
           printf("Check order for %s is %d\n", str, status);
           return 0;
      }
      

      【讨论】:

        【解决方案5】:

        像这样的return 语句之后的代码是无法访问的:

        return check_order(n / 10);
        if (n == 0)
        {
            return -1;
        }
        

        除此之外,您正在正确地检查当前数字与下一个数字,但我没有看到明确的基本情况(n &lt; 10,即单个数字)。

        试图在一个递归函数中检查升序和降序很难管理。特别是,堆栈帧之间的通信状态以及确定在给定调用中哪些情况仍然有效表明返回值过度工作。

        为了避免返回结构或使用枚举或幻数作为标志,我编写了两个通用辅助函数ascending_digitsdescending_digits

        #include <stdbool.h>
        #include <stdio.h>
        
        bool ascending_digits(int n) {
            if (n < 10) return true;
            if (n % 10 < n / 10 % 10) return false;
            return ascending_digits(n / 10);
        }
        
        bool descending_digits(int n) {
            if (n < 10) return true;
            if (n % 10 > n / 10 % 10) return false;
            return descending_digits(n / 10);
        }
        
        int check_order(int n) {
            if (ascending_digits(n)) return 1;
            if (descending_digits(n)) return -1;
            return 0;
        }
        
        int main() {
            printf("12345: %d\n", check_order(12345));
            printf("54321: %d\n", check_order(54321));
            printf("54323: %d\n", check_order(54323));
            printf("454321: %d\n", check_order(454321));
            printf("1: %d\n", check_order(1));
            printf("12: %d\n", check_order(12));
            printf("21: %d\n", check_order(21));
            return 0;
        }
        

        输出:

        12345: 1
        54321: -1
        54323: 0
        454321: 0
        1: 1
        12: 1
        21: -1
        

        这些功能不仅更易于理解和单独维护,而且与不可分割地捆绑在一起相比,它们的可重用性也更高。

        这不处理负数——你可以申请abs,如果你愿意,可以从那里开始。处理相等的值也是如此;此实现接受诸如1223 之类的数字,但您可以使用&lt;= 来强制执行严格排序。

        【讨论】:

        • 请注意,我的回答解释了如何分析和解决问题并找到解决方案......往往过于强调巧妙的数字技巧,而牺牲了可读性。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-08
        • 2021-03-27
        • 2019-11-12
        • 1970-01-01
        • 1970-01-01
        • 2019-07-17
        • 2018-04-25
        相关资源
        最近更新 更多