C# 计算两个以上值的最大公约数(GCD)

C# 计算两个以上值的最大公约数(GCD),c#,.net,vb.net,math,C#,.net,Vb.net,Math,在VB.NET或C#中,我希望能够动态计算一个或多个值的最大公约数(GCD),而无需使用递归方法 我以C#中的一个指导性解决方案来计算两个值的GCD。现在,我想调整该解决方案,使其能够计算未知数量的值(一个或多个包含在传递给下面函数的值数组中的值) 这就是我当时所做的: VB.NET(原始代码): 我知道将类型转换为List会影响大量值的总体性能,但最重要的是使该算法按预期工作,并最终对其进行优化/重构 对于某些价值观的组合,我的改编正如预期的那样有效,但对于其他价值观的组合则不起作用。例如,在

在VB.NET或C#中,我希望能够动态计算一个或多个值的最大公约数(GCD),而无需使用递归方法

我以C#中的一个指导性解决方案来计算两个值的GCD。现在,我想调整该解决方案,使其能够计算未知数量的值(一个或多个包含在传递给下面函数的值数组中的值)

这就是我当时所做的:

VB.NET(原始代码):

我知道将类型转换为List会影响大量值的总体性能,但最重要的是使该算法按预期工作,并最终对其进行优化/重构


对于某些价值观的组合,我的改编正如预期的那样有效,但对于其他价值观的组合则不起作用。例如,在在线GCD计算器中,如果我们输入以下值:{1920、1080、5000、1000、6800、5555}理论上,GCD是5,或者至少是该在线服务计算的GCD,但我的算法返回15。

可以使用Linq执行此操作:

    static int GCD2(int a, int b){
        return b == 0 ? Math.Abs(a) : GCD2(b, a % b);
    }

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

您所面临的问题是由于您过早地离开内部循环造成的。检查任何值是否为0是不够的,因为实际上必须检查除了一个值以外的所有值是否为0

C代码可能如下所示:

private static int InternalGetGreatestCommonDivisor(params int[] values)
{
    // Calculate GCD for 2 or more values...
    if (values.Length > 1)
    {
      while (values.Count(value => value > 0) != 1)
      {
          int firstMaxValue = values.Max();
          int secondMaxValue = values.OrderByDescending((int @int) => @int).ElementAtOrDefault(1);
          values[values.ToList().IndexOf(firstMaxValue)] = (firstMaxValue % secondMaxValue);
      }

      return values.Max();

    }
    else
    {
      // Calculate GCD for a single value...
    }

}
对于您的示例,代码返回
5
。恐怕我无法给出VB.NET代码的确切表示形式。

//在数组中传递所有值并调用findGCD函数
// pass all the values in array and call findGCD function
    int findGCD(int arr[], int n) 
    { 
        int gcd = arr[0]; 
        for (int i = 1; i < n; i++) {
            gcd = getGcd(arr[i], gcd); 
}

        return gcd; 
    } 

// check for gcd
int getGcd(int x, int y) 
    { 
        if (x == 0) 
            return y; 
        return gcd(y % x, x); 
    } 
int findGCD(int arr[],int n) { int gcd=arr[0]; 对于(int i=1;i
当您不使用变量“value”时,为什么要“将每个值作为值中的整数”进行这种类型的循环?@我知道设计是错误的,这就是我问的原因。然而,循环只是执行一个完整的循环迭代,而不是使用每个迭代值。我越来越接近(在大多数情况下是正确的)GCD这样做。但我知道这是错误的,我坚持。谢谢你的评论。
gcd(a,b,c)=gcd(a,gcd(b,c))
。这意味着,如果您有一个适用于两个参数的
gcd
函数,则可以使用LINQ的
Enumerable.Aggregate
将其提升到集合中。这不涉及递归,优化它(如果需要)可能与对集合排序一样简单。有点像,只是我不会递归地编写
GCD2
,因为优雅的非递归实现非常简单。不,排序值根本不需要正确性,但使用欧几里德算法,您可能希望“优化”顺序,以确保操作次数最少。除非有明显的必要,否则我不会从优化任何东西开始。@ElektroStudios您的问题隐藏在这里:
Do而不是value.Contains(0)
。你堕胎太早了。检查除一个值外所有值是否为零,然后离开。0以上的最后一个值就是您要查找的值。当然,还要去掉无用的foreach。谢谢,但这是递归的。如果您将“GCD2”函数修改为非递归函数(例如,如果您想复制并粘贴此函数),我会接受这个答案
private static int InternalGetGreatestCommonDivisor(params int[] values)
{
    // Calculate GCD for 2 or more values...
    if (values.Length > 1)
    {
      while (values.Count(value => value > 0) != 1)
      {
          int firstMaxValue = values.Max();
          int secondMaxValue = values.OrderByDescending((int @int) => @int).ElementAtOrDefault(1);
          values[values.ToList().IndexOf(firstMaxValue)] = (firstMaxValue % secondMaxValue);
      }

      return values.Max();

    }
    else
    {
      // Calculate GCD for a single value...
    }

}
// pass all the values in array and call findGCD function
    int findGCD(int arr[], int n) 
    { 
        int gcd = arr[0]; 
        for (int i = 1; i < n; i++) {
            gcd = getGcd(arr[i], gcd); 
}

        return gcd; 
    } 

// check for gcd
int getGcd(int x, int y) 
    { 
        if (x == 0) 
            return y; 
        return gcd(y % x, x); 
    }