用于反转整数数字的递归函数

时间:2018-04-13 16:39:47

标签: c# recursion digit

我的目标是编写一个反转整数数字的递归程序。当我测试第一个元素时,代码可以工作。但是,它对其他两种情况不适用,例如:它为reverse(456)打印321654,而reverse(731)打印321654137。 我认为问题出在public static variable reverted上。

有人可以帮助我理解问题并解决它吗?

using System;  
public class Program
{
    public static void Main(string[] args)
    {
        reverse(123);
        reverse(456);
        reverse(731);
    }

    public static int reverted=0;

    public static void reverse(int number)
    {
        if (number!=0)
        {
            int remainder = number % 10;
            reverted = (reverted*10)+remainder;
            reverse(number/10);
        } 
        else
            Console.WriteLine(reverted);
    }
}

4 个答案:

答案 0 :(得分:13)

  

我的目标是编写一个递归程序来反转整数的数字。

由于这是业内人士不希望达到的目标,因此这对于一个班级来说是好的。特别是,没有明智的人会通过递归来解决这个问题,即使他们有这个问题。因此,教授递归是一个糟糕的问题,因为非递归解决方案非常简单。

你不能很好地理解递归的可能性也很大。从某种意义上说,这是一个很好的练习,因为它需要使用一种称为 accumulator 的特殊技术来实现递归解决方案。

此外,即使您修复了错误,您的解决方案也不会生成所需的数字。它打印它,这是完全不同的。我们希望能够生成结果,而不仅仅是显示它。

(然后提出了一个有趣的问题,即如何处理适合int的数字,但其反转不符合1000000009。让我们暂时忽略这些问题存在。)

所以让我们从基础开始吧。每个递归方法都具有相同的结构:

  • 我们是否在基础案件中?如果是,请返回结果。
  • 我们不是基本情况。
  • 将问题分解为更小的问题
  • 递归地解决每个问题
  • 结合解决方案来解决更大的问题
  • 返回结果。

让我们天真地将这种模式应用到您的问题中,看看会发生什么。

基本案例很简单:

  • 从0到9的任何非负数的反向本身。

递归案例是什么?假设我们有157

  • 将数字除以10得到一个较小的数字,15
  • 反转较小的数字 - 51
  • 将原始数字的低位数字附加为反转较小数字的高位数字,751 ---等待,我们如何做到这一点

目前还不清楚如何执行最后一次操作。

我们需要更聪明。

这是你做的。 (我已经省略了拒绝负数的错误检查。)

static int ReverseHelper(int number, int accumulator) =>
  number == 0 ? 
    accumulator : 
    ReverseHelper(number / 10, accumulator * 10 + number % 10);

public static int Reverse(int number) =>
  ReverseHelper(number, 0);

让我们看一些案例。

假设number0。然后ReverseHelper返回0,好。零工作。

假设number3。然后我们致电ReverseHelper(3, 0),调用ReverseHelper(0, 3),返回3。一位数的数字。

假设number35。我们致电ReverseHelper(35, 0),调用ReverseHelper(3, 5),调用ReverseHelper(0, 53),返回53。两位数的数字有效。

等等。

练习:有一种直接的方法来处理逆转int的问题,其中逆转不适合int;它是什么?

你知道我希望为什么使用累加器来调用这种技术。随着递归的进行,期望的结果逐渐累积,然后在递归达到其基本情况时返回。

现在,请注意此技术与原始程序的关系。 您使用静态字段作为累加器。永远不要那样做!永远!递归方法不应该依赖于它们对外部状态的正确性。 相反,将递归消耗的值传递给对辅助方法的递归调用。

仔细研究这项技术。这是编写递归程序的强大技术。在函数式语言中,这种操作称为foldreduce;期待那些进一步的灵感。在C#中,它被称为Aggregate,用于生成序列的汇总结果。

