私の現在のC++プロジェクトには、整数キーをオブジェクトにマップするSTLマップがあります。アルゴリズムはエントリのセットを返します。返されるデータは、アルゴリズムの入力に依存し、したがって、予測することはできません。C++ STL:iteratorと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のエントリは結果の2つの連続したエントリに非常に近いことを発見しました。したがって、私は)(私は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が変更されたとします。 while
-loop内のイテレータをインクリメントするのかデクリメントするのかを調べる代わりに、for
-loopを入力する前にそれを決めることができました。
私はちょうどmap<>::reverse_iterator
にmap<>::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
パフォーマンスを向上させるという結論にはどうしましたか?それをバックアップするデータがありますか?これがアプリケーションの実際のボトルネックでない場合は、自分でもっと仕事をしているかもしれません。それはまだ興味深い質問です。 :) – Scott
'map :: find()'を使用するとO(log n)の複雑さがあるため、次のエントリが現在のものに近いと仮定することはできません。このコードは、いくつかのネストされたループの中で非常に重要な位置にあります – fishbone