Trong dự án C++ hiện tại của tôi, tôi có một bản đồ STL ánh xạ các phím số nguyên lên các đối tượng. Một thuật toán trả về một tập các mục. Các dữ liệu trả về phụ thuộc vào đầu vào của thuật toán và do đó không thể được dự đoán:C++ STL: Mã trùng lặp do thiếu lớp cơ sở cho trình lặp và 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]);
}
}
}
Như đã đề cập trong ví dụ tôi có thể thay thế map::count()
và operator[]
-calls với find. Các STL-reference nói rằng bản đồ :: tìm() 's phức tạp là logarithmic trong kích thước (O(log n)
).
Tôi phát hiện ra rằng trong hầu hết các trường hợp, các mục trong myMap rất gần với hai mục nhập liên tiếp trong kết quả. Vì vậy, tôi đi đến kết luận rằng tôi sẽ đạt được hiệu suất tốt hơn nếu tôi thay thế map.find() gọi bằng lặp:
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);
}
}
khái niệm này hoạt động nhưng tôi có một vấn đề lớn: Tùy thuộc vào inputData, tôi phải tìm kiếm tiến hoặc lùi. Hãy xem xét rằng tôi gọi mã bên trong main()
nhiều lần và các thay đổi inputData cho các cuộc gọi này. Thay vì kiểm tra xem có tăng hoặc giảm bộ lặp trong vòng while
vòng lặp hay không, tôi có thể quyết định rằng trước khi bước vào vòng lặp for
.
Tôi nghĩ rằng tôi là tốt với chỉ cần chuyển đổi các map<>::iterator
-map<>::reverse_iterator
và sử dụng rbegin()
/rend()
thay vì begin()
/end()
. Nhưng sau đó tôi nhận ra rằng reverse_iterator
và iterator
không có lớp cơ sở chung:
map<int, MyClass>::base_iterator myIt;
if (/* ... */)
{
myMapIt = myMap::begin();
myMapEndIt = myMap::end();
}
else
{
myMapIt = myMap::rbegin();
myMapEndIt = myMap::rend();
}
/* for (...) ... */
Đó sẽ là tuyệt vời, nhưng không có base_iterator
.
Tôi biết một workaround đơn giản cho vấn đề này: Tôi chỉ cần sao chép toàn bộ for
-loop và điều chỉnh nó cho cả hai trường hợp:
if (/* ... */)
{
/* for(...) which uses normal iterator in the while-loop */
}
else
{
/* for(...) which uses reverse iterator in the while-loop */
}
Rất xấu ... Bạn có biết một giải pháp tốt hơn?
sẽ gọi mẫu chức năng hoạt động? – PlasmaHH
Làm thế nào bạn đi đến kết luận rằng bạn sẽ đạt được hiệu suất tốt hơn? Bạn có dữ liệu để sao lưu không? Nếu đây không phải là một nút cổ chai thực sự trong ứng dụng của bạn, bạn chỉ có thể làm việc nhiều hơn cho chính mình. Điều đó nói rằng, nó vẫn là một câu hỏi thú vị. :) – Scott
Do độ phức tạp O (log n) khi sử dụng 'map :: find()' mà không thể giả định rằng mục nhập tiếp theo gần với mục nhập hiện tại. Mã này ở vị trí rất quan trọng, bên trong một vài vòng lặp lồng nhau – fishbone