2

我目前正在尝试一些问题,只是为了练习我的编程技能。(还没有在学校或任何东西上学习,自学)我遇到了这个问题,需要我从给定的 txt 文件中读取一个数字。这个数字是 N。现在我想找到 N <= 10 000 的第 N 个素数。找到它之后,我想把它打印到另一个 txt 文件中。现在对于问题的大部分部分,我能够理解并设计一种获得 N 的方法。问题是我正在使用一个数组来保存以前找到的素数,以便使用它们来检查未来的数字。即使我的数组大小为 100,只要输入整数大约 < 15,程序就会崩溃。

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;

int main() {
    ifstream trial;
    trial.open("C:\\Users\\User\\Documents\\trial.txt");
    int prime;
    trial >> prime;
    ofstream write;
    write.open("C:\\Users\\User\\Documents\\answer.txt");
    int num[100], b, c, e;
    bool check;
    b = 0;
    switch (prime) {
        case 1:
        {
            write << 2 << endl;
            break;
        }
        case 2:
        {
            write << 3 << endl;
            break;
        }
        case 3:
        {
            write << 5 << endl;
            break;
        }
        case 4:
        {
            write << 7 << endl;
            break;
        }
        default:
        {
            for (int a = 10; a <= 1000000; a++) {
                check = false;
                if (((a % 2) != 0) && ((a % 3) != 0) && ((a % 5) != 0) && ((a % 7) != 0)) // first filter
                {
                    for (int d = 0; d <= b; d++) {
                        c = num[d];
                        if ((a % c) == 0) {
                            check = true; // second filter based on previous recorded primes in array
                            break;
                        }

                    }
                    if (!check) {
                        e = a;
                        if (b <= 100) {
                            num[b] = a;
                        }

                        b = b + 1;
                    }
                }
                if ((b) == (prime - 4)) {
                    write << e << endl;
                    break;
                }
            }
        }
    }
    trial.close();
    write.close();
    return 0;
}

我完全根据我的傻瓜指南和我自己做到了这一点,所以请原谅我算法的一些代码效率低下和一般新手。对于最多 15 个,它也能正确显示素数。

谁能告诉我应该如何改进当前的代码?我正在考虑使用 txt 文件代替数组。那可能吗?任何帮助表示赞赏。

4

14 回答 14

16

由于您的问题是关于编程而不是数学,所以我也会尽量保持我的回答。

第一眼你的代码让我想知道你到底在做什么......如果你阅读答案,你会意识到他们中的一些人并没有费心理解你的代码,而有些人只是将你的代码转储到调试器看看发生了什么。是我们这么不耐烦吗?或者仅仅是你的代码对于一个相对简单的问题来说太难理解了?

要改进您的代码,请尝试问自己一些问题:

  1. 什么是a、、、bc?给更有意义的名字不是更好吗?
  2. 你的算法到底是什么?你能用英文写下你正在做的事情的清晰段落吗(以准确的方式)?您能否将段落修改为一系列步骤,您可以在精神上对任何输入执行并且可以确定它是正确的?
  3. 所有步骤都需要吗?我们可以合并甚至消除其中的一些吗?
  4. 有哪些步骤用英语很容易表达,但在 C/C++ 中需要超过 10 行?
  5. 您的步骤列表是否有任何结构?循环?大(可能是重复的)块可以作为一个步骤与子步骤一起放置吗?

完成问题后,您可能会得到一个布局清晰的伪代码来解决问题,并且易于解释和理解。之后,您可以用 C/C++ 或实际上任何通用语言实现您的伪代码。

于 2009-02-02T08:22:54.607 回答
1

我还没有查看您的代码,但是您的数组必须足够大以包含您将存储在其中的所有值。对于这个问题的大多数输入,100 肯定是不够的。

例如这段代码..

int someArray[100];
someArray[150] = 10;

写入比数组大的位置 (150 > 100)。这称为内存覆盖。根据该内存位置发生的情况,您的程序可能会立即、稍后或根本不会崩溃。

使用数组时的一个好习惯是以某种方式断言您正在写入的元素在数组的范围内。或者使用执行此检查的数组类型类。

对于您的问题,最简单的方法是使用 STL 向量类。虽然您必须添加元素 (vector::push_back()),但您可以稍后使用数组运算符 [] 访问元素。Vector 也会给你最好的迭代性能。

这是一些将数字 0-100 添加到向量然后打印它们的示例代码。请注意,在第二个循环中,我们使用存储在向量中的项目数。

