2011-04-26 71 views
9

所以我只想查找给定数字的所有除数(除了数字本身)。 目前,我有这样的:高效查找数字的所有因数

public static List<int> proper_divisors(int x) 
{ 
    List<int> toreturn = new List<int>(); 
    toreturn.Add(1); 
    int i = 0; 
    int j=1; 
    int z = 0; 
    while (primes.ElementAt(i) < Math.Sqrt(x)) 
    { 
     if (x % primes.ElementAt(i) == 0) 
     { 
      toreturn.Add(primes.ElementAt(i)); 
      toreturn.Add(x/primes.ElementAt(i)); 
      j = 2; 
      z = (int)Math.Pow(primes.ElementAt(i), 2); 
      while (z < x) 
      { 
       if (x % z == 0) 
       { 
        toreturn.Add(z); 
        toreturn.Add(x/z); 
        j++; 
        z = (int)Math.Pow(primes.ElementAt(i), j); 
       } 
       else 
       { 
        z = x; 
       } 
      } 
     } 
     i++; 
    } 
    toreturn = toreturn.Distinct().ToList<int>(); 
    return toreturn; 
} 

其中素数是素数的列表,(假设它是正确的,足够大)。 该算法的工作原理是它可以找到所有的素数因子,但不是所有的因子(即给出34534,它返回{1,2,17267,31,1114}但错过{62,557},因为62是一个组合,因此错过557为好。

我也尝试刚开了许多的首要因素,但我不知道如何将其转换成所有的正确组合的列表。

的该算法的代码如下:

public static List<int> prime_factors(int x) 
{ 
    List<int> toreturn = new List<int>(); 
    int i = 0; 
    while (primes.ElementAt(i) <= x) 
    { 
     if (x % primes.ElementAt(i) == 0) 
     { 
      toreturn.Add(primes.ElementAt(i)); 
      x = x/primes.ElementAt(i); 
     } 
     else 
     { 
      i++; 
     } 
    } 
    return toreturn; 
} 

关于如何解决的第一个,或如何创建组合从塞康列表中的任何想法d一个(我宁愿那样会更快)?

+0

的可能的复制[最佳在C#中查找给定数字的所有因素的方法](http://stackoverflow.com/questions/239865/best-way-to-find-all-factors-of-a-given-number-in-c-sharp ) – MxNx 2016-10-03 11:53:49

回答

7

既然你已经拥有的主要因素清单,你想要做的是计算该列表的幂。

现在,一个问题是,你可能会在列表中重复(例如20 = 2 * 2 * 5的主要因素),但集合不允许重复。因此,我们可以通过将其投影到形式为{x,y}的结构来使列表中的每个元素唯一,其中x是素数,y是列表中素数的索引。现在

var all_primes = primes.Select((x, y) => new { x, y }).ToList(); 

all_primes的形式是{X,Y},其中x是素数,y是该列表中的索引的列表。

然后我们计算功率设定(以下GetPowerSet定义):

var power_set_primes = GetPowerSet(all_primes); 

因此,power_set_primesIEnumerable<IEnumerable<T>>其中T是匿名类型{x, y}其中x和y是int类型。

接下来,我们计算的权力每个元素的产品集

foreach (var p in power_set_primes) 
{ 
    var factor = p.Select(x => x.x).Aggregate(1, (x, y) => x * y); 
    factors.Add(factor); 
} 

全部放在一起:

var all_primes = primes.Select((x, y) => new { x, y }).ToList(); //assuming that primes contains duplicates. 
var power_set_primes = GetPowerSet(all_primes); 
var factors = new HashSet<int>(); 

foreach (var p in power_set_primes) 
{ 
    var factor = p.Select(x => x.x).Aggregate(1, (x, y) => x * y); 
    factors.Add(factor); 
} 

http://rosettacode.org/wiki/Power_Set为幂的实现。

public IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list) 
{ 
    return from m in Enumerable.Range(0, 1 << list.Count) 
      select 
       from i in Enumerable.Range(0, list.Count) 
       where (m & (1 << i)) != 0 
       select list[i]; 
} 
+0

我不关注。因素是我发现的主要因素列表? 因为我想要的是乘以小于或等于数字的因素的所有组合,必须有更好的方法。 – soandos 2011-04-26 16:48:51

+0

Opps,那不应该是Math.Floor ...编辑... – 2011-04-26 16:52:05

+0

虽然这不是真的。目前,如果素数超过自身时间,这将不会给出正确的因素(这种情况发生了很多,即每次9是一个因素......) – soandos 2011-04-26 16:59:45

5

有类似的问题before,它有一个使用IEnumerable的有趣解决方案。如果你想要所有的因数而不是因素,并且假设你至少使用C#3。0您可以使用这样的事情:

static IEnumerable<int> GetDivisors(int n) 
{ 
    return from a in Enumerable.Range(2, n/2) 
      where n % a == 0 
      select a;      
} 

,然后用它是这样的:

foreach(var divisor in GetDivisors(10)) 
    Console.WriteLine(divisor); 

,或者,如果你想有一个列表,只需:

List<int> divisors = GetDivisors(10).ToList(); 
+0

再次,这是一个很好的方式来做它的蛮力。但鉴于我有一个必要的素数列表,没有理由这样做。 – soandos 2011-04-26 16:46:33

+0

因此,如果你有数字的所有主要因素,并且只想要它们之间的所有组合,为什么不使用笛卡尔积,那就是:'从素数中的y在素数中选择x!= y选择x * y' ?这可以解决你的问题,只要你的素数有1(否则.Concat(素数)就可以解决这个问题) – LazyOfT 2011-04-26 16:59:21

+0

我该怎么做? – soandos 2011-04-26 17:00:15