欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

探索一道面试题的多个解法:C++11 求从 1 到 10 的阶乘相加的结果

程序员文章站 2024-03-15 17:11:06
...

一、引言

最近,有个朋友出去面试(才毕业不到一年),里面有一道很简单的笔试题:

请你编写代码,求 1 到 10 的阶乘相加的结果

这是一道非常简单的题目,我们稍微动一动头脑,就能拿出下面的代码:

#include <iostream>
#include <cstdlib>

int factorial(int n)
{
    if (n == 1) return 1;
    return n * factorial(n - 1);
}

int main()
{
    int result = 0;
    for (int i = 1; i <= 10; ++i)
        result += factorial(i);
    std::cout << result << std::endl;
    system("pause");
    return 0;
}

上述代码中,我们首先编写了一个 factorial 函数递归实现对于某个确定数的阶乘计算,然后遍历 1 到 10,得到这十个数的阶乘数之和。

这个方法是很简单,或许就是最优解了。

但是!

人生在于不停的折腾,让我们来看看,如何(凑不要脸,不知道有什么意义 T_T)来使用 C++11 的库函数来实现这个算法。

二、工具一:std::multiplies

这个函数是我在阅读《C++并发编程实战》的时候看到的。

让我们看看标准库里面的解释cppreference

定义于头文件 <functional>
template< class T>
struct multiplies;
template < class T = void>
struct multiplies;
进行乘法的函数对象。等效地在两个 T 类型实例上调用 operator*

根据上述这段话,我们可以很清晰的看到,std::multiplies 就是实现无视类型的 两个 任何类对象实例的乘法的 函数对象

因此,我们可以使用这个函数来进行乘法计算(这一点契合了标准库的算法设计,我下一节会讲到)。

三、工具二:std::accumulate

这个函数也是我在看《C++并发编程实战》的时候看到的 T_T。

那么这个函数有什么强大的地方呢cppreference

定义于 <numeric>
template < class InputIt, class T>
T accumulate( InputIt first, InputIt last, T init);
template < class InputIt, class T, class BinaryOperation>
T accumulate( InputIt first, InputIt last, T init, BinaryOperation op );
计算给定值 init 与给定范围 [first, last) 中元素的和。第一版用 operator+ 求和元素,第二版本使用二元函数 op(有没有想到刚提到的哪个函数呀 ^_^)

仔细阅读了 std::accumulate 的介绍之后,我们发现,我们可以完成指定范围的数的和。

那么,要完成阶乘相加,我们必然要有乘法计算,这个怎么办呢?

很简单,我们只需要将刚才提到的 std::multiplies 与 std::accumulate 结合起来就可以啦!

现在,两个工具都已经介绍完毕,让我们开始编码吧!

四、我们就是要用牛刀杀鸡学牛刀是怎么用的 T_T

略加思考,我写下了如下的代码:

#include <iostream>
#include <cstdlib>
#include <vector>
#include <functional>
#include <numeric>

int main()
{
    int result = 0;
    std::vector<int> number = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    for (int i = 0; i < number.size(); ++i) {
        int temp = std::accumulate(number.begin(), number.begin() + i + 1, 1, std::multiplies<int>());
        std::cout << number[i] << "'s factorial is " << temp << std::endl;
        result += temp;
    }
    std::cout << result << std::endl;
    system("pause");
    return 0;
}

在这段代码中:

我们首先定义了一个 number 数组,它是我们用 std::accumulate 这个函数的前两个迭代器标记范围时需要的依靠;

然后,我们在 for 循环中,计算一次(也就是一个数)的阶乘之和,乘法使用了 std::multiplies 函数,请注意它的用法;

最后,我们通过 for 循环的遍历,累加,即可得到结果。

当当当!

我们使用了看似更加复杂的代码完成了这个需求~~~

好像有点吃不了撑的 T_T

五、总结

对于这么简单的一道题,却要探索那么“复杂”的解法,其根源在于,去熟悉 C++ 标准库中强大的工具的用法。

从用法中一窥其设计的理念,从杀鸡中得到牛刀的快感。

编程在于乐趣,
To be Stronger:)