#include <vector> // std::vector

...

const int MAX_ITEMS = 100;

std::vector<int> intVector;

intVector.reserve(MAX_ITEMS); // allocates all memory up-front

// add items
for (int i = 0; i < MAX_ITEMS; i++)
{
  intVector.push_back(i);  // this is how you add a value to a vector;
}

// print them
for (int i = 0; i < intVector.size(); i++)
{
  int elem = intVector[i]; // this access the item at index 'i'
  printf("element %d is %d\n", i, elem);
}
于 2009-02-02T07:49:10.163 回答
1

您可能需要考虑两种测试素数的方法:

  1. 问题域足够小,仅循环数字直到找到第 N 个素数可能是一个可接受的解决方案,并且只需不到几毫秒即可完成。您可以对这种方法进行许多简单的优化,例如您只需要测试它是否可以被 2 整除一次,然后您只需检查奇数并且您只需检查小于或等于的数字到被测数字的平方根。
  2. 埃拉托色尼筛法非常有效且易于实施,并且在数学方面非常轻松。

至于你的代码为什么会崩溃,我怀疑改变了读取的行

for( int d=0; d<=b; d++) 

for( int d=0; d<b; d++) 

将解决问题,因为您正试图从可能包含垃圾的数组的潜在未初始化元素中读取。

于 2009-02-02T07:50:18.727 回答
1

我现在正在尝试改进我的函数式编程,所以我只是快速编写了筛子。我想我会把它贴在这里。如果你还在学习,你可能也会觉得它很有趣。

#include <iostream>
#include <list>
#include <math.h>
#include <functional>
#include <algorithm>

using namespace std;

class is_multiple : public binary_function<int, int, bool>
{
    public:
        bool operator()(int value, int test) const
        {
            if(value == test) // do not remove the first value
                return false;
            else
                return (value % test) == 0;
        }
};

int main() 
{
    list<int> numbersToTest;
    int input = 500;

    // add all numbers to list
    for(int x = 1; x < input; x++)
        numbersToTest.push_back(x);

    // starting at 2 go through the list and remove all multiples until you reach the squareroot
    // of the last element in the list
    for(list<int>::iterator itr = ++numbersToTest.begin(); *itr < sqrt((float) input); itr++)
    {
        int tmp = *itr;
        numbersToTest.remove_if(bind2nd(is_multiple(), *itr));  
        itr = find(numbersToTest.begin(), numbersToTest.end(), tmp); //remove_if invalidates iterator 
                                                                 // so find it again. kind of ugly
    }

    // output primes
    for(list<int>::iterator itr = numbersToTest.begin(); itr != --numbersToTest.end(); itr++)
        cout << *itr << "\t";

    system("PAUSE");

    return 0;
}

顺便说一句,任何关于如何改进这一点的建议都将受到欢迎。

于 2009-02-02T10:22:25.283 回答
1

这是我的代码。处理大数字时,速度非常慢!它可以计算您输入的数字中的所有素数!

#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;

int main()
{
    int m;
    int n=0;
    char ch;
    fstream fp;
    cout<<"What prime numbers do you want get within?  ";
    if((cin>>m)==0)
    {
                 cout<<"Bad input! Please try again!\n";
                 return 1;
    }
    if(m<2)
    {
        cout<<"There are no prime numbers within "<<m<<endl;
        return 0;
    }
    else if(m==2)
    {
        fp.open("prime.txt",ios::in|ios::out|ios::trunc);//create a file can be writen and read. If the file exist, it will be overwriten.
        fp<<"There are only 1 prime number within 2.\n";
        fp<<"2\n";
        fp.close();
        cout<<"Congratulations! It has worked out!\n";
        return 0;
    }
    else
    {
        int j;
        int sq;
        fp.open("prime.txt",ios::in|ios::out|ios::trunc);
        fp<<"2\t\t";
        n++;
        for(int i=3;i<=m;i+=2)
        {
            sq=static_cast<int>(sqrt(i))+1;
            fp.seekg(0,ios::beg);
            fp>>j;
            for(;j<sq;)
            {
                if(i%j==0)
                {
                    break;
                }

                else
                {
                    if((fp>>j)==NULL)
                    {
                        j=3;
                    }
                }
            }
            if(j>=sq)
            {
                fp.seekg(0,ios::end);
                fp<<i<<"\t\t";
                n++;
                if(n%4==0)
                    fp<<'\n';
            }
        }
        fp.seekg(0,ios::end);
        fp<<"\nThere are "<<n<<" prime number within "<<m<<".\n";
        fp.close();
        cout<<"Congratulations! It has worked out!\n";
        return 0;
    }
}
于 2011-06-30T13:55:25.603 回答
0

