惯用STL:迭代列表并插入元素

时间:2010-04-07 20:19:38

标签: c++ stl iterator

我正在编写一个迭代点列表的算法,计算它们之间的距离,如果距离太大,则插入额外的点。然而,我似乎缺乏对STL的熟悉,无法提出一个优雅的解决方案。我希望我能学到一些东西,所以我只会告诉你我的代码。你可能会给我一些提示。

for (std::list<PathPoint>::iterator it = ++points_.begin();
     it != points_.end(); it++)
{
    Vector curPos = it->getPosition();
    Vector prevPos = (--it)->getPosition();
    Vector vecFromPrev = curPos - prevPos;
    float distance = vecFromPrev.abs();
    it++;
    if (distance > MAX_DISTANCE_BETWEEN_POINTS)
    {               
        int pointsToInsert = (int)(distance / MAX_DISTANCE_BETWEEN_POINTS);             
        Vector curPos = prevPos;                
        for (int i = 0; i < pointsToInsert; i++)
        {
            curPos += vecFromPrev / pointsToInsert;
            it = points_.insert(it, PathPoint(curPos, false));
            it++;
        }
    }
}

5 个答案:

答案 0 :(得分:6)

考虑使用adjacent_find来查找迭代器位置,其中连续元素之间的距离太大,然后插入pointsToInsert项。

http://www.sgi.com/tech/stl/adjacent_find.html

此外,您可以使用generate和仿函数来填充中间点。

http://www.sgi.com/tech/stl/generate.html

不确定你想进入STL有多深:)

答案 1 :(得分:0)

你的迭代解决方案是完全可以理解的。我知道当你说“我希望我能学到一些东西”这不是你想要的,但我希望你学到的是:

1)找到一个“优雅”的功能性解决方案对于你以一种精细的方式迭代解决的问题没有任何好处

2)C ++中的函数式编程很繁琐,甚至比C ++更乏味。

答案 2 :(得分:0)

我不喜欢提到迭代器类型,因为1.)它们有点丑陋2.)它减少了我必须做的更改,如果我更改集合类型,所以我可能会做这样的事情.. ..

我做了一些额外的调整,这些调整可能比我惯用的个人风格更多。

this->addAdditionalPoints(points.begin(), points.end());


template<typename InIt>
void MyClass::addAdditionalPoints(InIt start, InIt finish)
{
   InIt it = start;
   ++it;                                      // Starting with second element
   for (; it != finish; ++it)  // I usually pre-increment iterators, but 
                                             // it probably doesn't matter.
   {
      InIt curr = it;                       // Work with a temp rather than loop index
      Vector curPos = curr->getPosition();
      Vector prevPos = (--curr)->getPosition();
      Vector vecFromPrev = curPos - prevPos;
      float distance = vecFromPrev.abs();
      ++curr;                             // Prefer to pre-increment iterators
      if (distance > MAX_DISTANCE_BETWEEN_POINTS)
      {               
          int pointsToInsert = static_cast<int>(distance /              
              MAX_DISTANCE_BETWEEN_POINTS);  // I prefer C++-style casts     
          Vector curPos = prevPos;                
          for (int i = 0; i < pointsToInsert; i++)
          {
              curPos += vecFromPrev / pointsToInsert;
              curr = points_.insert(curr, PathPoint(curPos, false));
              ++curr;  // Again I prefer to pre-increment iterators
          }
      }
   }
}

答案 3 :(得分:0)

您不必将列表插入的返回值捕获到迭代器。这样,您无需手动递增它。

for (int i = 0; i < pointsToInsert; i++)
{
    curPos += vecFromPrev / pointsToInsert;
    points_.insert(it, PathPoint(curPos, false));
}

答案 4 :(得分:0)

斯蒂芬的解决方案是一个很好的解决方案,但为了教育的利益,你可以一次循环两个变量:

typedef typename std::list<PathPoint>::iterator Itr; //Pointless, but just to illustrate the possibility
for(Itr cur = points_.begin(), prev = cur++; cur != points_.end(); ++prev, ++cur) {
    Vector curPos = cur->getPosition();
    Vector prevPos = prev->getPosition();
    Vector vecFromPrev = curPos - prevPos;
    float distance = vecFromPrev.abs();
    if (distance > MAX_DISTANCE_BETWEEN_POINTS) {               
        int pointsToInsert = (int)(distance / MAX_DISTANCE_BETWEEN_POINTS);             
        Vector curPos = prevPos;                
        for (int i = 0; i < pointsToInsert; i++) {
            curPos += vecFromPrev / pointsToInsert;
            prev = points_.insert(cur, PathPoint(curPos, false));
            //as somebody mentioned, `cur` remains valid during `list` insertions
        }
    }
}

像往常一样来回移动迭代器有点令人困惑。另外,请注意,这个和原始代码都不像空列表那样。