0

我有一个用结构填充 STL 链表的程序,我试图从列表上的一个节点(我目前通过迭代器使用的节点)传递结构成员。我想要完成的一件事是计算运行平均值的函数。我不想将计数和总数存储在结构中,然后在输出时计算平均值,而是将计数和平均值存储在结构中,从而在重新计算平均值后丢弃我的数量值。我的结构如下所示:

struct mystruct 
{
    string item;
    long avg;
    short count;
} data;

这些结构存储在一个带有迭代器的列表中it,它允许我在列表中移动。如果我遍历了列表并且it等于我想要计算平均值的数据的节点,这是否是调用我的平均函数的正确方法?

// prior to running the code below, the `count` and `avg` members for the 
// struct at iterator location `it` are both 1 and 100 respectively

long qty = 50;
calc_average(it->count, it->avg, qty);

cout << "The current count is " << it->count << endl; 
  // Outputs 'The current count is 2'
cout << "The current average is " << it->avg << endl; 
  // Outputs 'The current average is 75'


void calc_average(short &count, long &avg, long quant)
{
    avg = ( (avg * count) + quant ) / (count + 1);
    count++;
}

这看起来正确吗?我正在尝试使用 STL 列表来实现这一点,但它似乎比仅仅实现我自己的链表类更令人困惑。我想我只是对结构以及迭代器的实际工作方式以及实际传递的内容/方式感到困惑。编码对我来说仍然相当新,所以这是一个学习过程......

谢谢!

4

4 回答 4

3

假设这X是列表中对象的类型,那么您可以执行以下操作:

void DoSomething(X& object) {
  object.count, object.avg;
}
void DoSomethingElse(int& count, int& average) {
  ...
}

int main() {
   ...
   for(std::list<X>::iterator it=myList.begin(), end=myList.end(); it != end; ++it) {
     DoSomething(*it); // how I'd do it
     DoSomethingElse(it->count, it->avg); // Equally valid way that you did it
   }
   ...
}

只记得:

  • container.begin()是指向第一个元素的指针
  • container.end()是指向最后一个元素的指针
  • *it是对指向元素的引用
  • it != container.end()是你如何判断你是否在最后
  • it->x是指向元素的成员
  • 从容器中移除一个对象可能会使未完成的迭代器失效,这取决于几个因素。
  • ++it可能比it++

编辑:OP问:

我不是遍历列表并在每个节点上运行 calc_average,而是遍历列表以查找特定的项目值。一旦找到感兴趣的节点,我就会在该特定节点上调用 calc_average 函数。我只是不需要for循环。相反,我会到达我想要的迭代器,并通过 *it 将其传递给 void DoSomething ?

我想你现在明白它是如何工作的了。您将有一些代码来搜索指示的节点,然后有一些其他代码来调用您的函数:

   std::list<X>::iterator it, end;
   for(it=myList.begin(), end=myList.end(); it != end; ++it) {
     // Look for the special node:
     if( it->magicValue == 42 ) {
       // We found it!
       break;
     }
   }

    // Either it is equal to end (boo!) or it points to the special node (yay!)
   if( it == end ) {
      std::cerr << "Could not find special node!\n";
   }
   if( it != end ) {
      DoSomething(*it);
   }
于 2012-10-22T21:05:45.120 回答
1

将迭代器视为指向列表中元素的指针。因此,与其让calc_average函数作用于个人成员,mystruct不如让它引用一个mystruct对象并用它做一些事情。

例如:

void do_work( mystruct& s )
{
  ++s.count;
}

std::list<mystruct> mylist;

// populate list

std::for_each( mylist.begin(), mylist.end(), do_work );

您还可以使用基于范围的for循环来实现相同的效果

for( auto& elem : mylist ) {
  do_work( elem );
}

我会将calc_average函数重写为

void calc_average( mystruct& s, long quant )
{
    s.avg = ( (s.avg * s.count) + quant ) / (s.count + 1);
    s.count++;
}

将它与基于范围的for循环一起使用是微不足道的,但要与它一起使用,std::for_each您必须使用std::bind绑定quant参数。

std::for_each( mylist.begin(), mylist.end(), 
  std::bind( calc_average, std::placeholders::_1, qty ) );
于 2012-10-22T21:10:24.993 回答
0

Yes, it all seems correct to me. You can think of iterators (especially iterators of standard containers) as just pointers, though in practice they're actually classes that look like pointers. Still, you can think of them as pointers.

于 2012-10-22T21:13:38.223 回答
0

我目前正在处理动态内容,我发现我有一个 SPRITE 结构 std::list characters_spr; 我通过 SPRITE 字符声明一个字符,然后我使用

characters_spr.push_back(character)

然后我使用 for 循环遍历列表

for(SPRITE &character : characters_spr){
   somefunction(character, ....);
}

在 somefunction 我有 somefunction(SPRITE &spr, ....................)

当调用 somefunction 时,它会更新列表中字符的字符数据。

于 2021-01-14T23:03:43.527 回答