使用累加器的递归模式是:

  • 我们是否在基础案件中?如果是,请从累加器返回结果
  • 我们不是基本情况。
  • 将问题分解为更小的问题
  • 递归解决每个问题,通过在递归调用上累积有关解决方案的信息
  • 结合解决方案来解决更大的问题
  • 返回结果。

为什么这种技术如此有价值?在C#中,这不太重要,但在尾递归函数语言中,编译器通常可以优化使用累加器的递归方法,使其成为比非尾递归方法更高效的代码,这样就可以了否则研究。

它在C#中很有价值,因为使用累加器的尾递归方法可以通过简单的程序转换过程轻松转换为非递归方法

让我们看看如何。我们有:

static int ReverseHelper(int number, int accumulator) =>
  number == 0 ? 
    accumulator : 
    ReverseHelper(number / 10, accumulator * 10 + number % 10);

让我们重写一句话:

static int ReverseHelper(int number, int accumulator)
{
  if (number == 0)
    return accumulator;
  else
    return ReverseHelper(number / 10, accumulator * 10 + number % 10);
  }
}

现在让我们为所有子表达式制作解释变量:

static int ReverseHelper(int number, int accumulator)
{
  if (number == 0)
    return accumulator;
  else 
  {
    int newNumber = number / 10;
    int newAccumulator = accumulator * 10 + number % 10;
    return ReverseHelper(newNumber, newAccumulator);
  }
}

到目前为止一切顺利。但现在我们注意到我们可以把整个事情变成一个循环!

static int ReverseHelper(int number, int accumulator)
{
  while (true) 
  {
    if (number == 0)
      return accumulator;
    else 
    {
      int newNumber = number / 10;
      int newAccumulator = accumulator * 10 + number % 10;
      number = newNumber;
      accumulator = newAccumulator;
      // And now the loop starts over!
    }
  }
}

当然,我们发现现在这种解决方案的形式是直接的非递归解决方案。

这可以让您深入了解递归程序的本质:

  • 每个递归程序都可以转换为尾递归程序,但并不总是很容易看到。
  • 每个尾递归程序都可以转换为非递归循环。
  • 反过来也是如此!每个带循环的程序都可以转换成尾递归程序!

再次,仔细研究这些简单的技术。理解递归和非递归程序之间的关系是CS理论中的关键工具。

答案 1 :(得分:2)

尝试我的方法:

public static int reverse(int number, int result = 0, int reminder = 0)
{
    if (number == 0)
    {
        return result * 10 + reminder;
    }
    return reverse(number / 10, result * 10 + reminder, number % 10);
}

只需调用reverse(123)之类的方法即可。其他两个参数resultreminder是可选的,因为它们具有默认值。

Demo here

修改

以下是上述代码的简明版本:

public static int reverse(int number, int result = 0)
{
    if (number == 0)
    {
        return result;
    }
    return reverse(number / 10, result * 10 + number % 10);
}

或者使用三元运算符:

public static int reverse(int number, int result = 0)
{
    return number == 0 ? result : reverse(number / 10, result * 10 + number % 10);
}

答案 2 :(得分:0)

使用递归反向输入数字

    public static int ReverseRecursive(int number)
    {
        int remainder = number % 10;
        number = number / 10;
        if (number < 1)
            return remainder;
        return ReverseRecursive(number) + remainder * Convert.ToInt32(Math.Pow(10, number.ToString().Length));
    }

答案 3 :(得分:-2)

两种方法:

     static void Main(string[] args)
     {
         reverse(123);
         reverse(456);
         reverse(731);

         Console.WriteLine();

         _reverse(123);
         _reverse(456);
         _reverse(731);
         _reverse(25);
         _reverse(int.MaxValue);
    }
    // Linq
    public static void reverse(int number)
    {
        Console.WriteLine(new string(number.ToString().Reverse().ToArray()));
    }
    // Recursive
    public static void _reverse(int number)
    {
        Console.Write(number%10);
        if (number >= 10)
            _reverse((number - (number % 10)) / 10);
        else
            Console.WriteLine();
    }