2010-09-03 79 views
13

有關Stack Overflow的幾個問題,討論如何找到兩個值的最大公約數。一個很好的答案顯示了一個整潔的recursive function要做到這一點。一組超過2個整數的最大公約數

但我怎樣才能找到一組超過2個整數的GCD?我似乎無法找到一個這樣的例子。


任何人都可以建議最有效的代碼來實現此功能?

static int GCD(int[] IntegerSet) 
{ 
    // what goes here? 
} 
+5

GCD是聯想和交換像+和*,這樣你就可以申請連續GCD以任何順序的編號。 – starblue 2010-09-03 17:04:10

+1

如果C#爲列表提供了「注入」或「減少」方法,就像許多功能語言一樣,那麼這很簡單。 – 2010-09-03 17:46:15

回答

42

在這裏你有代碼示例使用LINQ和GCD方法從你鏈接的問題。它是利用在其他的答案中描述的理論算法... GCD(a, b, c) = GCD(GCD(a, b), c)

static int GCD(int[] numbers) 
{ 
    return numbers.Aggregate(GCD); 
} 

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

完美,謝謝。只是我在找什麼! – BG100 2010-09-03 12:35:16

+1

小飛車: 'return b == 0? a:GCD(Math.Min(a,b),Math.Max(a,b)%Math.Min(a,b));' ''數字[']時節省多達'%' ]'包含升序值。 – robert4 2014-04-30 12:46:32

+1

@ robert4 - 您的解決方案被零除錯誤。還需要爲'a == 0'添加一個檢查。 '返回b == 0? a:(a == 0?b:GCD(Math.Min(a,b),Math.Max(a,b)%Math.Min(a,b)));' – NightOwl888 2016-10-15 21:33:12

2

Wikipedia

的GCD是一個關聯函數: GCD(一個,GCD(B,C))= GCD(最大公約數(A,B),C)。

三個數字的gcd可以計算爲gcd(a,b,c)= gcd(gcd(a,b),c),或者通過應用交換性和關聯性以不同的方式計算。這可以擴展到任意數量的數字。

只取前兩個元素的最大公約數,然後計算出結果的GCD和第三個元素,然後計算結果和第四元素的最大公約數...

4

這裏的C#版本。

public static int Gcd(int[] x) { 
     if (x.length < 2) { 
      throw new ArgumentException("Do not use this method if there are less than two numbers."); 
     } 
     int tmp = Gcd(x[x.length - 1], x[x.length - 2]); 
     for (int i = x.length - 3; i >= 0; i--) { 
      if (x[i] < 0) { 
       throw new ArgumentException("Cannot compute the least common multiple of several numbers where one, at least, is negative."); 
      } 
      tmp = Gcd(tmp, x[i]); 
     } 
     return tmp; 
    } 

    public static int Gcd(int x1, int x2) { 
     if (x1 < 0 || x2 < 0) { 
      throw new ArgumentException("Cannot compute the GCD if one integer is negative."); 
     } 
     int a, b, g, z; 

     if (x1 > x2) { 
      a = x1; 
      b = x2; 
     } else { 
      a = x2; 
      b = x1; 
     } 

     if (b == 0) return 0; 

     g = b; 
     while (g != 0) { 
      z= a % g; 
      a = g; 
      g = z; 
     } 
     return a; 
    } 

} 

來源http://www.java2s.com/Tutorial/Java/0120__Development/GreatestCommonDivisorGCDofpositiveintegernumbers.htm

+0

我剛纔提到你錯過了第二個功能......但你修好了:)謝謝,這正是我需要的。 – BG100 2010-09-03 12:23:23

+0

我正準備接受你的回答,但Darin Dimitrov和Matajon提出了一個更好的方法。抱歉! (無論如何+1) – BG100 2010-09-03 12:31:59

+1

對不起。我太倉促,認爲我是唯一一個有正確答案的人。 ;)如果速度很重要,應該根據Darin和Matajon描述的LINQ方法來測試這種方法。如果沒有,我很樂意說你應該使用LINQ方法,因爲它更加優雅。 – randomguy 2010-09-03 12:32:17

11

你可以使用一個GCD的這種共同特性:

GCD(a, b, c) = GCD(a, GCD(b, c)) = GCD(GCD(a, b), c) = GCD(GCD(a, c), b) 

假設你有GCD(a, b)已經定義很容易概括:

public class Program 
{ 
    static void Main() 
    { 
     Console.WriteLine(GCD(new[] { 10, 15, 30, 45 })); 
    } 

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

    static int GCD(int[] integerSet) 
    { 
     return integerSet.Aggregate(GCD); 
    }  
} 
+0

謝謝,正是我需要的,但是你的編輯稍微晚了一點,Matajon在你面前提出了同樣的答案......所以我認爲接受他是公平的。 (無論如何+1) – BG100 2010-09-03 12:34:34

1

