【发布时间】:2011-08-14 17:04:31
【问题描述】:
这更像是一个效率问题,而不是通用的“找到一种方法”,但是在得到一些奇怪的结果之后,我想看看是否有人可以告诉我为什么最后一种方法效率如此之低:
方式1:蛮力,无优化
public static List<int> proper_divisors(int x)
{
List<int> toreturn = new List<int>();
for (int i = 1; i <= Math.Floor(Math.Sqrt(x)); i++)
{
if (x % i == 0)
{
toreturn.Add(i);
toreturn.Add(x / i);
}
}
if (toreturn.ElementAt(toreturn.Count() / 2) == toreturn.ElementAt(toreturn.Count() / 2 - 1))
{
toreturn.Remove(toreturn.ElementAt(toreturn.Count() / 2));
}
return toreturn;
}
方式2:和以前一样,但是这次先检查它是否是素数(因为这些情况占用的时间最多,使用miller-rabin进行素数检查)
public static List<int> proper_divisors(int x)
{
List<int> toreturn = new List<int>();
if (!isprime(x))
{
for (int i = 1; i <= Math.Floor(Math.Sqrt(x)); i++)
{
if (x % i == 0)
{
toreturn.Add(i);
toreturn.Add(x / i);
}
}
if (toreturn.ElementAt(toreturn.Count() / 2) == toreturn.ElementAt(toreturn.Count() / 2 - 1))
{
toreturn.Remove(toreturn.ElementAt(toreturn.Count() / 2));
}
}
else
{
toreturn.Add(1);
toreturn.Add(x);
}
return toreturn;
}
到目前为止,它认为最快的方法是方法 3,因为每次找到素数时它都会减少它使用的数字,并且它只尝试素数(这些是在运行时由筛子生成的,大约需要 34 毫秒才能得到所有小于一百万的素数)这种方式要做的最后一件事是获取素数及其幂,并列出所有因数。
方式 3:
public static HashSet<int> prime_factors(int x)
{
if (!isprime(x))
{
List<int> toreturn = new List<int>();
int i = 0;
while (primes[i] <= x)
{
if (x % primes[i] == 0)
{
toreturn.Add(primes[i]);
x = x / primes[i];
}
else
{
i++;
}
}
var power_set_primes = GetPowerSet(toreturn);
var factors = new HashSet<int>();
foreach (var p in power_set_primes)
{
var factor = p.Select(z => z).Aggregate(1, (z, y) => z * y);
factors.Add(factor);
}
return factors;
}
else
{
HashSet<int> toreturn = new HashSet<int>();
toreturn.Add(1);
toreturn.Add(x);
return toreturn;
}
public static 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];
}
分解前一百万个数字所需的时间: 方式1:7223毫秒 方式 2:8985 毫秒(我猜对于少量的素数检查不值得) 方式3:49423毫秒
所以我的问题是双重的: 1)为什么方式3这么慢??? 2)有什么东西可以让它更快吗? 顺便说一句,素数被计算为一个列表,然后转换为一个数组,因为我认为这样会更快。不好的举动?
【问题讨论】:
-
你不是已经问过这个了吗? stackoverflow.com/questions/5793009/…
-
配置文件配置文件。此外,如果您关心那里的效率,请不要使用枚举器或 LINQ。用 C 语言编写并使用 P/Invoke。一般来说,如果你能衡量它,不要问这个问题
-
请使用类似“result”而不是“toreturn”。
-
我相信#3由于内存使用而效率低下。您必须查看一块太大而无法放入缓存的内存。
标签: c# .net aggregate primes factorization