【问题标题】:Computing gcd in Java用Java计算gcd
【发布时间】:2015-04-20 23:15:33
【问题描述】:

我正在自学 Java,所以我在加州大学伯克利分校 CS 61B 做实验室。我正在尝试编写一个 gcd 方法来使我的 toString 方法工作。

toString 方法以非约简形式打印 Fraction。 检查 toString 方法中的代码。它正在调用另一个名为 gcd 计算两个正整数的最大公约数 (GCD)。 如果此方法正常工作,toString 将以减少的形式打印 Fractions 形式。我必须重写 gcd 的主体,以便它是 正确计算 GCD 的递归函数。

这是我的 toString 方法:

public String toString() {
    int thisGcd = gcd(numerator, denominator);

    return (numerator / thisGcd + "/" + denominator / thisGcd);
  }

我的目标是编写正确的 gcd 函数,以便 toString 返回不可约形式的分数。这是我写的:

private static int gcd(int x, int y) {
    int div;
    if(x<0 || y<0){
        return -1;
    }
    else {

        if(x>y){
            div = y ;
        }
        else{
            div = x;
        }
        while( div !=0){
            if( (x % div==0 )&&(y % div == 0) ) {
                return div;

            }
            div --;

        }
    }

}

说明是关于使用以下伪代码编写递归 gcd 函数,但我不确定如何准确实现它:

function gcd(a, b)
if b = 0
  return a
else
  return gcd(b, a mod b)

我的 gcd 函数有什么问题?我如何让我的工作?我将如何编写递归函数?

【问题讨论】:

  • 对于大数字,性能要好得多。请使用 10000000/9999999 测试您的代码。请用否定数字测试您的方法和建议的答案方法。例如-2/4、2/-4 和 -2/-4。

标签: java algorithm recursion greatest-common-divisor


【解决方案1】:

为什么不按照说明进行操作?

private static int gcd(int x, int y) {
  if (y == 0) {
    return x;
  }
  return gcd(y, x % y);
}

这个函数被称为尾递归,因为最后一行是递归调用。尾递归函数很容易转化为while循环:

private static int gcd(int x, int y) {
  while (y != 0) {
    int tempX = x;
    x = y;
    y = tempX % y;
  }
  return x;
}

如您所见,转换使 while 循环谓词等于调用递归函数的谓词,而 while 循环的内容只是将 x 和 y 设置为与递归函数的输入相同。一般情况下是这样(见wiki article)。

【讨论】:

    【解决方案2】:

    递归函数:

    public int gcd(int a, int b)
    {
     if(b == 0) return a;
     else return gcd(b, a % b);
    }
    

    【讨论】:

      【解决方案3】:

      您的gcd 效率极低。除此之外,它缺少最终的返回语句。假设您的输入为x = 0 和y = 1。它将通过第一次检查输入 return 语句的方法的末尾。对于递归:

      public int gcd(int a , int b){
          return (b == 0 ? a : gcd(b , a % b));
      }
      

      【讨论】:

        【解决方案4】:

        这里有两个版本,一个简短而简洁:

            public static int gcd(int a, int b){
              return b == 0 ? a : gcd(b, a % b);
            }
        

        另一个更接近您的指示:

            public static int gcd(int a, int b) {
              if (b == 0) 
                return a;
              else 
                return gcd(b, a % b);
            }
        

        您的代码来自哪里?它看起来不像说明。

        这两个版本在语义上完全相同(我怀疑了一秒钟,因为自动装箱的三元运算符的奇怪行为......但是这里没有自动装箱的地方):

          public static int gcd(int, int);
            Code:
               0: iload_1
               1: ifne          8
               4: iload_0
               5: goto          15
               8: iload_1
               9: iload_0
              10: iload_1
              11: irem
              12: invokestatic  #10                 // Method gcd:(II)I
              15: ireturn
        
          public static int gcd_verbose(int, int);
            Code:
               0: iload_1
               1: ifne          6
               4: iload_0
               5: ireturn
               6: iload_1
               7: iload_0
               8: iload_1
               9: irem
              10: invokestatic  #13                 // Method gcd_verbose:(II)I
              13: ireturn
        

        【讨论】:

        • 我当然希望如此?编辑:哎呀...第一个是编译错误,gcd != gcf
        【解决方案5】:

        你问了一个由三个部分组成的问题:

        我的 gcd 函数有什么问题?我如何让我的工作?如何 我会写递归函数吗?

        其他人回答得很好,所以我不回答那部分,而是关于你的另外两个问题:

        我的 gcd 函数有什么问题?

        第一件事是你的代码没有在每个状态下都返回,虽然逻辑上它确实返回了,但是java会给你编译错误error: missing return statement所以你需要在你的函数末尾添加一个返回值,如果你只是想要它工作。但这不会解决您的问题,您的解决方案没有为gcd(0,a) = a 返回正确的值来解决此问题,您只需进行一些更改!

        如何让我的工作?

        这部分是关于进行更改的,下面的函数最接近你的答案,可以正常工作:

        private static int gcd(int x, int y) {
            int div;
            if(x<0 || y<0){
                return -1;
            }
            else {
        
                if(x>y){
                    div = x-y ;    //to fix the problem for zero input
                }
                else{
                    div = y-x;     //to fix the problem for zero input
                }
                while( div !=0){
                    if( (x % div==0 )&&(y % div == 0) ) {
                        return div;
        
                    }
                    div --;
                }
                return div;    //the return statement so you dont get compile error and fix problem of zero input.
            }
        }
        

        但是为什么要停在那里呢?您的函数根本没有时间效率,所以让我们进行一些更改:

        private static int gcd(int x, int y) {
            int div;
            int a;
            if(x<0 || y<0){
                return -1;
            }
            else {
                if(x>y){
                    div = y;
                    a = x-y ;
                }
                else{
                    div = x;
                    a = y-x;
                }
                while( div !=0){
                    if( (x % div==0 )&&(y % div == 0) ) {
                        return div;
                    }
                    a = a - div;
                    if(a<div){
                        int temp = div;
                        div = a;
                        a = temp;
                    }
                }
                return a;
            }
        }
        

        虽然这不是我想要的,但它是你的代码中最有效的代码。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多