讲师中心 微信公众号

工具推荐

视频效率加速
updream

一键生成高质量推广成片

AniShort
AniShort

AI短剧协同制作平台

立刻MV
立刻MV

低成本歌曲 MV、视频生成

Seko
Seko

AI短剧一键生成成片

C++STL算法accumulate和count使用方法

老晨吖_4067

老晨吖_4067

发布时间:2025-09-14 08:24:01

|

639人浏览过

|

来源于php中文网

原创

std::accumulate用于序列的累加或自定义规约操作,std::count用于统计特定值出现次数。前者支持自定义二元操作实现求和、乘积、字符串连接等复杂聚合,后者可结合count_if、map等实现条件计数与频率统计,二者均提升代码简洁性与可读性。

c++stl算法accumulate和count使用方法

std::accumulate
算法主要用于对一个范围内的元素进行累加或更广义的“规约”操作,将它们合并成一个单一的值,而
std::count
则专注于统计某个特定值在给定范围内的出现次数。两者都是C++标准库(STL)中非常实用的工具,能有效简化代码,提升可读性。

std::accumulate
和
std::count
是STL中两个非常基础但功能强大的算法,它们都位于
<numeric>
和
<algorithm>
头文件中(通常
accumulate
在
<numeric>
,
count
在
<algorithm>
)。理解它们的使用场景和机制,对于写出更简洁、更符合C++惯用法的代码至关重要。

std::accumulate
:从聚合到自定义规约

std::accumulate
的核心思想是将一个序列中的所有元素通过一个二元操作(binary operation)“累积”成一个结果。最常见的例子就是求和。

它的基本形式是:

OutputIt accumulate(InputIt first, InputIt last, T init);
或者带自定义操作符的:
OutputIt accumulate(InputIt first, InputIt last, T init, BinaryOperation op);

这里,

first
和
last
定义了要操作的元素范围。
init
是累加的初始值,这个参数非常关键,因为它不仅提供了累加的起点,还决定了最终结果的类型。
op
是一个可选的二元操作符,默认为
std::plus<T>()
(即加法)。

立即学习“C++免费学习笔记(深入)”;

示例:求和

#include <iostream>
#include <vector>
#include <numeric> // For std::accumulate

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // 求和
    int sum = std::accumulate(numbers.begin(), numbers.end(), 0); // 初始值为0
    std::cout << "Sum: " << sum << std::endl; // 输出:Sum: 15

    // 注意init值对类型的影响
    std::vector<double> prices = {10.5, 20.3, 5.2};
    double total_price = std::accumulate(prices.begin(), prices.end(), 0.0); // 初始值为0.0,结果为double
    std::cout << "Total Price: " << total_price << std::endl; // 输出:Total Price: 36

    return 0;
}

示例:自定义操作(乘积)

#include <iostream>
#include <vector>
#include <numeric>
#include <functional> // For std::multiplies

int main() {
    std::vector<int> nums = {1, 2, 3, 4};

    // 求乘积,初始值为1
    int product = std::accumulate(nums.begin(), nums.end(), 1, std::multiplies<int>());
    std::cout << "Product: " << product << std::endl; // 输出:Product: 24

    // 使用lambda表达式连接字符串
    std::vector<std::string> words = {"Hello", " ", "World", "!"};
    std::string sentence = std::accumulate(words.begin(), words.end(), std::string(""),
                                           [](const std::string& a, const std::string& b) {
                                               return a + b;
                                           });
    std::cout << "Sentence: " << sentence << std::endl; // 输出:Sentence: Hello World!

    return 0;
}

std::count
:精准统计元素出现次数

std::count
算法用于计算一个特定值在给定范围内出现的次数。它非常直观且易于使用。

它的基本形式是:

SizeT count(InputIt first, InputIt last, const T& value);

first
和
last
定义了要搜索的元素范围。
value
是要计数的特定值。

示例:计数

#include <iostream>
#include <vector>
#include <algorithm> // For std::count

int main() {
    std::vector<int> scores = {85, 90, 78, 90, 95, 88, 90};

    // 统计90出现的次数
    int count_90 = std::count(scores.begin(), scores.end(), 90);
    std::cout << "Number of 90s: " << count_90 << std::endl; // 输出:Number of 90s: 3

    std::vector<char> letters = {'a', 'b', 'c', 'a', 'd', 'a'};
    int count_a = std::count(letters.begin(), letters.end(), 'a');
    std::cout << "Number of 'a's: " << count_a << std::endl; // 输出:Number of 'a's: 3

    return 0;
}

