在列表<int>或向量<int>中添加备用数字

Add alternate numbers in a list<int> or vector<int>

本文关键字:int gt lt 添加 备用 数字 向量 列表      更新时间:2023-10-16

我试图访问列表中的备用数字以添加其值。例如,如果List的值={1,2,3,5}。我应该得到输出,4和7。

为了达到这个目的,我使用了std::List。首先,我需要能够访问序列的第n个元素,std::list,以便能够添加值。也就是说,我知道我可以使用std::advance: 获得到第n个元素的迭代器
std::list<Object> l;
unsigned N = /* index of the element that I want to retrieve */;
if (l.size() > N)
{
    std::list<Object>::iterator it = l.begin();
    std::advance(it, N);
}

然而,这并不能解决我的问题,因为我不明白如何能够访问替代值,同时添加它们,因为它不提供随机访问。

所以,我尝试使用std::vector,我使用

sum_of_vector =std::accumulate(vector.begin(),vector.end(),0);

当我添加向量的所有值时,这工作得很好,但我不理解逻辑,如果我只需要添加std::liststd::vector的替代值。

请看下面的代码。我已经添加了注释,所以它将是不言自明的。

#include <bits/stdc++.h>
using namespace std;
int main() 
{
    //Your vector of integers
    vector<int> V = {1, 2, 3, 5};
    //Size of your vector
    int n = V.size();
    //Initialise two integers to hold the final sum
    int sum1 = 0;
    int sum2 = 0;
    //Calculate sum1 starting from first element and jumping alternate element until you reach end
    for(int i=0; i<n; i+=2)
        sum1 += V[i];
    //Calculate sum2 starting from second element and jumping alternate element until you reach end
    for(int i=1; i<n; i+=2)
        sum2 += V[i];
    //Print your answer
    cout << "Sum1 = " << sum1 << " " << "Sum2 = " << sum2 << endl;
    return 0;
}

解决方法很简单。

  1. 创建包含两个元素的数组来累加总和。
  2. 使用在01之间交替的索引

Object sum[2] = {0};
int index = 0;
auto iter = l.begin();
auto end = l.end();
for ( ; iter != end; ++iter, index = (index+1)%2 )
{
    sum[index] += *iter;
}

代码解释,回应OP的注释

让我们以你的清单为例:

l is {1, 2, 3, 5}

for循环开始处:

sum[0] = sum[1] = 0
index = 0
iter points to the element whose value is 1

当循环执行时,

sum[index] = sum[0] = 1

在循环的下一次迭代中,

index = 1
iter points to the element whose value is 2

当循环执行时,

sum[index] = sum[1] = 2

在循环的下一次迭代中,

index = 0
iter points to the element whose value is 3

当循环执行时,

sum[index] = sum[0] = 4

在循环的下一次迭代中,

index = 1
iter points to the element whose value is 5

当循环执行时,

sum[index] = sum[1] = 7

在循环的下一次迭代中,指数= 0Iter指向终点。循环停止执行。

此时,

sum[0] = 4
sum[1] = 7

这样如何:

Object sum[2];
size_t i = 0;
for (auto it = l.begin(); it != l.end(); ++it, ++i)
  sum[i % 2] += *it; 

递归爱好者可能会建议:

typedef std::list<int>    IntList;
typedef IntList::iterator IntListIT;
void odd (IntListIT IT, int& sumEven, int& sumOdd, IntListIT ITend);
void even(IntListIT IT, int& sumEven, int& sumOdd, IntListIT ITend);

void even(IntListIT IT, int& sumEven, int& sumOdd, IntListIT ITend) {
   sumEven += *IT;
   if(++IT != ITend)
      odd(IT, sumEven, sumOdd, ITend); // tail-recursion
}
void odd(IntListIT IT, int& sumEven, int& sumOdd, IntListIT ITend) {
   sumOdd += *IT;
   if(++IT != ITend)
      even(IT, sumEven, sumOdd, ITend); // tail-recursion
}
int t209(void)
{
   IntList   intList;
   for (int i=0; i<10; ++i)
      intList.push_back(i+1);
   int sumEven = 0;
   int sumOdd  = 0;
   even(intList.begin(), sumEven, sumOdd, intList.end());
   std::cout << "nsumEven: " << sumEven
             << "n sumOdd: " << sumOdd
             << "n  total: " << (sumEven + sumOdd)
             << std::endl;
   return(0);
}
与输出

sumEven: 25
 sumOdd: 30
  total: 55

一个不同的递归爱好者不会喜欢"混乱的"4参数递归函数,并且可能会建议一个类来完成这项工作。令人惊讶的是(?或者你是否怀疑这一点),他能够消除(!)所有(可见)参数为类的两个相互递归方法。

