一个问题。我的代码有什么问题?

时间:2011-08-24 21:13:11

标签: c++

问题的文本:

输入:输入流包含一组整数Ai(0≤Ai≤1018)。数字由任意数量的空格和换行符分隔。输入流的大小不超过256 KB。

输出:对于从最后一个到第一个的每个数字Ai,您应输出其平方根。每个平方根应打印在一个单独的行中,小数点后至少有四位数。

示例
输入:

 1427  0   

876652098643267843 5276538

输出:

2297.0716
936297014.1164
0.0000
37.7757

时限:2.0秒
内存限制:16 MB

C和C ++程序由32位Microsoft Visual C ++ 2010在服务器上编译。直到2010年8月3日,才使用了英特尔C ++编译器7.0。您可以在此页面上下载Microsoft Visual Studio 2010 Express的免费副本。使用以下参数调用编译器:

// C
cl /TC /MT /EHsc /O2 /W3 /Za /D "_CRT_SECURE_NO_WARNINGS" 
   /D "_CRT_SECURE_NO_DEPRECATE" /D "ONLINE_JUDGE"

// C++
cl /TP /MT /EHsc /O2 /W3 /Za /D "_CRT_SECURE_NO_WARNINGS" 
   /D "_CRT_SECURE_NO_DEPRECATE" /D "ONLINE_JUDGE"

这是我在gcc 4.3中解决这个问题的方法:

#include <iostream>
#include <list>
#include <string>
#include <sstream>
#include <math.h>
#include <algorithm>
#include <iomanip>
#include <stdio.h>

void sqrt_f(double n)
{
    printf ( "%.4f\n", sqrt( static_cast<double>( n ) ) );
}

int main()
{
    std::list<double> numbers;
    std::string sInput;
    getline( std::cin, sInput );
    std::istringstream parse( sInput );
    double tmp;
    while ( parse >> tmp )
        numbers.push_front( tmp );
    std::for_each(numbers.begin(), numbers.end(), sqrt_f);
    return 0;
}

但判断结果是:错误答案(test1)

有什么问题?

1 个答案:

答案 0 :(得分:3)

警告:当我写这篇文章时,问题仍然存在于代码审查网站上,所以它主要是作为代码审查编写的。主要应用于SO(修复输入问题)的部分几乎没有提及。

目前,我将假设你已经解决了问题@Jeff Mercado指出要获得类似这样的代码:

#include <iostream>
#include <list>
#include <string>
#include <sstream>
#include <math.h>
#include <algorithm>
#include <iomanip>
#include <stdio.h>

void sqrt_f(double n)
{
    printf ( "%.4f\n", sqrt( static_cast<double>( n ) ) );
}

int main()
{
    std::list<double> numbers;
    std::string sInput;
    while (getline( std::cin, sInput )) {  // added `while` to process all input
        std::istringstream parse( sInput );
        double tmp;
        while ( parse >> tmp )
            numbers.push_front( tmp );
    }
    std::for_each(numbers.begin(), numbers.end(), sqrt_f);
    return 0;
}

然后,我将忽略您实际提出的问题(关于正确性),并且只是检查(重写)代码,假设它符合要求。

void sqrt_f(double n)
{
    printf ( "%.4f\n", sqrt( static_cast<double>( n ) ) );
}

我在这里看到三件我不太喜欢的事情:

  1. 在C ++中使用printf。通常喜欢iostream(虽然我们会看到,在这种情况下,它们更加冗长。)
  2. static_cast似乎完全无关(n已经是双倍的。)
  3. 关注点分离不佳。您将计算与I / O结合起来。

    std::list<double> numbers;

  4. 我认为没有太多理由在这里使用std::list。你只是在一端插入,并且从头到尾遍历。使用std::list的主要原因是您要在列表中间的某处插入/删除。即使这样,它也不一定是最好的选择,但是当你只需要插入一端时,几乎肯定是错误的选择。

    std::string sInput;
    while (getline( std::cin, sInput )) {  // added `while` to process all input
        double tmp;
        while ( parse >> tmp )
            numbers.push_front( tmp );
    }
    

    我认为没有任何真正的理由在这里使用std::getlinegetline主要用于输入具有面向行的格式,但这里只是由一些任意数量的空格分隔的双精度流。为此,您似乎增加了额外的复杂性而没有获得太多功能作为回报。

    我对循环while (parse >> tmp)也不太兴奋。它肯定比某些替代方案更好,但我宁愿使用std::copy(在这种情况下)std::istream_iterator<double>将值复制到集合中。

    我对你如何使用这个系列并不是特别兴奋。首先,您使用push_front来撤销订单。至少对我而言,如果您按照原始顺序将数字添加到集合中,然后向后浏览集合,似乎更容易理解。

        std::for_each(numbers.begin(), numbers.end(), sqrt_f);
    

    ......这是导致sqrt_f责任分离不良的罪魁祸首。自从STL来到C ++以来已经有15年了,在那个时候我怀疑我已经看到了std::for_each的多达六种好用途。它可以有用,但通常应该是你最后选择的算法,当你找不到其他更好的东西时。

    我认为如果我这样做,我会使用std::vector进行存储(我们只需要在一端添加项目,这符合vector提供的内容)。我使用带有std::copy的{​​{1}}将数据直接从std :: cin复制到该向量中。然后,我将std::istream_iterator<double>与向量上的一对反向迭代器一起使用,并为输出使用std::transform。由于固定标志和精度都是“粘性”,我们可以通过在调用ostream_iterator之前设置一次格式来获得正确格式的所有输出:

    std::transform