何时选择
std::accumulate
而非手动循环求和?

这个问题我其实经常思考,毕竟一个简单的

for
循环也能完成求和。但我的观点是,
std::accumulate
在很多情况下提供了更清晰、更“意图明确”的代码。

Word文档工具V102(专业版)
Word文档工具V102(专业版)

Word文档处理增强版本,支持高级格式化、样式管理、修订追踪与协同编辑。

下载

首先,它体现了STL的“算法与容器分离”哲学。当你看到

std::accumulate
时,你立刻知道这里正在进行一个聚合操作,而不需要去解析循环体内部的逻辑。这对于代码阅读者来说,是一种认知上的捷径,尤其是在处理大型或复杂的代码库时。一个手动循环可能包含额外的副作用或更复杂的条件判断,而
accumulate
则将焦点纯粹地放在了“规约”这一行为上。

其次,

accumulate
能有效避免一些常见的循环错误,比如初始化值错误、循环边界错误(off-by-one errors)。它将这些细节封装起来,让你只关注操作本身。

再者,当聚合逻辑变得复杂时,

accumulate
配合lambda表达式的优势就更明显了。比如,求一个自定义权重的和,或者连接不同类型的对象,手动循环可能需要更多行代码和临时变量,而
accumulate
可以以一种更函数式、更紧凑的方式表达。当然,对于非常简单的求和,一个基于范围的
for
循环(
for (int x : numbers) sum += x;
)也同样简洁明了,甚至可能在某些极端情况下更易读。所以,选择哪个,更多是关于代码风格、团队规范以及对特定“规约”行为的强调。我个人倾向于在聚合操作清晰且不涉及复杂副作用时,优先使用
accumulate
。

如何利用
std::accumulate
进行更复杂的聚合操作?

std::accumulate
的真正威力在于它的第四个参数:
BinaryOperation op
。这个参数允许你定义任何你想要的二元操作,从而实现远超简单求和的复杂聚合。

  1. 连接异构数据或自定义对象: 假设你有一个学生对象列表,每个学生有姓名和分数,你想把所有学生的名字连接起来。

    #include <iostream>
    #include <vector>
    #include <numeric>
    #include <string>
    
    struct Student {
        std::string name;
        int score;
    };
    
    int main() {
        std::vector<Student> students = {
            {"Alice", 90}, {"Bob", 85}, {"Charlie", 92}
        };
    
        // 连接所有学生的名字
        std::string all_names = std::accumulate(students.begin(), students.end(), std::string("Students: "),
                                                [](const std::string& current_names, const Student& s) {
                                                    return current_names + s.name + " ";
                                                });
        std::cout << all_names << std::endl; // 输出:Students: Alice Bob Charlie
    
        // 计算总分
        int total_score = std::accumulate(students.begin(), students.end(), 0,
                                          [](int current_sum, const Student& s) {
                                              return current_sum + s.score;
                                          });
        std::cout << "Total Score: " << total_score << std::endl; // 输出:Total Score: 267
    
        return 0;
    }
  2. 计算加权平均值: 如果你有一系列数据点,每个点有其值和对应的权重,你可以用

    accumulate
    来计算加权和,然后除以总权重。

    #include <iostream>
    #include <vector>
    #include <numeric>
    #include <utility> // For std::pair
    
    int main() {
        std::vector<std::pair<double, double>> data_points = {
            {10.0, 0.5}, // value, weight
            {20.0, 0.3},
            {5.0,  0.2}
        };
    
        // 计算加权和
        double weighted_sum = std::accumulate(data_points.begin(), data_points.end(), 0.0,
                                              [](double current_sum, const std::pair<double, double>& p) {
                                                  return current_sum + (p.first * p.second);
                                              });
    
        // 计算总权重
        double total_weight = std::accumulate(data_points.begin(), data_points.end(), 0.0,
                                              [](double current_weight, const std::pair<double, double>& p) {
                                                  return current_weight + p.second;
                                              });
    
        if (total_weight > 0) {
            double weighted_average = weighted_sum / total_weight;
            std::cout << "Weighted Average: " << weighted_average << std::endl; // 输出:Weighted Average: 12.5
        } else {
            std::cout << "Cannot calculate weighted average: total weight is zero." << std::endl;
        }
    
        return 0;
    }

这些例子展示了

accumulate
的强大之处:它不仅仅是求和,而是一个通用的“折叠”(fold)操作,能够将一个序列规约为任何你想要的单一结果,只要你能定义好那个二元操作。

除了
std::count
,还有哪些STL算法能帮助我统计数据?

当我们谈到数据统计,

std::count
确实是基础且直接的。但实际开发中,我们往往需要更灵活、更复杂的统计方式。STL提供了一些其他算法,可以作为
std::count
的补充或替代,以满足不同的统计需求。

  1. std::count_if
    :条件计数 这是
    std::count
    的升级版,它不是计数某个特定值,而是计数满足某个特定条件的元素。这个条件由一个谓词(predicate,通常是lambda表达式或函数对象)来定义。这在需要根据更复杂的逻辑来统计时非常有用。

    #include <iostream>
    #include <vector>
    #include <algorithm> // For std::count_if
    
    int main() {
        std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
        // 统计偶数的个数
        int even_count = std::count_if(numbers.begin(), numbers.end(),
                                       [](int n) { return n % 2 == 0; });
        std::cout << "Even numbers: " << even_count << std::endl; // 输出:Even numbers: 5
    
        // 统计大于5的数字个数
        int greater_than_5_count = std::count_if(numbers.begin(), numbers.end(),
                                                 [](int n) { return n > 5; });
        std::cout << "Numbers greater than 5: " << greater_than_5_count << std::endl; // 输出:Numbers greater than 5: 5
    
        return 0;
    }

    count_if
    无疑是处理“有多少个满足X条件的元素”这类问题的首选。

  2. std::for_each
    (配合外部计数器): 虽然
    std::for_each
    本身不是一个统计算法,但它可以结合一个外部变量来实现复杂的统计。当你需要在遍历过程中执行某些操作的同时进行计数,或者计数逻辑非常复杂以至于无法用一个简单的谓词表达时,这种方式就派上用场了。

    #include <iostream>
    #include <vector>
    #include <algorithm> // For std::for_each
    
    int main() {
        std::vector<std::string> words = {"apple", "banana", "cat", "dog", "elephant"};
        int words_with_a = 0;
    
        // 统计包含字母'a'的单词,并打印它们
        std::for_each(words.begin(), words.end(),
                      [&](const std::string& word) { // 注意这里需要捕获words_with_a
                          if (word.find('a') != std::string::npos) {
                              words_with_a++;
                              std::cout << "Found word with 'a': " << word << std::endl;
                          }
                      });
        std::cout << "Total words with 'a': " << words_with_a << std::endl; // 输出:Total words with 'a': 3
    
        return 0;
    }

    这种方式的优点是可以在统计的同时执行其他操作,但缺点是需要一个可变的外部状态,不如

    count_if
    纯粹。

  3. 结合容器(如

    std::map
    或
    std::unordered_map
    )进行频率统计:
    如果你的目标是统计所有不同元素的出现频率,而不是某个特定值的频率,那么使用
    std::map
    或
    std::unordered_map
    会更高效和直观。你可以遍历一次容器,将元素作为键,出现次数作为值。

    #include <iostream>
    #include <vector>
    #include <map> // For std::map
    #include <string>
    
    int main() {
        std::vector<std::string> fruits = {"apple", "banana", "apple", "orange", "banana", "apple"};
        std::map<std::string, int> frequency_map;
    
        for (const std::string& fruit : fruits) {
            frequency_map[fruit]++;
        }
    
        std::cout << "Fruit Frequencies:" << std::endl;
        for (const auto& pair : frequency_map) {
            std::cout << pair.first << ": " << pair.second << std::endl;
        }
        // 输出:
        // Fruit Frequencies:
        // apple: 3
        // banana: 2
        // orange: 1
    
        return 0;
    }

    这种方法在需要全面了解数据分布时是无价的,它提供了一个“全景”的统计视图,而不仅仅是单一元素的计数。

总的来说,STL提供了一个工具箱,我们应该根据具体的统计需求来选择最合适的工具。

count
用于精确查找,
count_if
用于条件查找,而结合
for_each
或
map
则能处理更复杂、更全面的统计场景。理解它们的适用范围,能让我们在解决问题时更加游刃有余。

热门AI工具

更多
UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

SoundView
SoundView Hot

SoundView是一款面向跨境电商的视频翻译、配音和本地化 AI 创作平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3928

2023.11.20

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2458

2023.09.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1938

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

3184

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6384

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

6569

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

8094

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

12574

2024.04.29

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

40

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go-Zero HTTP服务开发指南
Go-Zero HTTP服务开发指南

共0课时 | 0人学习

Go-Zero goctl安装与使用手册
Go-Zero goctl安装与使用手册

共0课时 | 0人学习

Go-Zero框架快速开始指南
Go-Zero框架快速开始指南

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn