代码之家  ›  专栏  ›  技术社区  ›  xsl Fredrik Hedblad

C++ STL列表计算平均值

  •  2
  • xsl Fredrik Hedblad  · 技术社区  · 15 年前

    我必须改正一些C++/STL代码。不幸的是,我只有很少的C++经验,对STL一无所知。尽管如此,我还是完成了大部分工作,但下面的功能仍然给我带来问题:

    C++源程序:

    double MyClass::CalculateAvg(const std::list<double> &list)
    {
        double avg = 0;
        std::list<int>::iterator it;
        for(it = list->begin(); it != list->end(); it++) avg += *it;
        avg /= list->size();
    }
    

    C++标题:

    static double CalculateAvg(const std::list<int> &list);
    

    它最有可能是从一个列表中计算出平均值,但它会遇到很多错误。我试图在网上搜索解决方案,但什么也找不到。如果有人能帮助我,我会很高兴的。

    更新: 感谢您的快速回复。公认的答案解决了我所有的问题。

    9 回复  |  直到 15 年前
        1
  •  13
  •   PierreBdR    15 年前

    所以,第一个错误是:

    std::list<int>::iterator it;
    

    在整数列表上定义一个迭代器,并使用它来迭代一个双精度列表。此外,迭代器只能用于非常量列表。你需要一个常量运算符。你应该写:

    std::list<double>::const_iterator it;
    

    最后,您忘记返回值。

    编辑: 我没看到,但是你把列表作为参考传递,但是把它作为指针使用。所以把所有的 list-> 通过 list.

        2
  •  32
  •   Peter Alexander    15 年前

    很少的事情:

    1. 你什么都不退货。(添加) return avg; )
    2. 这个 -> 运算符用于指向对象的指针。您有一个对列表的引用,因此使用 list.begin() 而不是 list->begin() (其他成员函数相同)
    3. 迭代器应该是 const_iterator 不是 iterator .

    在任何情况下,您只需执行以下操作:

    return std::accumulate(list.begin(), list.end(), 0.0) / list.size();

    可选检查 list.size() == 0 如果这在您的用例中是可能的。

        3
  •  4
  •   Maurits Rijk    15 年前

    如何使用 accumulate ?

        4
  •  2
  •   Tom    15 年前

    除了@pierrebdr answer, 还应检查list->size()是否大于0,

    就在这里之前

      avg /= list.size();
    

    添加

     if (list.size()>0) 
        //avg code here.
    

    或将列表作为参数接收的文档不应为空。

       assert(list.size()>0)
    
        5
  •  2
  •   Jerry Coffin    15 年前

    与其进行编辑以确保迭代器引用相同类型的列表,不如将代码编写为一种通用算法,迭代器类型作为模板参数。

    我也会注意到 std::list ,两个原始代码 大多数已发布的答案都有一个相当严重的效率问题:给定一个典型的列表实现,它们对列表进行一次迭代,以将值相加,然后再进行一次迭代,以计算元素的数量。理论上, list.size() 能够 在不变的时间内运行而不迭代元素,但事实上很少这样(对于 list::size() list::splice 但不能同时用于两者)。

    我会写一些代码,比如:

    template <class fwdit> 
    typename fwdit::value_type arithmetic_mean(fwdit begin, fwdit end) { 
    
        typedef typename fwdit::value_type res_type;
    
        res_type sum = res_type();
        size_t count = 0;
    
        for (fwdit pos = begin; pos!= end; ++pos) { 
            sum += *pos;
            ++count;
        }
        return sum/count;
    }
    

    这是通用的,因此当您意识到这一点时,它将继续工作(不变)。 STD::列表 是个糟糕的选择,你会过得更好的 std::vector . 同样,如果您想要一些int的算术平均值而不是double的算术平均值,它也可以处理这个问题(同样,不需要更改代码)。第三,即使(如上建议)您的库实现了 st::list::size() 碰巧是线性的,它仍然只遍历列表一次,所以它的速度可能是原始代码(工作版本)的两倍左右。

    当然,缓存会影响这一点——当您平均一个小列表时,第一次遍历会将整个列表拉入缓存,因此第二次遍历通常会更快(因此消除第二次遍历不会节省那么多时间)。

        6
  •  1
  •   Ron Warholic    15 年前

    你通过了 std::list<double> 但你创造了 std::list<int> 迭代器?你的原型需要 std::list<int> 也。

        7
  •  1
  •   batbrat    15 年前

    正如Maurits Rijk所说,您还没有返回avg。此外,编译时还使用了哪些错误?

        8
  •  1
  •   Derrick Turk    15 年前

    自从 list 是引用而不是指针,您不需要 -> 解引用运算符,而不仅仅是 . 运算符,即 it = list.begin() 等等。

    另外,正如其他人所指出的,列表及其迭代器的模板类型参数都需要匹配:要么 <int> <double> . 看起来函数最初是为接受 double S.

        9
  •  1
  •   Hassan Syed    15 年前

    作为你自己的练习。一旦你成功了,你应该把它变成 for_each . 从长远来看更容易理解。

    --编辑——

    Accumulate 更好,因为它是用于二进制数字运算。

    推荐文章