0

0

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

P粉602998670

P粉602998670

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

|

599人浏览过

|

来源于php中文网

原创

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

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

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

std::accumulate
std::count
是STL中两个非常基础但功能强大的算法,它们都位于
头文件中(通常
accumulate
count
)。理解它们的使用场景和机制,对于写出更简洁、更符合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()
(即加法)。

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

示例:求和

#include 
#include 
#include  // For std::accumulate

int main() {
    std::vector 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 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 
#include 
#include 
#include  // For std::multiplies

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

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

    // 使用lambda表达式连接字符串
    std::vector 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 
#include 
#include  // For std::count

int main() {
    std::vector 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 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
在很多情况下提供了更清晰、更“意图明确”的代码。

95Shop仿醉品商城
95Shop仿醉品商城

95Shop可以免费下载使用,是一款仿醉品商城网店系统,内置SEO优化,具有模块丰富、管理简洁直观,操作易用等特点,系统功能完整,运行速度较快,采用ASP.NET(C#)技术开发,配合SQL Serve2000数据库存储数据,运行环境为微软ASP.NET 2.0。95Shop官方网站定期开发新功能和维护升级。可以放心使用! 安装运行方法 1、下载软件压缩包; 2、将下载的软件压缩包解压缩,得到we

下载

首先,它体现了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 
    #include 
    #include 
    #include 
    
    struct Student {
        std::string name;
        int score;
    };
    
    int main() {
        std::vector 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 
    #include 
    #include 
    #include  // For std::pair
    
    int main() {
        std::vector> 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& 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& 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 
    #include 
    #include  // For std::count_if
    
    int main() {
        std::vector 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 
    #include 
    #include  // For std::for_each
    
    int main() {
        std::vector 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 
    #include 
    #include  // For std::map
    #include 
    
    int main() {
        std::vector fruits = {"apple", "banana", "apple", "orange", "banana", "apple"};
        std::map 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
则能处理更复杂、更全面的统计场景。理解它们的适用范围,能让我们在解决问题时更加游刃有余。

相关专题

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

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

197

2023.11.20

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

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

525

2023.09.20

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

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

258

2023.08.03

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

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

209

2023.09.04

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

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

1468

2023.10.24

字符串介绍
字符串介绍

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

620

2023.11.24

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

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

550

2024.03.22

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

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

566

2024.04.29

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.21

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号