【问题标题】:Prime Sieve class or overloaded function?Prime Sieve 类或重载函数?
【发布时间】:2014-01-03 22:03:47
【问题描述】:

目前我有两个功能:

  • 取素数来生成。
  • 第二个取素数的上限来生成。

它们是这样编码的(在 C++ 中):

prime_list erato_sieve(ul_it upper_limit)
{
    prime_list primes;
    if (upper_limit < 2)
        return primes;
    primes.push_back(2); // Initialize Array, and add 2 since its unique.

    for (uit i = 3; i <= upper_limit; i += 2) // Only count odd numbers
    {
        flag is_prime = true;
        for (uit j = 0; j < primes.size(); ++j)
        {
            if ((i % primes[j]) == 0)
            {
                is_prime = false;
                break;
            }
        }
        if (is_prime)
        {
            primes.push_back(i);
        }
    }
    return primes;
}

还有:

prime_list erato_sieve_num(ul_it MAX)
{
    prime_list primes;
    if (MAX == 0)
        return primes;
    primes.push_back(2); // Initialize Array, and add 2 since its unique.

    uit i = 3;
    while (primes.size() < MAX) // Only count odd numbers
    {
        flag is_prime = true;
        for (uit j = 0; j < primes.size(); ++j)
        {
            if ((i % primes[j]) == 0)
            {
                is_prime = false;
                break;
            }
        }
        if (is_prime)
        {
            primes.push_back(i);
        }
        ++i;
    }
    return primes;
}

其中定义了以下类型:

typedef bool flag;
typedef unsigned int uit;
typedef unsigned long int ul_it;
typedef unsigned long long int ull_it;
typedef long long int ll_it;
typedef long double ld;

typedef std::vector<ull_it> prime_list;

(如果您喜欢或不喜欢,请随意使用它们。查找替换会解决这个问题。我使用它们来使代码阅读更多我的想法)

我试图将它们变成一个重载的“函数”,但它们两个具有相似的论点。我担心它们之间的选择会归结为单独的类型,这会导致难以调试的问题。

我的第二个选择是创建一个类,但我很尴尬地说..,我以前从未使用过类。完全没有。所以我不知道该怎么做,而且文档有点……稀疏?

无论如何,如果有人愿意帮助我一点点,将不胜感激。文档总是很有帮助的,也欢迎任何指针。

编辑

正如我所说,我的部分选项是一个类。我完全确定如何制作一个将这两者结合起来的类。

【问题讨论】:

  • 如果您打算实施埃拉托色尼筛法,您所拥有的并没有做到。
  • 怎么不呢?它检查一个数字是否有以前找到的素数作为因子,如果没有,则将其添加到列表中。
  • 这不是埃拉托色尼筛的作用。它从 2 开始,一直到最大值的平方根,消除当前数字的倍数(跳过已经消除的倍数)。有一个不错的解释here

标签: c++ class overloading


【解决方案1】:

切勿为具有不同语义的函数赋予相同的名称。重载不是为此而设计的。这两个都是整数,如果你可以重载它们,你怎么知道erato_sieve(5)调用了哪个函数?

给他们不同的名字,例如erato_sieve_up_toerato_sieve_count

好吧,如果你仍然想让事情变得更糟(请不要),你可以重载它们(请不要),只是让他们期待不同类型的参数。例如,将一个整数包装到一个类中并传递该类,例如

class CountWrapper {
 public:
  CountWrapper(int n) { n_ = n; }
  operator int() { return n_; }
 private:
  int n_;
};

prime_list erato_sieve(const CountWrapper& MAX) {
  // function's body stays the same

然后这样称呼它

my_list = erato_sieve(CountWrapper(5));

但再次强调:请不要!

要对函数进行分组,您可以将它们定义为类的静态方法:

class PrimeGenerator {
 public:
  static prime_list EratoSieveUpTo(ul_it upper_limit) {
    // body
  }

  static prime_list EratoSieveAmount(ul_it MAX) {
    // body
  }
};

并调用类似的函数

list1 = PrimeGenerator::EratoSieveUpTo(5);
list2 = PrimeGenerator::EratoSieveAmount(10);

【讨论】:

  • +1 用于提供“解决方案”,但您会多么讨厌在生产代码中看到它?
  • 我尽量反对它。现在更加努力了。 :)
  • @Basic 我非常想说。在某些情况下,函数重载使代码更清晰。这是滥用行为,我同意。如果它让我的生活更轻松,我会考虑它。
  • 我还说过,如果重载不是解决方案,上课会很好,但谢谢。我想是这样的。我宁愿不写糟糕的代码。
  • 对不起,我误解了那部分。好吧,如果您想对函数进行“分组”,您可能希望将它们定义为某个类的静态方法,或者可能在命名空间内。我认为互联网上有很多例子。
【解决方案2】:

如果你想创建重载函数,你需要为每个函数定义一个不同的参数列表。在实际使用的参数类型相同的情况下,可以使用以下技巧:

typedef struct {} flag_type_1;
typedef struct {} flag_type_2;
...
typedef struct {} flag_type_n;

prime_list erato_sieve(ul_it boundary, flag_type_1) { ... }
prime_list erato_sieve(ul_it boundary, flag_type_2) { ... }
...
prime_list erato_sieve(ul_it boundary, flag_type_n) { ... }

这个想法是每个类型定义的结构都具有不同的类型签名。这会为每个函数重载创建完全不相关的参数列表。此外,由于类型是虚拟持有者,您不关心内容。这就是为什么您只需要在函数定义的参数列表中包含 type 即可。

我不久前从第 9 频道捡到了这个。非常巧妙的把戏。

【讨论】:

    【解决方案3】:

    这不是对您问题的直接回答,但会帮助回答您的问题。

    您似乎正在尝试实施埃拉托色尼筛法。该筛子的基本算法如下:

    1) Create a list of numbers from 2 to N (N is the maximum value you are looking for)
    2) Start at 2, and eliminate all other even numbers (they are non-prime) less than or equal to N
    3) Move to the next non-eliminated number.
    4) Eliminate all multiples of that number less than or equal to N.
    5) Repeat steps 3 and 4 until you reach the square root of N.
    

    将其翻译成 C++ 代码,它看起来像这样(未优化):

    std::vector<unsigned int> sieve_of_eratosthenes(unsigned int maximum)
    {
        std::vector<unsigned int> results; // this is your result set
        std::vector<bool> tests(maximum + 1); // this will be your "number list"
        // initialize the tests vector
        for (unsigned int i = 0; i <= maximum; ++i)
        {
            if (i == 0 || i == 1)
                tests[i] = false;
            else
                tests[i] = true;
        }
    
        // eliminate all even numbers but 2
        for (unsigned int i = 4; i <= maximum; i += 2)
        {
            tests[i] = false;
        }
    
        // start with 3 and go to root of maximum
        unsigned int i = 3;
        while (i * i <= maximum)
        {
            for (unsigned int j = i + i; j <= maximum; j += i)
            {
                tests[j] = false;
            }
    
            // find the next non-eliminated value
            unsigned int k = i + 1;
            while (!tests[k])
            {
                k++;
            }
            i = k;
        }
    
        // create your results list
        for (unsigned int j = 0; j <= maximum; ++j)
        {
            if (tests[j])
            {
                results.push_back(j);
            }
        }
    
        return results;
    }
    

    Example

    由于筛需要一个最大值,因此您不想为此算法提供多个素数。还有其他素数生成算法可以做到这一点,但埃拉托色尼筛却没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 2014-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-08
      相关资源
      最近更新 更多