今天有位朋友去面试,一道题是“写段代码验证哥德巴赫猜想”,觉得很有意思,因为其中涉及到刚接触计算机时搞过的求素数算法,在记忆中,为了提高效率(用空间换时间),应该是保留已求得的素数,然后在判断N的时候,只需用N去依次试除所有不大于N平方根的已知质数,而勿需遍历小于N的所有(奇)数。
按上述思路编制的Primes类如下,可做为“验证哥德巴赫猜想”的辅助类(因为这个需求,所以该类的generate()方法可以按需要计算出所需的素数)。
这个求素数的算法速度很不错,在我赛扬2.0的机器上,大约在1.5秒就可以算出所有小于一百万的素数,共78,498个。
#pragma once
#include <vector>
#include <ostream> // for ostream & operator << ()
#include <cmath> // for sqrt()
class Primes {
public:
Primes() {
primes_.push_back(2);
primes_.push_back(3);
}
//生成不小于maxValue的所有质数
void generate(int maxValue) {
if (maxValue <= getMaxPrime())
return;
for (int v=getMaxPrime()+2; v<=maxValue; v+=2) {
int sqrtV = static_cast<int>(sqrt(static_cast<double>(v)));
bool isPrime = true;
for (size_t i=0; i<primes_.size() && primes_[i]<=sqrtV; ++i) {
if (0==(v % primes_[i])) {
isPrime = false;
break;
}
}
if (isPrime)
primes_.push_back(v);
}
}
//取已生成的最大质数
int getMaxPrime() const { return primes_[primes_.size()-1]; }
//取已生成的质数个数
size_t getCount() const { return primes_.size(); }
//取已生成质数中的指定序号项的质数
int operator[](int index) const { return primes_[index]; }
//判断给定数是不是质数
bool isPrime(int value) const {
if (value<primes_[0] || (value!=2 && 0==(value % 2)) || value>getMaxPrime())
return false;
//用二分法在已知质数中查找
size_t low=0, high=primes_.size()-1;
while (low<=high) {
size_t midd = (low + high) / 2;
int middPrime = getValue(midd);
if (value==middPrime)
return true;
if (value<middPrime)
high = midd - 1;
else
low = midd + 1;
}
return false;
}
//测试用,将生成的所有质数输出到流中
friend std::ostream & operator << (std::ostream & os, const Primes & right) {
for (size_t i=0; i<right.primes_.size(); ++i)
os << right.primes_[i] << "/t";
os << std::endl;
return os;
}
private:
std::vector<int> primes_;
};
网上有段FLASH演示二分查找,很有意思: