Geçerli C++ - projemde, tamsayı tuşlarını nesnelerin üzerine eşleyen bir STL haritasına sahibim. Bir algoritma bir dizi giriş döndürür. Dönen veri algoritmanın giriş bağlıdır ve dolayısıyla tahmin edilemez:C++ STL: Yineleyici kod, yineleyici ve reverse_iterator için eksik temel sınıf nedeniyle kopyalanıyor
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]);
}
}
}
Ben Bul ile map::count()
ve operator[]
-calls yerini alabilir örnekte belirtildiği gibi. STL-reference, map :: find() 'ın karmaşıklığının logaritmik boyutta olduğunu bildiriyor (O(log n)
).
Çoğu durumda, myMap'teki girdilerin sonuçta iki sıralı girdi için çok yakın olduğunu keşfettim. Bu nedenle ben map.find (değiştirilir eğer iyi performans elde ederim sonuca) geldi yineleyiciler tarafından çağırır:
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);
}
}
Bu kavram eserlerini ama büyük bir sorun var: InputData bağlı olarak, bunu yapmak zorunda ileriye veya geriye doğru arama. Kodu main()
'un içinde birçok kez aradığımı ve bu çağrılar için inputData'nın değiştiğini düşünün. while
-loop içerisindeki yineleyicinin artırılıp artırılmayacağına karar vermek yerine, for
-loop girmeden önce karar verebilirim.
map<>::reverse_iterator
için
map<>::iterator
anahtarlama ve
rbegin()
/
rend()
yerine
begin()
/
end()
kullanmasının bir sakıncası yok düşündük. Ama sonra
reverse_iterator
ve
iterator
ortak temel sınıfa sahip olduğunu fark etti:
map<int, MyClass>::base_iterator myIt;
if (/* ... */)
{
myMapIt = myMap::begin();
myMapEndIt = myMap::end();
}
else
{
myMapIt = myMap::rbegin();
myMapEndIt = myMap::rend();
}
/* for (...) ... */
çok iyi olurdu, ancak hiçbir base_iterator
yoktur.
for
-loop kopyalayıp ayarlamak gerekir:
if (/* ... */)
{
/* for(...) which uses normal iterator in the while-loop */
}
else
{
/* for(...) which uses reverse iterator in the while-loop */
}
Çok kötü ... Eğer daha iyi bir çözüm biliyor musunuz?
, bir işlev şablonu çalışması çağırır mı? – PlasmaHH
Daha iyi bir performans elde edeceğiniz sonucuna nasıl geldiniz? Yedeklemek için verileriniz var mı? Bu, uygulamanızda gerçek bir darboğaz değilse, sadece kendiniz için daha fazla iş yapıyor olabilirsiniz. Bu, yine de ilginç bir soru. :) – Scott
Bir sonraki girişin geçerli olana yakın olduğunu kabul edemeyen map :: find() 'kullanırken O (log n) karmaşıklığı nedeniyle O (log n) karmaşıklığı. Bu kod çok kritik bir konumda, iç içe geçmiş birkaç döngünün içinde – fishbone