如何制作一个仅使用加法和仅使用2个变量进行除法的递归函数

问题描述

最近我被派去做一个递归函数,该函数仅使用加法(不允许减法)进行除法,并且只有两个变量。

编辑:基于注释的一些注释:

  • n1除以n2。 (n1:n2)

  • 答案应该是整数(整数),表示您可以将n2放入n1的次数(8:3应该得到2,8:4也应该得到2)。

  • 您可以假定输入只是整数正数。

按照评论中的要求,我会尽力将作业翻译成英文并使其尽可能准确:

编写一个名为“ PDiv”的递归函数,该函数将获得两个完整的正数并仅使用加法运算返回其商数。

我尝试使用如下所示的2个递归函数来实现:(赋值仅需要一个函数,因此这不是正确的答案)

public static int PDiv(int n1,int n2)
{
    if (n1 < n2)
        return 0;
    else if (n1 == n2)
        return 1;
    else
        return PDiv(n1,n2 + n2,n2) + 1;
}

public static int PDiv(int n1,int n2,int con)
{
    if (n1 < n2)
        return 0;
    else if (n1 == n2)
        return 1;
    else
        return PDiv(n1,con) + 1;
}

除此之外,我还尝试了一个确实有效的方法,但是它伪装成明智的做法,而不是真正地通过加法来实现,而是加上减法(基本上是减法)。示例:

public static int PDiv(int n1,int n2)
{
    if (n1 < n2)
        return 0;
    else if (n1 == n2)
        return 1;
    else
        return PDiv(n1 + -n2,n2) + 1;
}

如果有人对我的工作方式有所了解,我很想听听!预先感谢!

解决方法

如果可以使用取模运算符和局部变量,这是实现此目标的一种方法。

这个想法是,如果我们知道PDiv(n,m + m),我们只需要知道是否仍然可以再添加一个m

C#代码:

using System;

public class Test
{
    public static int PDiv(int n,int m)
    {
        if (n < m)
            return 0;
        if (n == m)
            return 1;
  
        int k = PDiv(n,m + m);

        return k + k + (n % (m + m) < m ? 0 : 1);
    }

    public static void Main()
    {
        Console.WriteLine(PDiv(21,3));
    }
}
,

这是我们可以通过纯粹的加法,比较和赋值操作以及根据要求提供的两个参数来实现的方法,前提是允许我们提供元组返回值。 C#代码:

using System;

public class Test
{
    // Returns (floor(n / m) * m,floor(n / m))
    public static (int,int) f(int n,int m){
        if (n < m)
            return (0,0);
        if (n == m)
            return (n,1);
  
        (int _n,int k) = f(n,m + m);

        if (_n + m > n)
            return (_n,k + k);
    
        return (_n + m,k + k + 1);
    }

    public static void Main()
    {
        for (int n=1; n<200; n++){
            for (int m=1; m<n; m++){
                (int _n,int nm) = f(n,m);
                if (nm != n / m)
                    Console.WriteLine($"Mismatch: { n },{ m }") ;
            }
        }

        Console.WriteLine("Test done.");
    }
}
,

您唯一的问题是,在使用n2 = n2 + con时,您仍然可以在第二种方法中将n1与n2进行比较,而con仍然盯着n2,它应该可以工作。

    private int div(int n1,int n2)
    {
        if (n1 == n2) return 1;
        if (n1 < n2) return 0;
        return div(n1,n2,n2+n2) + 1;  
    }
    private int div(int n1,int n2,int runner)
    {
        if (n1 == runner) return 1;
        if (n1 < runner) return 0;
        return div(n1,runner+n2) + 1;
    }
,
d = a/b 
d * b + r = a

第二行给出了如何以递归方式解决此问题的想法。 不考虑余数(r),将b加起来直到d*b > a。这样,剩下要做的就是跟踪我们必须将b加在一起多少次,直到b大于a

int div_loop(int dividend,int divisor,int x,int n) {
  if (x > dividend)
     return (n-1);
  return div_loop(dividend,divisor,(x + divisor),(n+1));
}
int div(int dividend,int divisor) {
  return div_loop(dividend,0);
}

这应符合要求,因为要求不禁止编写辅助函数。而且main函数只有2个参数,这是一个递归解决方案,仅使用加法。

如果C#具有嵌套函数(不确定是否现在有,但是我上次用C#编程时没有),则div_loop()可以嵌套在div()函数内部,内部函数可以被视为实现细节(并减少了2个参数)。例如,在F#中,可能看起来像这样:

let div dividend divisor =
  let rec operate x n =
    if x > dividend
    then (n - 1)
    else operate (x + divisor) (n + 1)
  operate 0 0

Microsoft c# documentation开始,C#现在支持嵌套函数,其名称为“本地函数”。

因此,您可以满足所有要求,例如:

int pdiv(int dividend,int divisor) {
  return div_loop(0,0);
  int div_loop(int x,int n) {
    if (x > dividend) return (n-1);
    return div_loop(x+divisor,n + 1);
  }
}