我的目标是编写一个反转整数数字的递归程序。当我测试第一个元素时,代码可以工作。但是,它对其他两种情况不适用,例如:它为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);
}
}
答案 0 :(得分:13)
我的目标是编写一个递归程序来反转整数的数字。
由于这是业内人士不希望达到的目标,因此这对于一个班级来说是好的。特别是,没有明智的人会通过递归来解决这个问题,即使他们有这个问题。因此,教授递归是一个糟糕的问题,因为非递归解决方案非常简单。
你不能很好地理解递归的可能性也很大。从某种意义上说,这是一个很好的练习,因为它需要使用一种称为 accumulator 的特殊技术来实现递归解决方案。
此外,即使您修复了错误,您的解决方案也不会生成所需的数字。它打印它,这是完全不同的。我们希望能够生成结果,而不仅仅是显示它。
(然后提出了一个有趣的问题,即如何处理适合int
的数字,但其反转不符合1000000009
。让我们暂时忽略这些问题存在。)
所以让我们从基础开始吧。每个递归方法都具有相同的结构:
让我们天真地将这种模式应用到您的问题中,看看会发生什么。
基本案例很简单:
递归案例是什么?假设我们有157
目前还不清楚如何执行最后一次操作。
我们需要更聪明。
这是你做的。 (我已经省略了拒绝负数的错误检查。)
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);
让我们看一些案例。
假设number
为0
。然后ReverseHelper
返回0
,好。零工作。
假设number
为3
。然后我们致电ReverseHelper(3, 0)
,调用ReverseHelper(0, 3)
,返回3
。一位数的数字。
假设number
为35
。我们致电ReverseHelper(35, 0)
,调用ReverseHelper(3, 5)
,调用ReverseHelper(0, 53)
,返回53
。两位数的数字有效。
等等。
练习:有一种直接的方法来处理逆转int的问题,其中逆转不适合int;它是什么?
你知道我希望为什么使用累加器来调用这种技术。随着递归的进行,期望的结果逐渐累积,然后在递归达到其基本情况时返回。
现在,请注意此技术与原始程序的关系。 您使用静态字段作为累加器。永远不要那样做!永远!递归方法不应该依赖于它们对外部状态的正确性。 相反,将递归消耗的值传递给对辅助方法的递归调用。
仔细研究这项技术。这是编写递归程序的强大技术。在函数式语言中,这种操作称为fold
或reduce
;期待那些进一步的灵感。在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)
之类的方法即可。其他两个参数result
和reminder
是可选的,因为它们具有默认值。
修改强>
以下是上述代码的简明版本:
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();
}