2010-04-07 79 views
1

我正在寫一個迭代點列表的算法,計算它們之間的距離並在距離太大時插入附加點。不過,我似乎缺乏與STL合適的解決方案。我希望我能學到一些東西,所以我會告訴你我的代碼。你可能對我有一些提示。地道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++; 
     } 
    } 
} 
+0

對我很好。雖然我會做一些事情來清楚說明'Vector'不是'std :: vector '。 – 2010-04-07 20:22:12

+1

您正在增加'it'兩次而未檢查它是否有效。 – 2010-04-07 20:46:39

+0

其實我不是。在循環內部,我的迭代器將始終指向有效的列表元素。然而迭代器的運動有點狂野,這是我對代碼不滿意的原因之一。 – 2010-04-07 20:56:36

回答

6

考慮使用adjacent_find找到一個迭代位置連續元素之間的距離過大,則插入pointsToInsert項目。

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

此外,你可以使用generate用函子來填補中間點。

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

不知道你想有多深進入STL :)

+0

盡我所能。很好的答案,謝謝! – 2010-04-07 20:57:14

+1

很好的學習方式,但使用stl廣泛可以給很不可讀的代碼,除非讀者非常熟悉stl。 – Zitrax 2010-04-07 21:34:55

+1

無論您使用什麼方法,編寫不良的代碼都很難閱讀。 – 2010-04-07 22:38:16

0

你迭代求解是完全可以理解的。我知道你什麼時候說「我希望我能學到東西」這不是你想要的,但我希望你學到的是:

1)找到一個「優雅」功能解決方案沒有任何好處,你有一個好方法

2)函數式編程的C++迭代求解一個問題是單調乏味的,甚至比C++已經是乏味的。

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 
      } 
     } 
    } 
} 
0

您不必捕獲列表插入到迭代器的返回值。這樣,你不需要手動增加它。

for (int i = 0; i < pointsToInsert; i++) 
{ 
    curPos += vecFromPrev/pointsToInsert; 
    points_.insert(it, PathPoint(curPos, false)); 
} 
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 
     } 
    } 
} 

移動你的迭代器來回就像是有點混亂。另外,請注意,無論是這個還是您的原始代碼,都不會像空列表那麼多。