gcd(a1,a2,...,an)=gcd(a1,gcd(a2,gcd(a3...(gcd(a(n-1),an))))) ,所以我只會一步一步中止荷蘭國際集團,如果如果你的數組排序一些gcd計算爲1

,它可能會更快評估gcd爲早期小數字,因爲那麼它可能是更可能是一個gcd計算結果爲1,你可以停止。

2

,改寫本作爲一個單一的功能...

static int GCD(params int[] numbers) 
    { 
     Func<int, int, int> gcd = null; 
     gcd = (a, b) => (b == 0 ? a : gcd(b, a % b)); 
     return numbers.Aggregate(gcd); 
    } 
0
/* 

Copyright (c) 2011, Louis-Philippe Lessard 
All rights reserved. 

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

*/ 

unsigned gcd (unsigned a, unsigned b); 
unsigned gcd_arr(unsigned * n, unsigned size); 

int main() 
{ 
    unsigned test1[] = {8, 9, 12, 13, 39, 7, 16, 24, 26, 15}; 
    unsigned test2[] = {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048}; 
    unsigned result; 

    result = gcd_arr(test1, sizeof(test1)/sizeof(test1[0])); 
    result = gcd_arr(test2, sizeof(test2)/sizeof(test2[0])); 

    return result; 
} 


/** 
* Find the greatest common divisor of 2 numbers 
* See http://en.wikipedia.org/wiki/Greatest_common_divisor 
* 
* @param[in] a First number 
* @param[in] b Second number 
* @return greatest common divisor 
*/ 
unsigned gcd (unsigned a, unsigned b) 
{ 
    unsigned c; 
    while (a != 0) 
    { 
     c = a; 
     a = b%a; 
     b = c; 
    } 
    return b; 
} 

/** 
* Find the greatest common divisor of an array of numbers 
* See http://en.wikipedia.org/wiki/Greatest_common_divisor 
* 
* @param[in] n Pointer to an array of number 
* @param[in] size Size of the array 
* @return greatest common divisor 
*/ 
unsigned gcd_arr(unsigned * n, unsigned size) 
{ 
    unsigned last_gcd, i; 
    if(size < 2) return 0; 

    last_gcd = gcd(n[0], n[1]); 

    for(i=2; i < size; i++) 
    { 
     last_gcd = gcd(last_gcd, n[i]); 
    } 

    return last_gcd; 
} 

Source code reference

0

這是最常見的三種使用:

public static uint FindGCDModulus(uint value1, uint value2) 
{ 
    while(value1 != 0 && value2 != 0) 
    { 
      if (value1 > value2) 
      { 
        value1 %= value2; 
      } 
      else 
      { 
        value2 %= value1; 
      } 
    } 
    return Math.Max(value1, value2); 
     } 

    public static uint FindGCDEuclid(uint value1, uint value2) 
     { 
    while(value1 != 0 && value2 != 0) 
    { 
      if (value1 > value2) 
      { 
        value1 -= value2; 
      } 
      else 
      { 
        value2 -= value1; 
      } 
    } 
    return Math.Max(value1, value2); 
    } 

    public static uint FindGCDStein(uint value1, uint value2) 
    { 
    if (value1 == 0) return value2; 
    if (value2 == 0) return value1; 
    if (value1 == value2) return value1; 

    bool value1IsEven = (value1 & 1u) == 0; 
    bool value2IsEven = (value2 & 1u) == 0; 

    if (value1IsEven && value2IsEven) 
    { 
      return FindGCDStein(value1 >> 1, value2 >> 1) << 1; 
    } 
    else if (value1IsEven && !value2IsEven) 
    { 
      return FindGCDStein(value1 >> 1, value2); 
    } 
    else if (value2IsEven) 
    { 
      return FindGCDStein(value1, value2 >> 1); 
    } 
    else if (value1 > value2) 
    { 
      return FindGCDStein((value1 - value2) >> 1, value2); 
    } 
    else 
    { 
      return FindGCDStein(value1, (value2 - value1) >> 1); 
    } 
    } 
0

不使用LINQ。

static int GCD(int a, int b) 
    { 
     if (b == 0) return a; 
     return GCD(b, a % b); 
    } 

    static int GCD(params int[] numbers) 
    { 
     int gcd = 0; 
     int a = numbers[0]; 
     for(int i = 1; i < numbers.Length; i++) 
     { 
      gcd = GCD(a, numbers[i]); 
      a = numbers[i]; 
     } 

     return gcd; 
    } 
1
int GCD(int a,int b){ 
    return (!b) ? (a) : GCD(b, a%b); 
} 

void calc(a){ 
    int gcd = a[0]; 
    for(int i = 1 ; i < n;i++){ 
     if(gcd == 1){ 
      break; 
     } 
     gcd = GCD(gcd,a[i]); 
    } 
} 
+0

請給我的答案增加一些解釋。 – 2015-01-10 13:18:47

+0

當然可以採取一些更多的解釋,但這是唯一的答案打破了gcd = 1,所以很榮幸。 – Cimbali 2015-01-10 16:33:32