簡體   English   中英

Java 中歐幾里得算法的最大公約數 (GCD)

[英]Greatest Common Divisor (GCD) by Euclidean algorithm in Java

我為 Greatest Common Divisor-GCD 編寫了這段代碼。 I subtract smaller integer from bigger integer, then I remove biggest integer and subtract smaller integer from bigger integer again until two integers are equal and it's result. 我想知道這是否正確,是否可以更簡單? 謝謝你。

public static void main(String[] args) {
    int firstInteger=114, secondInteger=67;


    if (firstInteger>secondInteger) {

        int result=firstInteger-secondInteger;

        while (firstInteger != secondInteger) {

            if (secondInteger > result) {
                firstInteger = secondInteger;
                secondInteger = result;
                result = firstInteger - secondInteger;
            } else {
                firstInteger = result;
                result = firstInteger - secondInteger;
            }
        }
        System.out.println(firstInteger);
    }
    else {

        int result=secondInteger-firstInteger;

        while (secondInteger!=firstInteger) {

            if (firstInteger>result)  {
                secondInteger=firstInteger;
                firstInteger=result;
                result=secondInteger-firstInteger;

            }
            else {
                secondInteger=result;
                result=secondInteger-firstInteger;
            }
        }
        System.out.println(secondInteger);
    }


}

態度是正確的,代碼將按預期 function 但是,如果將 0 作為值應用於firstIntegersecondInteger ,它將失敗(鎖定到連續循環)。 這同樣適用於帶符號的 integer 值。 如果它們出現,您將需要處理這些情況。

盡管代碼對於它打算完成的任務來說相當長,但它確實有效。 如果您使用不同的概念來處理任務,則可以大大縮短它,例如,通過使用 (%) 運算符(又名:余數運算符)並執行一種除法形式來查看是否有余數,而不是執行減法,並忽略哪個參數值開始時更大。 這是一個實際上可以用作方法的示例:

public static int getGreatestCommonDivisor(int numerator, int denominator) {
    if (numerator <= 0 || denominator <= 0) {
        System.err.println("getGreatestCommonDivisor() Method Error! A value of "
                         + "zero (0) or less can not be supplied as an argument!");
        return -1;
    }
    int temp = numerator % denominator;
    while (temp > 0) {
        numerator = denominator;
        denominator = temp;
        temp = numerator % denominator;
    }
    return denominator;
}

如果要在方法內部處理帶符號的參數值,則可以使用Math#abs()方法,該方法返回int值的絕對(正)值。 此方法給出參數的絕對值。 參數可以是 int、double、long 和 float,但對於這種方法,我們只關心int類型 arguments。 這是一個例子:

public static int getGreatestCommonDivisor(final int numerator, final int denominator) {
    if (numerator == 0 || denominator == 0) {
        System.err.println("greatestCommonDivisor() Method Error! A value of "
                         + "zero (0) can not be supplied as an argument!");
        return -1;
    }
    int num = numerator;
    num = Math.abs(numerator);          // Ensure an absolute value
    int gcd = Math.abs(denominator);    // Ensure an absolute value
    int temp = num % gcd;
    while (temp > 0) {
        num = gcd;
        gcd = temp;
        temp = num % gcd;
    }
    return gcd;
}

您的代碼確實有效。 以下是我編寫的程序。

    public int calculateGCD(int highNumber, int lowNumber){
        boolean GCDFound = false;
        int quotient, remainder, GCD = 1;
         while(!GCDFound)
         {
            quotient = highNumber / lowNumber;
            remainder = Math.floorMod(highNumber, lowNumber);
            if(remainder == 0)
            {
                GCD = lowNumber;
                GCDFound = true;
            }
            else
            {
                highNumber = lowNumber;
                lowNumber = remainder;
            }
         }
         return GCD;
}`

沒有錯誤處理。 兩個數字都不是零或減去什么。

我對您的 (kamilP) 代碼和我的代碼完成了三個測試。 每個測試使用 1,000,000 對數字的二維數組。 第一個數組編號介於 1 和 107,374,143 之間,第二個數組編號介於 107,374,143 和 2,147,483,646 之間,第三個數組編號介於 1 和 2,147,483,646 之間。 測試程序通過數組到 go 需要多長時間。

結果如下(以毫秒為單位):KamilP & CombatWomble

  • 陣列 1 273ms 155ms
  • 陣列 2 274ms 175ms
  • 陣列 3 285ms 173ms

這是我讓它變得更簡單和更快的方法。

如果它可以變得更簡單?

有幾種方法可以簡化它。 這里有三個。

  • 第一種情況會修改您的算法。 我沒有進行性能分析,因為它需要我沒有安裝的JMH之類的東西。
  • 所有案例都處理正值和負值。
  • 數學會自動調整分子和分母,因此調用方法時rs的順序無關緊要。
  • 第二種和第三種方法采用歐幾里得算法
  • 這兩種方法都會在除以 0 時拋出異常。

在您的方法中,我使用了一個循環並更正了這兩個值,以確保在減法過程中得到積極的結果。

public static int gcd(int r, int s) {
      // absolute value of r and s
      r = r > 0 ? r : -r;
      s = s > 0 ? s : -s;

      while (s > 0) {
          // find min(r,s)
          int t = r > s ? s : r;

          // find max(r,s)
          r = r > s ? r : s;

          s = t;
          r = r - s;
      }
      return r;
}

第二種方法是簡單的迭代,可能是最有效的。 但是,必須在歸還 GCD 之前更正該標志。

public static int gcd(int r, int s) {
    while (s != 0) {
        int t = r % s;
        r = s;
        s = t;
    }
    return r > 0 ? r : -r;
}

這是遞歸方法。 再次需要更正該標志。

public static int gcd(int r, int s) {
    if (s != 0) {
        return gcd(s, r % s);
    }
    return r > 0 ? r : -r;
}

這是對順序和符號可能變化的測試。

System.out.println(gcd(24, 36));
System.out.println(gcd(-24, 36));
System.out.println(gcd(24, -36));
System.out.println(gcd(-24, -36));
System.out.println(gcd(36, 24));
System.out.println(gcd(-36, -24));
System.out.println(gcd(36, -24));
System.out.println(gcd(-36, 24));

所有三種方法都打印。

12
12
12
12
12
12
12
12

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM