2010-09-03 22 views
13

Có một số câu hỏi về Ngăn xếp ngăn xếp thảo luận cách tìm số chia chung lớn nhất của hai giá trị. Một câu trả lời hay cho thấy recursive function gọn gàng để thực hiện việc này.Số chia chung lớn nhất từ ​​một tập hợp nhiều hơn 2 số nguyên

Nhưng làm thế nào tôi có thể tìm thấy GCD của một tập hợp nhiều hơn 2 số nguyên? Tôi dường như không thể tìm thấy một ví dụ về điều này.


Có ai đề xuất mã hiệu quả nhất để triển khai chức năng này không?

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

GCD là kết hợp và giao hoán như + và *, vì vậy bạn có thể áp dụng liên tiếp GCD đến những con số theo thứ tự nào. – starblue

+1

nếu C# có phương pháp "tiêm" hoặc "giảm" cho danh sách, giống như nhiều ngôn ngữ chức năng, thì đây là một snap. –

Trả lời

42

Và tại đây bạn có ví dụ về mã sử dụng phương pháp LINQ và GCD từ câu hỏi bạn đã liên kết. Nó được sử dụng thuật toán lý thuyết mô tả trong câu trả lời khác ... 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

Hoàn hảo, cảm ơn. Chỉ là những gì tôi đang tìm kiếm! – BG100

+1

Tốc độ tăng nhỏ: 'return b == 0? a: GCD (Math.Min (a, b), Math.Max ​​(a, b)% Math.Min (a, b)); ' Điều này tiết kiệm tới 50% số phần '%' khi 'số [ ] 'chứa các giá trị tăng dần. – robert4

+1

@ robert4 - Giải pháp của bạn được chia cho 0 lỗi. Cũng cần thêm một dấu kiểm cho 'a == 0'. 'return b == 0? a: (a == 0? b: GCD (Math.Min (a, b), Math.Max ​​(a, b)% Math.Min (a, b))); ' – NightOwl888

2

Wikipedia:

Các gcd là một chức năng kết hợp: gcd (a, gcd (b, c)) = UCLN (UCLN (a, b), c).

Gcd của ba số có thể được tính như gcd (a, b, c) = gcd (gcd (a, b), c) hoặc trong một số cách khác nhau bằng cách áp dụng giao thoa và kết hợp. Điều này có thể được mở rộng đến bất kỳ số lượng nào.

Chỉ cần lấy UCLN của hai yếu tố đầu tiên, sau đó tính toán UCLN của kết quả và các yếu tố thứ ba, sau đó tính toán UCLN của kết quả và yếu tố thứ tư ...

4

Dưới đây là phiên bản 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; 
    } 

} 

Nguồn http://www.java2s.com/Tutorial/Java/0120__Development/GreatestCommonDivisorGCDofpositiveintegernumbers.htm

+0

Tôi vừa đề cập đến việc bạn đã bỏ lỡ chức năng thứ hai ... nhưng bạn đã sửa nó :) Cảm ơn, đây chính xác là những gì tôi cần. – BG100

+0

Tôi đã chấp nhận câu trả lời của bạn, nhưng Darin Dimitrov và Matajon đã đưa ra một phương pháp neater. Lấy làm tiếc! (+1 anyway) – BG100

+1

Xin lỗi về điều đó. Tôi đã quá vội vàng nghĩ rằng tôi là người duy nhất có câu trả lời đúng. ;) Nếu tốc độ là quan trọng, phương pháp này nên được thử nghiệm dựa trên các phương pháp LINQ được mô tả bởi Darin và Matajon. Nếu không, tôi hạnh phúc hơn khi nói rằng bạn nên sử dụng phương pháp LINQ vì nó thanh lịch hơn nhiều. – randomguy

11

Bạn có thể sử dụng tài sản chung này của một GCD:

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

Giả sử bạn có GCD(a, b) đã được xác định nó rất dễ dàng để khái quát:

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

Cảm ơn, chính xác những gì tôi cần, nhưng chỉnh sửa của bạn hơi muộn, Matajon đã đưa ra câu trả lời tương tự ngay trước bạn ... Vì vậy, tôi nghĩ rằng nó chỉ công bằng cho tôi để chấp nhận của mình. (+1 anyway) – BG100

1

gcd(a1,a2,...,an)=gcd(a1,gcd(a2,gcd(a3...(gcd(a(n-1),an))))) , vì vậy tôi sẽ làm điều đó từng bước hủy bỏ Nếu số của bạn được sắp xếp, có thể nhanh hơn để đánh giá gcd cho các số nhỏ trước đó, vì vậy có thể nhiều khả năng một số gcd đánh giá là 1 và bạn có thể dừng lại.

2

Viết lại này như một chức năng duy nhất ...

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

Đây là ba phổ biến nhất đã sử dụng:

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

Không sử dụng 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

vui lòng thêm một số giải thích cho câu trả lời của bạn. –

+0

Chắc chắn nó có thể mất một số giải thích thêm, nhưng đó là câu trả lời duy nhất phá vỡ trên gcd = 1, vì vậy kudo. – Cimbali

Các vấn đề liên quan