在我當前的C++項目中,我有一個將整數鍵映射到對象的STL映射。算法返回一組條目。返回的數據依賴於算法的輸入,因此無法預測:C++ STL:迭代器和reverse_iterator缺少基類的代碼複製
class MyClass
{
//...
};
int myAlgorithm(vector<int>::iterator inputIt)
{
// return a key for myMap which is calculated by the current value of inputData
}
int main(int argc, char *argv[])
{
vector<int> inputData;
map<int, MyClass> myMap;
//<fill map with some data>
//<fill inputData>
vector<MyClass> result;
for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
{
int myMapKey = myAlgorithm(*it);
// count() > 0 means "check whether element exists. Performance can be improved by replacing
// the operator[] and count() calls by map::find(). However, I want to simplify things
// in this example.
if (myMap.count(myMapKey) > 0)
{
// in some cases there is no entry in myMap
result.push_back(myMap[myMapKey]);
}
}
}
如例子中提到的,我可以用查找替換map::count()
和operator[]
-calls。 STL-reference表示map :: find()的複雜度是對數大小(O(log n)
)。
我發現在大多數情況下myMap中的條目對於結果中的兩個連續條目非常接近。因此,我得出的結論,如果我取代了map.find(我會獲得更好的性能)調用由迭代器:
map<int, MyClass>::iterator myMapIt = myMap.begin();
for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
{
int myMapKey = myAlgorithm(*it);
// just increment iterator
while (myMapKey != myMapIt->first)
{
myMapIt++;
// we didn't find anything for the current input data
if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
{
break;
}
}
// I know that I'm checking this twice, but that's not the point of my
// question ;)
if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
{
// probably it would be better to move the iterator back to the position
// where we started searching, to improve performance for the next entry
myMapIt = myMap.begin();
}
else
{
result.push_back(myMapIt.second);
}
}
這個概念的作品,但我有一個很大的問題:根據inputData,我要向前或向後搜索。考慮我多次調用main()
中的代碼,並且inputData更改爲這些調用。而不是檢查是否增加或減少循環內的迭代器,我可以決定在輸入for
-loop之前。
我認爲我很好只是切換到map<>::iterator
和map<>::reverse_iterator
使用rbegin()
/rend()
,而不是begin()
/end()
。但後來我意識到,reverse_iterator
和iterator
沒有公共基類:
map<int, MyClass>::base_iterator myIt;
if (/* ... */)
{
myMapIt = myMap::begin();
myMapEndIt = myMap::end();
}
else
{
myMapIt = myMap::rbegin();
myMapEndIt = myMap::rend();
}
/* for (...) ... */
這將是巨大的,但沒有base_iterator
。
我知道這個問題的簡單解決方法:我只需要複製整個for
-loop,並將其調整爲兩種情況:
if (/* ... */)
{
/* for(...) which uses normal iterator in the while-loop */
}
else
{
/* for(...) which uses reverse iterator in the while-loop */
}
極壞的...你知道一個更好的解決方案?
會調用一個函數模板的工作? – PlasmaHH 2012-02-13 14:23:55
你是如何得出結論的,你會獲得更好的表現?你有數據支持它嗎?如果這不是應用程序中真正的瓶頸,那麼您可能只是爲自己做更多的工作。這就是說,這仍然是一個有趣的問題。 :) – Scott 2012-02-13 15:08:23
由於使用'map :: find()'時O(log n)的複雜性,它無法假定下一個條目接近當前條目。此代碼處於非常關鍵的位置,在幾個嵌套循環內 – fishbone 2012-02-14 21:01:51