【问题标题】:C# Sieve of EratosthenesC# 埃拉托色尼筛
【发布时间】:2014-09-06 16:13:31
【问题描述】:

我已经编写了这段代码来查找素数,它运行良好,但是计算速度非常慢.....我做错了吗?我知道我可能真的以错误的方式做这件事,但请帮助我!非常感谢!

using System;
using System.Collections.Generic;

namespace Primenumbers
{
    class MainClass
    {
        public static void Main (string[] args)
        {    
            List<int> NoPrime = new List<int>();

            for(int x = 2; x < 10000;x++)
            {
                for(int y = x * 2;y < 10000;y = y + x)
                {    
                    if(!NoPrime.Contains(y))
                    {
                        NoPrime.Add(y);
                    }    
                }    
            }

            for(int z = 2; z < 10000;z++)
            {
                if(!NoPrime.Contains(z))
                {
                    Console.WriteLine(z);
                }
            }
        }
    }
}

编辑: 这是新代码,我将“List”更改为“HashSet”并添加了一个计数器来获取所有素数的总和。非常感谢所有评论/回答的人,你们太棒了!

using System;
using System.Collections.Generic;

class MainClass
{
    public static void Main (string[] args)
    {
        HashSet<int> NoPrime = new HashSet<int>();

        long count = 0;
        int n = 2000000;

        for(int x = 2; x < n;x++)
        {
            for(int y = x * 2;y < n;y = y + x)
            {

            if(!NoPrime.Contains(y))
            {
                NoPrime.Add(y);
            }
        }

        for(int z = 2; z < n;z++)
        {
            if(!NoPrime.Contains(z))
            {
                Console.WriteLine(z);
                count = count + z;
            }
        }

        Console.WriteLine("Sum is: " + count);
    }
}

【问题讨论】:

  • 使用 HashSet 而非 List..
  • 包含进行线性搜索。我建议使用数组。使用的内存更多,但速度更快。
  • 这个问题可能更适合codereview.stackexchange.com
  • @Ondra:不,不是。 List 使用数组进行内部存储,没错,但在素数/非素数方面它是稀疏的。该数组是密集的,这使得查找特定元素变得简单而快速。
  • @ondra:我不是说使用 array.contains。我的意思是在索引处检查 0 或 1。例如 a (4) = 0 表示 4 不是素数。 a (5) = 1 表示 5 是素数。

标签: c# primes


【解决方案1】:

您的代码的复杂性介于 O(n * (n log n)) 和 O(n ^ 3) 之间(不完全确定)而不是 O(n log log n)(请参阅 Sieve of Eratosthenes: Complexity )。更高的复杂性引起的

  • NoPrime 列表中进行线性搜索(给复杂度一个额外的n
  • 外循环缺少“查找下一个素数”检查 - 因此内循环的复杂度超过 O(log log n)

修复:

更改为Dictionary&lt;int,bool&gt;(或者更好的是根据 cmets 中的建议改为HashSet&lt;int&gt;)以获得Contains 的 O(1) 复杂度。或者,您可以通过为每个数字分配 bool 的大数组并标记项目 true 来直接实现算法(再次给出 O(1) 检查数字是否为素数)。

在外部循环中添加检查以跳过 x 不是素数的内部迭代。

【讨论】:

  • 我实际上只是将'List'更改为'HashSet'并解决了这个问题,程序在短短15,75秒内打印出所有低于200万的素数,非常感谢大家!
  • 为什么是 N^2?使用 O(1) Contains(和 Add)它是 N*log(N)。
  • @WillNess - 感谢提醒,由于内部循环的步长可变,复杂性实际上优于 O(n^2)。请注意,根据维基百科,它实际上更好 - log log n,而不仅仅是 log n
  • 我说的是 OP 代码(固定为 O(1) 访问)。它在 Nlog(N) 中,因为它不枚举素数,而是枚举 *all 数字。使用 O(N) 访问它在 N^2*log(N) 中。可以通过empirical orders of growth轻松测量。
【解决方案2】:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace primefinder2
{
    class Program
    {
        static void Main(string[] args)
        {
            //edited version of Alexander Ameye's code (https://stackoverflow.com/users/4014883/alexander-ameye)
            HashSet<int> NoPrime = new HashSet<int>();
        long count = 0;
        Console.WriteLine("please enter a max search value");
        bool input = int.TryParse(Console.ReadLine(), out int n);
        while (input == false)
        {
            Console.WriteLine($"{input} is not a valid value.\nPlease enter a valid number");
            input = int.TryParse(Console.ReadLine(), out n);

        }
        string name = $"Primes_to_{n}";
        string filename = String.Format("{0:yyyy-MM-dd-hh-mm}__{1}", DateTime.Now, name);
        for (int x = 2; x < n; x++)
        {
            for (int y = x * 2; y < n; y = y + x)
            {

                if (!NoPrime.Contains(y))
                {
                    NoPrime.Add(y);
                }

            }

        }

        for (int z = 2; z < n; z++)
        {
            if (!NoPrime.Contains(z))
            {
                Console.WriteLine(z);
                using (System.IO.StreamWriter file =
        new System.IO.StreamWriter($@"{filename}.csv", true))
                {
                    file.WriteLine(z);
                }
                count = count + z;
            }
        }

        Console.WriteLine($"Sum is: {count}");
        Console.ReadLine();


    }
}
}

我对代码做了一些细微的修改,以允许用户确定搜索长度并将素数写入 CSV 以供将来参考。 让我知道我是怎么做的,如果我的编辑有什么可以解决的。

【讨论】:

    猜你喜欢
    • 2011-12-16
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多