// class Even-Odd-Sum 
class EOSum          // wrap recursive efforts
{
public:
   EOSum(IntList& intList) :
      m_list(intList),
      m_eSum(0),
      m_oSum(0),
      m_IT(intList.begin()),
      m_ITend  (intList.end())
      { }
   ~EOSum() { m_eSum = 0; m_oSum = 0; }
   std::string operator()()
      {
         // do the math
         e();  // recursively
         // report results
         std::stringstream ss;
         ss << "n  eSum: " << m_eSum
            << "n  oSum: " << m_oSum
            << "n total: " << (m_eSum + m_oSum)
            << "nn sizeof(this): " << sizeof(this) << " bytes.  "
            << "nestimated total stack needed with unoptimized recursive call: "
            << DTB::digiComma(C100M*(2*sizeof(this)))
            << "ndefault stack size Ubuntu 15.04                             :     "
            << DTB::digiComma(8*1024*1024)
            << std::endl;
         return(ss.str());
      }
   static const int C100M = 100000000;
private:
   IntList&  m_list;
   int64_t   m_eSum;
   int64_t   m_oSum;
   IntListIT m_IT;    // iterate thru the list
   IntListIT m_ITend;
   // the new and improved recursion - NO (visible) PARAMETERS
   void e()
      {
         m_eSum += *m_IT;
         if (++m_IT != m_ITend)
            o(); // tail-recursion
      }
   void o()
      {
         m_oSum += *m_IT;
         if (++m_IT != m_ITend)
            e(); // tail-recursion
      }
};
// test 
int t209b(void)
{
   std::cout << "nnt209b start: using EOSum::C100M = "
             << DTB::digiComma(EOSum::C100M) << " multiplier  (~10 seconds on lab005)"
             << std::endl;
   uint64_t t209bStartMS = DTB::getSystemMillisecond();
   uint64_t dtorStartMS;
   {
      IntList   intList;
      {
         uint64_t startMS = DTB::getSystemMillisecond();
         for (int i=0;   i<EOSum::C100M; ++i)  // use -O3 to avoid segfault - tail recursion optimized
            intList.push_back(i+1);
         uint64_t durationMS = DTB::getSystemMillisecond() - startMS;
         std::cout << "n100M list push_back's   : " << durationMS << " ms"
                   << "n     to 'new' intList elements " << std::endl;
      }
      {
         uint64_t startMS = DTB::getSystemMillisecond();
         // Ubuntu 15.04 default stack size  8 M Bytes
         //     100,000: No stack over flow
         //   1,000,000: -O0 stack overflow segfault, -O3: No segfault
         // 100,000,000: -O3: No segfault
         std::cout << EOSum(intList)() << std::endl;
         uint64_t durationMS = DTB::getSystemMillisecond() - startMS;
         std::cout << "100 M recursion calls   : " << durationMS << " ms "
                   << "n    to compute eSum, oSum, total shown above " << std::endl;
      }
      dtorStartMS = DTB::getSystemMillisecond();
   }  // intList destruction at this brace
   uint64_t dtorDurationMS = DTB::getSystemMillisecond() - dtorStartMS;
   std::cout << "n100 M list item dtor's  : " << dtorDurationMS
             << "n      to 'delete' intList elements " <<  std::endl;

   uint64_t t209bDurationMS = DTB::getSystemMillisecond() - t209bStartMS;
   std::cout << "n t209b() duration MS    : " << t209bDurationMS << std::endl;
   return(0);
}

在这段代码中,当使用优化级别0(- 0)时,堆栈溢出(在递归期间),将100,000到1m个元素添加到列表中。注意Ubuntu 15.04的默认堆栈只有8 M字节,每个方法调用可能会使用16个字节(this ptr,并返回addr)。

然而,作者实现了尾部递归,并且由于g++ 4.9.2编译器令人印象深刻的优化(在第3级,-O3),该递归现在使用固定的堆栈元素数!尽管双重相互递归方法增加了复杂性。

这段代码有一些个人的库使用,所以下面是测试的输出:

请随意在您的机器上尝试(使用一些简单的替换或删除我的DTB::方法)。

所有的持续时间是从我的6年以上的戴尔。

t209b start: using EOSum::C100M = 100,000,000 multiplier (~10 seconds on lab005)
100M list push_back's   : 6930 ms
     to 'new' intList elements 
  eSum: 2500000000000000
  oSum: 2500000050000000
 total: 5000000050000000
 sizeof(this): 8 bytes.  
estimated total stack needed with unoptimized recursive call: 1,600,000,000
default stack size Ubuntu 15.04                             :     8,388,608
100 M recursion calls   : 1320 ms 
    to compute eSum, oSum, total shown above 
100 M list item dtor's  : 2754
      to 'delete' intList elements 
 t209b() duration MS    : 11035

real  0m11.290s
user  0m8.532s
sys   0m2.556s

在这种情况下,std::valarray可能是合适的。假设您的目标是添加所有偶数成员和所有奇数成员,您可以这样做:

std::valarray<int> l;
// Put stuff into the array
std::valarray<int> even = l[std::slice(0, l.size() / 2, 2)]
std::valarray<int> odd  = l[std::slice(1, l.size() / 2, 2)];
int sum_of_odd = odd.sum(), sum_of_even = even.sum();