由于这是出于教学目的,我建议实施Eratosthenes 筛

于 2009-02-02T07:44:24.823 回答
0

一方面,如果您没有针对 3、5 和 7 的特殊情况,您将拥有更少的代码(这总是一件好事!)。

此外,如果您仅设置 num[b] = 2 并且仅测试数组中事物的可分性,则可以避免 2 的特殊情况。

于 2009-02-02T07:50:25.200 回答
0

看起来当您绕过主 for() 循环时, b 的值会增加。

然后,这会导致崩溃,因为您访问数组末尾的内存:

                for (int d = 0; d <= b; d++) {
                    c = num[d];

我认为您需要更清楚地了解算法,然后再次处理代码。

于 2009-02-02T07:52:16.790 回答
0

通过调试器运行您的代码,我发现它在“”处因浮点异常而崩溃if ((a % c) == 0)。这样做的原因是你没有在 num 中初始化任何东西,所以你正在做“a % 0”。

于 2009-02-02T07:53:29.547 回答
0

据我所知,在 C/C++ 中,int 是 16 位类型,因此不能容纳 100 万个(限制为 2^16=32k)。尝试并声明“a”

我认为 C 标准说它int至少shortlong.

实际上int是 4 个字节,因此它可以容纳 和 之间-2^31的数字2^31-1

于 2009-02-02T07:55:59.947 回答
0

您也应该对此感兴趣:http ://en.wikipedia.org/wiki/Primality_test

于 2009-02-02T08:19:14.333 回答
0
for(int currentInt=2; currentInt<=1000000; currentInt++) 

{check = false;  // Basically the idea for this for loop is to run checks against integers. This is the main for loop in this program. I re initialize check to false ( check is a bool declared above this. )

for( int arrayPrime=0; arrayPrime<currentPrime; arrayPrime++) // This for loop is used for checking the currentInt against previously found primes which are stored in the num array.

{ c=num[arrayPrime];
        if ((currentInt%c)==0) { check = true;// second filter based on previous recorded primes in array
                break;}  // this is the check. I check the number against every stored value in the num array. If it's divisible by any of them, then bool check is set to true.


if ( currentInt == 2)
{ check = false; } // since i preset num[0] = 2 i make an exception for the number 2.

if (!check)
{
e=a;
if(currentPrime <= 100){
num[currentPrime]= currentInt;} // This if uses check to see if the currentInt is a prime. 

currentPrime = currentPrime+1;} // increases the value of currentPrime ( previously b ) by one if !check.

if(currentPrime==prime)
{
write<<e<<endl;
break;}           // if currentPrime == prime then write the currentInt into a txt file and break loop, ending the program.

感谢您的建议 polythinker =)

于 2009-02-02T10:22:40.667 回答
0
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <fstream>

using namespace std;

int main()
{
ifstream trial;
trial.open("C:\\Users\\User\\Documents\\trial.txt");
int prime, e;
trial>>prime;
ofstream write; 
write.open("C:\\Users\\User\\Documents\\answer.txt");
int num[10000], currentPrime, c, primePrint;
bool check;
currentPrime=0;
num[currentPrime] = 2;
currentPrime=1;

for(int currentInt=2; currentInt<=1000000; currentInt++) 
{check = false; 
for( int arrayPrime=0; arrayPrime<currentPrime; arrayPrime++) 
        { c=num[arrayPrime];
            if ((currentInt%c)==0) { check = true;// second filter based on previous recorded primes in array
                    break;}
               }


 if (!check)
    { e=currentInt;  
    if( currentInt!= 2 ) { 
    num[currentPrime]= currentInt;}
    currentPrime = currentPrime+1;}
    if(currentPrime==prime)
    {
    write<<e<<endl;
    break;}
    }
trial.close();
write.close();
return 0;
}

这是基于我的原始代码的最终版本。它工作得很好,如果你想增加素数的范围,只需增加数组数。感谢您的帮助 =)

于 2009-02-02T15:15:29.203 回答
0

由于以后的问题需要更大的素数,我建议你听从 dreeves 的建议,做一个筛子。这是一个非常有用的箭,放在你的箭袋里。

于 2009-02-02T16:04:40.290 回答