【问题标题】:Sum the elements from a vector using a nested for loop使用嵌套的 for 循环对向量中的元素求和
【发布时间】:2022-01-23 03:03:15
【问题描述】:

我正在尝试对向量的值求和,但我遇到了问题。

向量的大小是 20 个元素,我正在尝试从当前位置计算 5 个元素的总和。

类似于:将 1 到 5、2 到 6、3 到 7 等元素相加。

我认为我可以做一个 for 嵌套循环,如下所示:

for (int a = 0; a < numVec.size(); a++) {
    for (int b = a; b < numVec.size(); b++)
    {
        if (aux < 5) {
            cout << "B: " << b << endl;
            sum += numVec[b].num;
        }

        if (aux > 4) {
            aux = 0;
            sumAux= sum;
            sum= 0;
            break;
        }

        aux++;
    }
    cout << "Sum: " << sumAux<< endl;
}

但是当我获得第 15 位时,我遇到了一些问题,一切都出错了,我不知道为什么。

如果你能帮助我,我非常感谢你。

【问题讨论】:

  • 如果列表中只有 20 个元素,那么任何超过 15 个的元素都将少于 5 个元素可供选择。
  • aux = 5 时,您总是break 不在循环中,所以为什么不使用类似for (int a = 0; a &lt; numVec.size() - 5; a++) { for (int b = 0; b &lt; 5; b++) { sum += numVec[a + b].num;.... 的循环
  • @JohnnyMopp 嗯,没错。但是如何告诉它对剩余的数字求和呢?问题是我认为的“aux > 4”,但我不知道用什么替换它。
  • 但是你放置 for 循环总和值的方式不是我应该得到的数字。
  • 提示。在 O(N) 中进行。将前 5 个相加。称其为 S(1, 5)。那么 S(2, 6) 就是 S(1, 5) - 元素 1 + 元素 6。不需要内部循环,处理向量的结尾更简单。更简单的方法 = 更少的错误。

标签: c++


【解决方案1】:

如果您在开始编写代码之前考虑更长的时间,它将对您有很大帮助。也许你可以拿一张纸写下来。

那么,如果你选择长而清晰的变量名,它会对你有很大帮助。

所以,让我们做一张照片。我们将一些测试值及其索引写入存储它们的向量中。请记住。在 C++ 中,索引以 0 开头。

Value:   21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
Index:    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19

所以,如果我们现在想为每个 5 个值构建总和,那么我们需要添加

Index   0  1  2  3  4      Value: 21 22 23 24 25
Index   1  2  3  4  5      Value: 22 23 24 25 26
Index   2  3  4  5  6      Value: 23 24 25 26 27

. . . 

Index   14 15 16 17 18     Value: 35 36 37 38 39
Index   15 16 17 18 19     Value: 36 37 38 39 40

所以,你可以看到。我们有一个起始索引,它始终会递增 1。从这个起始索引开始,我们将始终将 5 个值相加。但是我们必须结束这个过程,正如您在上面的索引 15 处看到的那样,所以 20 - 5。所以,始终是整个数组的大小 - 子数组的大小。

所以,让我们先解决这个问题,我们可以向前迈进:

#include <iostream>
#include <vector>

int main() {
    // Our test data to play with
    std::vector<int> data = { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
    
    // This is the size of the subarray. So the number of values that we want to sum up
    int sizeOfSubarray = 5;

    // And because we have a subarray size, the last summation starts at this index
    int lastIndex = data.size() - sizeOfSubarray;

    // So, now iterate over all data that needs to be summed up
    for (int startIndex = 0; startIndex <= lastIndex; ++startIndex) {

        // Because we have a new start index now, we start also with a 0 sum
        int sum = 0;

        // Calculate the end index of the sub array
        int endIndexOfSubarray = startIndex + sizeOfSubarray;
        for (int sumIndex = startIndex; sumIndex < endIndexOfSubarray; ++sumIndex) {

            // Some debug output
            std::cout << "Startindex: " << startIndex << "\tSumindex: " << sumIndex << "\tValue: " << data[sumIndex] << '\n';

            // Calculate the subarray sum
            sum = sum + data[sumIndex];
        }
        // Show the subarray sum
        std::cout << "Sum: " << sum << '\n';
    }
}

好的,明白了。如果我们还想将数组的末尾值相加怎么办?那么,如果 startindex 将遍历整个数组怎么办。让我们看看这个。

Index   16 17 18 19  ?     Value: 37 38 39  40 ?
Index   17 18 19  ?  ?     Value: 38 39 40  ?  ?
Index   18 19  ?  ?  ?     Value: 39 40  ?  ?  ?
Index   19  ?  ?  ?  ?     Value: 40  ?  ?  ?  ?

您可以看到,起始索引一直运行到

如果求和的结束索引>19,那么>=向量的大小,我们可以将其限制为19,

我们可以计算或使用简单的 if 语句。

那么代码应该是这样的

#include <iostream>
#include <vector>

int main() {
    // Our test data to play with
    std::vector<int> data = { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
    
    // This is the size of the subarray. So the number of values that we want to sum up
    int sizeOfSubarray = 5;

    // So, now iterate over all data that needs to be summed up
    for (int startIndex = 0; startIndex < data.size(); ++startIndex) {

        // Because we have a new start index now, we start also with a 0 sum
        int sum = 0;

        // Calculate the end index of the sub array
        int endIndexOfSubarray = startIndex + sizeOfSubarray;

        // If this index is too big ( > 20) then limit it to 20
        if (endIndexOfSubarray > data.size()) {
            endIndexOfSubarray = data.size();
        }
        // Claculate sum of sub array
        for (int sumIndex = startIndex; sumIndex < endIndexOfSubarray; ++sumIndex) {

            // Some debug output
            std::cout << "Startindex: " << startIndex << "\tSumindex: " << sumIndex << "\tValue: " << data[sumIndex] << '\n';

            // Calculate the subarray sum
            sum = sum + data[sumIndex];
        }
        // Show the subarray sum
        std::cout << "Sum: " << sum << '\n';
    }
}

希望这个解释对你有帮助

【讨论】:

  • 多么好的解释……100% 可以理解。非常感谢您花费时间来构建此答案。
【解决方案2】:

一种选择是使内部循环范围为0-5

for (int a = 0; a < numVec.size(); a++) {
    int sum = 0;
    for (int b = 0; b < 5 && a + b < numVec.size(); b++) {
         sum += numVec[a + b];
    }
    std::cout << sum << "\n";
}

另一种选择是使用std::accumulate

for (auto a = numVec.begin(); a < numVec.end(); a++) {
    std::cout << std::accumulate(a, std::min(a + 5, numVec.end()), 0) << '\n';
}

另外,@Bathsheba 在 cmets 中提到的是保持一个运行总计,即 O(n)。

int sum = 0;
for (int a = 0; a < 5 && a < numVec.size(); a++) sum += numVec[a];
std::cout << sum << '\n';
for (int a = 5; a < numVec.size(); a++) {
    sum = sum - numVec[a - 5] + numVec[a];
    std::cout << sum << '\n';
}

【讨论】:

    【解决方案3】:

    这被认为是滚动和等。您可以编写一个模板,在指定窗口的向量上操作二进制函数:

    # include <iostream>
    # include <numeric>
    # include <vector>
    # include <functional> 
    using namespace std;
    
    template<class T, class Lambda>
    vector<T> roll_fun(vector<T> vec, int window, Lambda&& func, T init){
        int final_size =  vec.size() - window + 1;
        vector<T> result(final_size);
        for (int k = 0; k < final_size; k++)
          result[k] = accumulate(vec.begin() + k, vec.begin() + k + window, init, func);
        return result;
    };
    
    
    int main() 
    {  vector<double> myvec{1,2,2.3,3,4,5,6,7,8,9,1,2,3,4,5,6,7};
    
        //rolling sum
        vector<double> v = roll_fun<double>(myvec, 5,plus<double>(), 0.0);
        for(auto i: v) cout<<i<<' ';
        cout<<endl;
        
        // rolling mean
        vector<double> v1 = roll_fun<double>(myvec, 5,[](double x, double y){return x+y/5;}, 0);
        for(auto i: v1) cout<<i<<' ';
        cout<<endl;
        
         //rolling max
        vector<double> v2 = roll_fun<double>(myvec, 5,[](double x, double y){return x>y?x:y;}, 0.0);
        for(auto i: v2) cout<<i<<' ';
        cout<<endl;
        
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      整个auxsumAux 处理使您的逻辑比它需要的更复杂。

      试试这样的:

      #include <algorithm>
      
      const size_t size = numVec.size();
      const size_t increment = 5;
      
      for (size_t a = 0; a < size; ++a)
      {
          size_t stop = a + std::min(size-a, increment);
      
          sum = 0;
          for (size_t b = a; b < stop; ++b)
              sum += numVec[b].num;
      
          cout << "Sum: " << sum << endl;
      }
      

      Online Demo

      或者:

      #include <algorithm>
      #include <numeric>
      
      auto end = numVec.end();
      decltype(numVec)::difference_type increment = 5;
      
      for (auto start = numVec.begin(); start != end; ++start)
      {
          auto stop = start + std::min(end-start, increment);
      
          sum = std::accumulate(start, stop, 0,
              [](auto a, const auto &elem){ return a + elem.num; }
          );
      
          cout << "Sum: " << sum << endl;
      }
      

      Online Demo

      【讨论】:

      • 哇,我实际上做的事情比这更复杂......非常感谢。我只是不明白 std::min 的用法
      • std::min() 接受 2 个输入并返回具有较低值的那个。由于您希望一次处理不超过 5 个元素,我使用 std::min() 将总和限制为 5 个元素,如果剩余元素超过 5 个,否则我只对剩余元素求和,例如:std::min(6, 5)=5, std::min(4, 5)=4就像 JohnnyMopp 在 cmets 中所说,“如果列表中只有 20 个元素,那么任何超过 15 个的元素都将少于 5 个元素可供选择。
      猜你喜欢
      • 2014-02-11
      • 2021-12-17
      • 2013-03-03
      • 2021-07-29
      • 1970-01-01
      • 2019-07-22
      • 1970-01-01
      • 2021-11-02
      相关资源
      最近更新 更多