【问题标题】:How do I reverse the order of the digits of an integer using recursion in C programming?如何在 C 编程中使用递归来反转整数的数字顺序?
【发布时间】:2021-01-25 14:19:46
【问题描述】:

问题陈述:

给定一个 32 位有符号整数,反转整数位。

注意:假设我们正在处理的环境只能存储 32 位有符号整数范围内的整数:[ -2^31, 2^31 - 1]。为了 这个问题的目的,假设你的函数返回 0 时 反转整数溢出。

我正在尝试实现递归函数 reverseRec(),它适用于较小的值,但对于边缘情况来说是一团糟。

int reverseRec(int x)
{
    if(abs(x)<=9)
    {
        return x;
    }
    else
    {
        return reverseRec(x/10) + ((x%10)*(pow(10, (floor(log10(abs(x)))))));
    }
}

我已经实现了运行良好的非递归函数:

int reverse(int x)
{
    long long val = 0;
    do{
        val = val*10 + (x%10);
        x /= 10;
    }while(x);

    return (val < INT_MIN || val > INT_MAX) ? 0 : val;
}

这里我使用 long long 类型的变量 val 来检查 MAXMIN 的签名 int 类型的结果,但描述问题特别提到我们需要在 32 位整数的范围内处理,虽然它以某种方式被接受但我只是好奇 是否有一种方法可以仅使用 int 数据类型实现递归函数?

即使我考虑使用 long long,我也无法在递归函数 reverseRec() 中实现它。

【问题讨论】:

  • logpow - 甜蜜
  • 在非递归函数中,将val 乘以10,然后加上数字。为避免溢出,您应该验证乘法和加法在之前是否可以工作。最大的正整数是 2147483647。所以检查是if (val &gt; 214748364) { multiplication will overflow } else if (val == 214748364 &amp;&amp; digit &gt; 7) { addition will overflow }

标签: c recursion flowchart


【解决方案1】:

如果有一种方法可以仅使用 int 数据类型来实现递归函数?
(and) 反转整数溢出时返回 0

是的。

对于此类 +/- 问题,我喜欢将 int 值折叠到一侧并根据需要取反。折叠到一侧(- 或 +)简化了溢出检测,因为只有一侧需要测试

我更喜欢折叠到消极的一面,因为消极的一面多于积极的一面。 (使用 32 位 int,对这个问题真的没有任何影响。)

由于代码形成反转值,在执行之前测试以下r * 10 + least_digit是否可能溢出。


一个int 唯一的递归解决方案来反转一个int。溢出返回 0。

#include <limits.h>
#include <stdio.h>

static int reverse_recurse(int i, int r) {
  if (i) {
    int least_digit = i % 10;
    if (r <= INT_MIN / 10 && (r < INT_MIN / 10 || least_digit < INT_MIN % 10)) {
      return 1; /// Overflow indication
    }
    r = reverse_recurse(i / 10, r * 10 + least_digit);
  }
  return r;
}

// Reverse an int, overflow returns 0
int reverse_int(int i) {
  // Proceed with negative values, they have more range than + side
  int r = reverse_recurse(i > 0 ? -i : i, 0);
  if (r > 0) {
    return 0;
  }
  if (i > 0) {
    if (r < -INT_MAX) {
      return 0;
    }
    r = -r;
  }
  return r;
}

测试

int main(void) {
  int t[] = {0, 1, 42, 1234567890, 1234567892, INT_MAX, INT_MIN};
  for (unsigned i = 0; i < sizeof t / sizeof t[0]; i++) {
    printf("%11d %11d\n", t[i], reverse_int(t[i]));
    if (t[i] != INT_MIN) {
      printf("%11d %11d\n", -t[i], reverse_int(-t[i]));
    }
  }
}

输出

          0           0
          0           0
          1           1
         -1          -1
         42          24
        -42         -24
 1234567890   987654321
-1234567890  -987654321
 1234567892           0
-1234567892           0
 2147483647           0
-2147483647           0
-2147483648           0

【讨论】:

  • 谢谢,我理解了逻辑,但现在我得到了这个运行时错误:-2147483648 的否定不能用“int”类型表示;强制转换为无符号类型以将此值取反。
  • @0_0perplexed 此处发布的代码不会否定 -2147483648,因此您遇到的问题在于我不知道的代码 - 如果没有真正的代码,很难为您提供建议。
【解决方案2】:

您可以添加第二个参数:

int reverseRec(int x, int reversed)
{
    if(x == 0)
    {
        return reversed;
    }
    else
    {
        return reverseRec(x/10, reversed * 10 + x%10);
    }
}

并调用传递 0 作为第二个参数的函数。如果你想要负数,你可以检查前面的符号并将绝对值传递给这个函数。

