用Java计算gcd

时间:2015-04-20 23:15:34

标签: java algorithm recursion greatest-common-divisor

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

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

这是我的toString方法:

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

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

我的目标是编写正确的gcd函数,以便toString以不可缩减的形式返回一个fracyion。这是我写的:

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功能有什么问题?我如何让我的工作?我将如何编写递归函数?

5 个答案:

答案 0 :(得分:7)

为什么不遵循说明?

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)。

答案 1 :(得分:2)

递归函数:

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

答案 2 :(得分:1)

以下是两个版本,一个简洁明了:

    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

答案 3 :(得分:1)

你的gcd效率很低。除此之外,它错过了最终的回报声明。假设您的输入为x = 0且y = 1.它将通过第一次检查输入&lt; 0,&#39; div&#39;是0并且永远不会执行while循环。现在,您在方法的最后没有任何return语句。对于递归:

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

答案 4 :(得分:0)

你问了三个问题:

  

我的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;
    }
}

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