范围之间的快速素数

时间:2011-01-28 18:27:46

标签: c#

我正在尝试开发一个程序来开发非常快速的素数。素数将在范围内生成(范围<= 10000),结果应在6秒内打印。这是我到目前为止所做的计划。它在我的机器1.73 core 2 duo上运行得很好,并且在3秒内产生结果。但是当我将它提交给在线程序提交验证器时,它会超出时间限制。我甚至删除了try catch block等,因为我认为删除try catch可能会节省很少的资源并为我买几毫秒,但无论我做什么,我总是会超出时间限制。这是我的代码: -

using System;
using System.Collections.Generic;
using System.Linq;

namespace PrimeNumberGenerator
{
    class Program
    {
        static void Main(string[] args)
        {
                int T = Convert.ToInt32(Console.ReadLine());
                List<string> listInput = new List<string>();

                for (int i = 0; i < T; i++)
                    listInput.Add(Console.ReadLine());

                for (int i = 0; i < T; i++)
                {
                    string[] str = listInput[i].Split(' ');
                    int M = Convert.ToInt32(str[0]);
                    int N = Convert.ToInt32(str[1]);

                    if ((N - M) <= 100000 && M >= 1 && M <= 1000000000 && N >= 1 && N <= 1000000000)
                    {
                        int[] list = Enumerable.Range(M, (N - M + 1)).ToArray();
                        int k = 2;
                        while (true)
                        {
                            if ((k * k) > N)
                                break;
                            for(int j = 0 ; j < list.Count() ;j++)
                            {
                                if (list[j] != k && (list[j] % k) == 0 && list[j] != 1 && list[j] != -1)
                                    list[j] = -1;
                            }

                            k++;
                        }

                        foreach (int item in list)
                        {
                            if (item != -1)
                                Console.WriteLine(item);
                        }

                    }
                    else
                        Console.WriteLine("Limit exceeded");
                }

        }
    }
}

您必须提供以下输入: -

1

2 30

1不是测试用例,2和30表示应生成2到30之间的所有质数。 如果您只测试一次,可以给它1。如果你能优化这个程序,我将非常感激

提前致谢:)

编辑: -

这是我认为的原始实施,但显然有列表的开销: -

using System;
using System.Collections.Generic;
using System.Linq;

namespace PrimeNumberGenerator
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int T = Convert.ToInt32(Console.ReadLine());
                List<string> listInput = new List<string>();

                for (int i = 0; i < T; i++)
                    listInput.Add(Console.ReadLine());

                for (int i = 0; i < T; i++)
                {
                    string[] str = listInput[i].Split(' ');
                    int M = Convert.ToInt32(str[0]);
                    int N = Convert.ToInt32(str[1]);

                    List<int> list = null;
                    if ((N - M) <= 100000 && M >= 1 && M <= 1000000000 && N >= 1 && N <= 1000000000)
                    {
                        list = Enumerable.Range(M, (N - M + 1)).ToList();
                        int k = 2;
                        while (true)
                        {
                            if ((k * k) > N)
                                break;
                            List<int> tempList = new List<int>();
                            foreach (int item in list)
                                if (item != k && (item % k) == 0 && item != 1)
                                    tempList.Add(item);
                            list = list.Except(tempList).ToList();
                            k++;
                        }

                        //list.Remove(1);
                        foreach (int item in list)
                            Console.WriteLine(item);
                        Console.WriteLine();

                    }
                    else
                        Console.WriteLine("Limit exceeded");
                }


            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadKey();
        }
    }
}

3 个答案:

答案 0 :(得分:4)

我只能说,你看起来像循环中的很多循环。可能主要问题只是你的一般算法。

要测试一个数字是否为素数,只需检查它是否可以被2和它的sqrt(向下舍入)之间的任何数字整除。

但是如果你正在检查许多素数,你应该利用这样一个事实:当你检查越来越高的数字时,你只能从素数开始(我会将它们存储在一个简单的List<int>中)。例如,假设您已达到数字27.您只需要检查它是否可以被2,3或5整除(您已经找到的素数小于sqrt(25),即5),而不是4(因为4可以被2整除 - 如果它可以被4整除,那么它可以被2)整除,而不是高于该值的任何东西(如果它被5以上的任何东西整除,则商将低于5,你就已经检查了它)

这些是一些一般性的概念,应该帮助你优化乍看之下像一个非常低效的算法。

答案 1 :(得分:2)

性能问题有三种解决方案:基准测试,基准测试,基准测试。

使用分析器对代码进行基准测试。对于C#,我个人更喜欢ANTS Performance Profiler,但也有其他选择。

我建议您更新(或发布另一个)具有特定瓶颈的问题。

答案 2 :(得分:1)

您的程序预计会在6秒内输出数字(时间紧迫),因此您应该在6秒内充分利用内存以节省时间。例如,您可以使用多线程或并行编程来更快地生成数字(更多CPU /内存使用)。目前,您正在以常规方式工作,这无法展示C#的优势(您的代码可以直接转换为C / Java /其他几乎没有变化的代码)。你需要用C#方式做,否则你为什么选择C#?这是一个示例(未经过测试,但我认为应该是正确的),这更像是C#方式。

int min = 2;
int max = 10000;

Enumerable.Range(min, max - min + 1)
          .AsParallel()
          .ForAll(g =>
             {
                 bool prime = true;
                 for (int i = 2; i <= Math.Sqrt(g); i++)
                 {
                      if (g % i == 0)
                      {
                         prime = false;
                         break;
                      }
                 }
                 if (prime) Console.WriteLine(g);
             });

编辑:我刚刚测试了代码,在0秒内打印出小于10000的素数,由StopWatch测量。