【讨论】:

    【解决方案3】:

    我假设反转一个整数是指将 129 变为 921 或 120 变为 21。

    你需要一个初始化方法来初始化你的递归函数。 您的递归函数必须计算出您的整数使用了多少个小数位。这可以通过使用以 10 为底的 log 值,然后将结果转换为整数来找到。

    • log10 (103) 大约2.04 => 2

    将初始值模数 10 以得到个位并将其存储在名为 temp 的变量中 从初始值中减去个位并将其存储在名为 newStart 的变量中。

    • 将此值除以 10

    从小数位减去一个并存储在另一个名为 newDecimal 的变量中。

    将个位乘以 10 的小数次方,并将其添加到初始值为 newStart 且小数点为 newDecimal 的函数中。

    #include <stdio.h>
    #include <math.h>
    
    int ReverseInt(int startValue, int decimalPlace);
    
    int main()
    {
        int i = -54;
        int positive = i < 0? i*-1 : i;
        double d = log10(positive);
        int output = ReverseInt(positive,(int)d);
        int correctedOutput = i < 0? output*-1 : output;
        printf("%d \n",correctedOutput);
        return 0;
    }
    
    int ReverseInt(int startValue, int decimalPlace)
    {
        if(decimalPlace == 0)
        {
            return startValue;
        }
        int temp = startValue % 10;
        int newStart = (startValue -temp)/10;
        int newDecimal = decimalPlace -1;
        
        
        int value = temp*pow(10,decimalPlace);
        return value + ReverseInt(newStart,newDecimal);
    }
    

    【讨论】:

    • 函数完成后,检查初始数是否小于0,如果乘以负数,则不用管。
    • 更新了代码以包含一些样板文件。
    • 没关系 - 整数计算中没有pow
    • 这个功能非常好 - 任何负数都会失败。 godbolt.org/z/d3qs9x
    • 感谢您告诉我,我没有注意到我没有使用负数进行测试。我将其更新为现在考虑负数。
    【解决方案4】:

    在尝试学习 C 编程时,我编写了这个问题并得到了一些正确的结果和一些不正确的结果。我看不出差异的原因。

        #include <stdio.h>
        #include <string.h>
        #include <stdlib.h>
        #include <math.h>  // requires adding link to math -lm as in: gcc b.c -lm -o q11
    
        int ReverseInt(int startValue, int decimalPlace)
        {
            if(decimalPlace == 0)  // if done returns value
            {
                return startValue;
            }
        int temp = startValue % 10;  // gets units digit
        int newStart = (startValue -temp)/10; // computes new starting value after removing one digit
        int newDecimal = decimalPlace -1;
        
        
        int value = temp*pow(10,decimalPlace);
        return value + ReverseInt(newStart,newDecimal);  // calls itself recursively until done
        }
    
    
        int main()
        {
            int x, decimalP, startValue;
            printf("Input number to be reversed \n Please note number must be less than 214748364 :");
            scanf("%d", &x);
            if (x > 214748364)
            {
                printf("Input number to be reversed \n Please note number must be less than 214748364 :");
                scanf("%d", &x);
            }
            decimalP = round(log10(x));  // computes the number of powers of 10 -  0 being units etc.
            startValue = ReverseInt(x, decimalP);  // calls function with number to be reversed and powers of 10
            printf("\n reverse of %d is %d \n", x, startValue);
        }
    

    输出是:1234 的反转是 4321,然后 4321 的反转是 12340

    【讨论】:

      【解决方案5】:

      已经很晚了,没有更好的事情出现在我的脑海中。没有浮动计算。当然,整数必须足够大以容纳结果。否则就是 UB。

      int rev(int x, int partial, int *max)
      {
          int result;
          if(x / partial < 10 && (int)(x / partial) > -10)
          {
              *max = partial;
              return abs(x % 10) * partial;
          }
          result = rev(x, partial * 10, max) + abs(((x / (int)(*max / partial)) % 10) * partial);
          return result;
      }
      
      int reverse(int x)
      {
          int max;
          return rev(x, 1, &max) * ((x < 0) ? -1 : 1);
      }
      
      
      int main(void){
        
        printf("%d", reverse(-456789));
      }
      

      https://godbolt.org/z/M1eezf

      unsigned rev(unsigned x, unsigned partial, unsigned *max)
      {
          unsigned result;
          if(x / partial < 10)
          {
              *max = partial;
              return (x % 10) * partial;
          }
          result = rev(x, partial * 10, max) + (x / (*max / partial) % 10) * partial;
          return result;
      }
      
      unsigned reverse(unsigned x)
      {
          unsigned max;
          return rev(x, 1, &max);
      }
      
      
      int main(void){
        
        printf("%u", reverse(123456));
      }
      

      当使用 long long 存储结果时,所有可能的整数都可以取反

      long long rev(int x, long long partial, long long *max)
      {
          long long result;
          if(x / partial < 10 && (int)(x / partial) > -10)
          {
              *max = partial;
              return abs(x % 10) * partial;
          }
          result = rev(x, partial * 10, max) + abs(((x / (int)(*max / partial)) % 10) * partial);
          return result;
      }
      
      long long reverse(int x)
      {
          long long max;
          return rev(x, 1, &max) * ((x < 0) ? -1 : 1);
      }
      
      
      int main(void){
        
        printf("%d reversed %lld\n", INT_MIN, reverse(INT_MIN));
        printf("%d reversed %lld\n", INT_MAX, reverse(INT_MAX));
      }
      

      https://godbolt.org/z/KMfbxz

      【讨论】:

      • 有什么意见吗?还是你埃里克
      猜你喜欢
      • 2019-06-25
      • 1970-01-01
      • 2021-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-14
      • 1970-01-01
      相关资源
      最近更新 更多