我刚刚开始学习C,我遇到了以下问题: 在第一个 / 递归步骤 / 我不明白为什么我们不能简单地返回乘(x,y)?为什么我们需要为y添加一个值,然后才返回它?
代码如下。 谢谢!
#include <stdio.h>
unsigned int multiply(unsigned int x, unsigned int y)
{
if (x == 1)
{
/* Terminating case */
return y;
}
else if (x > 1)
{
/* Recursive step */
return y + multiply(x-1, y);
}
/* Catch scenario when x is zero */
return 0;
}
int main() {
printf("3 times 5 is %d", multiply(3, 5));
return 0;
}
答案 0 :(得分:2)
如果您返回乘(x,y),您将永远循环使用相同的调用参数。要进行适当的递归,您必须将问题简化为更简单的情况。更简单的情况是将乘数减少1。
答案 1 :(得分:1)
递归只是使用较小的输入执行相同的操作。我们能用较小的数字表示两个数的乘法吗?好的!找到这样做的方法是找到乘法的递归定义。首先,我们将尝试使用较小的x表示x * y,如x-1。 从简单的事实来看:
(x-1)*y = x*y - y
我们发现:
x*y=(x-1)*y + y
请记住,我们总是必须找到一个停止步骤,我们知道
0*y=0
我们已经完成了。这给了我们一个更简单的递归mul函数形式,就像@RobertEagle给出的那样。
但是让我们更进一步。 x-1小于x,因为y-1小于y。探索这个事实让我们:
(x-1)*(y-1)=x*y-x-y+1
x*y = (x-1)*(y-1) + x + y - 1
这次停止步骤为“如果x或y为0则结果为0”。将其翻译成代码:
unsigned multiply(unsigned x, unsigned y)
{
if ( (x==0) || (y==0) )
return 0;
else
return x+y-1+multiply(x-1, y-1);
}
这种递归效率不高,因为我们没有用更小的东西来表达递归。如果我们尝试将其中一个参数减半怎么办? 如果x是偶数,我们可以写:
x*y=2*(x/2)*y=(x/2)*(2*y)
如果x是奇数,我们可以写:
x*y=(x-1+1)*y=(x-1)*y+y=((x-1)/2)*(2*y)+y
左(右)右移可以实现乘以(分为右)2:
unsigned multiply(unsigned x, unsigned y)
{
if (x==0)
return 0;
else if (x%2==0)
return multiply(x>>1, y<<1);
else
return y+multiply((x-1)>>1, y<<1);
}
此方法比第一步采用更少的步骤。一般而言,“越多”越小,“越多”越快。
答案 2 :(得分:0)
如果您没有添加该值,则只会返回y
作为最高递归调用的最终结果。
X * Y = X,Y次
e.g。 4 * 5 = 4 + 4 + 4 + 4 + 4
这个逻辑正在扩展该评估,只返回最后一个值只能评估为Y一次。
答案 3 :(得分:0)
每个递归函数由2个元素组成:
没有停止条件,程序将进入无限循环。
在这种情况下,这意味着该计划将不断调用x == 1
。
该程序不会停止在x == 1
处自行调用,而是会将multiply(-1,y)
,multiply(-2,y)
...调用为无限。
最终,您需要将 y 与 x 相加。要做到这一点,您需要返回 x 乘以 y 的值。在这种情况下,重复条件为 x-1 次添加 y ,对于停止条件,您只需要再多一次。
你也可以这样做:
#include <stdio.h>
unsigned int multiply(unsigned int x, unsigned int y)
{
if (x == 0)
{
/* Terminating case */
return 0;
}
else if (x > 0)
{
/* Recursive step */
return y + multiply(x-1, y);
}
}
int main() {
printf("3 times 5 is %d", multiply(3, 5));
return 0;
}
在这里,您可以看到重复性与 y 完全相同的 x 时间相加。从逻辑上讲,停止条件需要返回0,因为我们不需要再添加 y 值。我们已经为 x 次添加了它。