生成康威看起来并说出'数字

时间:2014-08-15 20:39:28

标签: c++ c++11

我受到启发,编写了一个小型的C ++ 11程序,可以生成所谓的Conway数字,或者“外观和说”数字。基本上,给定第n个术语,例如11112,接下来只是前一个词的发音;在我们的案例4112中,因为有4个1并且只有一个2.另一个例子:'13'到'1113'。

以下是程序的完整性源代码(如果没有使用MS Visual Studio进行编译,则省略stdafx.h包含):

#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>

using namespace std;

void print_usage(){

    cout << endl << "Conway Number Generator";
    cout << endl << "Arguments: initializer followed by nth term to be printed" << endl;
}

string say(string s){

    // Returns string said phonetically
    // e.g. '111' becomes '31'

    unsigned int sz = s.size();

    if (sz == 1){
        s.insert(0, "1");
    }
    else{
        s.insert(0, to_string(sz));
        s.erase(2, sz-1);
    }
    return s;
}

string get_next(string x){

    // Returns next term in Conway sequence

    unsigned prev_point = 0;
    vector<string> grp;
    string tmp;
    tmp.resize(x.size());

    // Organize sequence in group of identical consecutive characters

    for (unsigned int i = 0; i < x.size(); ++i){

        if (i != x.size() - 1){

            if (x.at(i) != x.at(i + 1)){
                tmp.assign(x, prev_point, i - prev_point);
                grp.push_back(tmp);
                prev_point = i + 1;
                tmp.clear();
            }
        }
        else if (i != 0){

            if (x.at(i) != x.at(i - 1)){
                tmp = x.at(i);
                grp.push_back(tmp);
                tmp.clear();
            }
        }
    }

    // Phonetically say each group

    // Could use a lambda: transform(begin(grp), end(grp), begin(said_grp)[=](string s){return say(s);});
    // if I create a new vector<string> said_grp to copy in
    // That didn't help the runtime error

    for (auto& i : grp)
        i = say(i);

    // Join each vector<string> entry into a single string

    string next_seq;
    next_seq = accumulate(begin(grp), end(grp), string(""));
    return next_seq;
}

string conway(string init, int n){

    // Print out nth Conway term
    // starting sequence at init

    for (int i = 1; i <= n; ++i)
        init = get_next(init);
    return init;
}

int main(int argc, const char* argv[]){

    if (argc < 3){
        print_usage();
        return 0;
    }
    cout << endl << "Conway number: " << conway(argv[1], stoi(argv[2])) << endl;
    return 0;
}

一般方法:

  1. 接受两个参数:Conway序列的第一个术语,整数n选择计算该序列的第n个术语。
  2. 函数conway(...)循环执行get_next()到初始字符串n次。
  3. 函数say()'发出'数字。
  4. get_next()通过将整个数字拆分为连续的相同数字来起作用;然后通过say()转换每个。
  5. 我遇到的问题是std::out_of_range函数的return语句中的错误say()。但是,我可以回想一下单独使用各种输入测试say(),并且它从未引起异常。我必须以某种方式错误地使用它。正如我在代码注释中注意到的那样,我尝试使用STL转换而不是带有lambda的for循环,同样的错误。


    注意:对于对Conway序列感兴趣的人,请参阅Conway的原始论文。他们承认了一些有趣的属性,并且它们似乎产生了一个被称为康威常数的常数,它被证明是代数的。

2 个答案:

答案 0 :(得分:2)

正如我在评论中提到的,这是使用调试器解决的完美问题。 80多个(非常聪明)的人看过你的代码,没有人能够通过观察完全解决它(虽然@hlt得到了很多)。经过一些调试后,我想我已经完成了其余的工作。让我们来看看这些作品。

就像hlt所说的那样,auto&中基于范围的循环需要get_next(),否则你永远不会真正改变grp并继续获得原始数字。有关详细信息,请参阅this question

另外,多亏了hlt,你有一条关于零长度字符串输入的缺失逻辑。但是,get_next()函数中还有一个缺失的部分。以输入./conway 111 2为例。数字111实际上永远不会被放入grp,因为所有字符都相同,因此if (x.at(i) != x.at(i + 1))if (x.at(i) != x.at(i - 1))都不会评估为真;因此,你会得到一个空字符串作为结果。缺少的部分包含在下面。

for (unsigned int i = 0; i < x.size(); ++i){

    if (i != x.size() - 1){

        if (x.at(i) != x.at(i + 1)){
            tmp.assign(x, prev_point, i+1 - prev_point);
            grp.push_back(tmp);
            prev_point = i + 1;
            tmp.clear();
        }
    }
    else if (i != 0){

        if (x.at(i) != x.at(i - 1)){
            tmp = x.at(i);
            grp.push_back(tmp);
            tmp.clear();
        }
        else
        {
            tmp.assign(x, prev_point, i+1 - prev_point);
            grp.push_back(tmp);
            tmp.clear();
        }
    }

我在上面的评论中提到的最后一个问题,并包含在此处的代码中。要将正确长度的子字符串分配到tmp,您需要i+1-prev_point而不是i-prev_point

我说开始我认为我已经抓住了其余的错误,但这可能不是真的。我建议用大量具有不同特征的数字(例如,1,12121212,0000,1222,2221等)编写一些测试及其预期结果。如果它们中的任何一个产生了意想不到的结果,那么就该回到调试器了。

答案 1 :(得分:0)

我查看了您的源代码,并注意到您的函数get_next()可以简化。我已将其替换为以下版本:

string get_next(const string & inStr) {
    string result;
    int len = inStr.size();
    int count = 0;
    // Loop over non-duplicates
    for (int i = 0; i < len; i += count) {
        // Calculate total number of duplicates for inStr[i]:
        for (count = 0; i+count < len; count++) {
            if (inStr[i+count] != inStr[i]) {
                break;
            }
        }
        // Append count + non-duplicate (count and say)
        result += to_string(count) + inStr[i];
    }
    return result;
}

当我以“1”作为初始字符串并且5作为n运行新代码时,我得到以下输出结果:

康威号码:312211

这是正确的:1 - &gt; 11 - &gt; 21 - &gt; 1211 - &gt; 111221 - &gt; 312211

无需调试。希望这会有所帮助。