Вот некоторые оптимизации, которые могут помочь:
Возьмите этот сегмент кода из функции get
:
if(umap.count(key)){
// remove it from the old position
klist.erase(umap[key].second);
Выше приведенный выше поиск key
на карте дважды. Один раз для метода count
, чтобы увидеть, существует ли он. Другой, чтобы вызвать оператор []
для получения его значения. Сохраните несколько циклов, выполнив это:
auto itor = umap.find(key);
if (itor != umap.end()) {
// remove it from the old position
klist.erase(itor->second);
В функции put
вы сделаете следующее:
if(umap.count(key)){
klist.erase(umap[key].second);
umap.erase(key);
}
То же, что и get
, вы можете избежать избыточного поиска до umap
. Кроме того, нет причины вызывать umap.erase
только для того, чтобы добавить этот же ключ обратно на карту несколькими строками позже.
Кроме того, это также неэффективно
umap[key].first = value;
umap[key].second = --key_loc;
Как и выше, Излишне ищем key
дважды на карте. В первом операторе присваивания key
отсутствует на карте, поэтому по умолчанию создается новая пара значений. Второе назначение - это еще один поиск на карте.
Давайте реструктурируем вашу функцию put
следующим образом:
void put(int key, int value) {
auto itor = umap.find(key);
bool reinsert = (itor != umap.end());
// if key already exists delete it from the klist only
if (reinsert) {
klist.erase(umap[key].second);
}
else {
// if the unordered map is at max capacity
if (umap.size() == cap) {
umap.erase(klist.front());
klist.pop_front();
}
}
// finally update klist and umap
klist.push_back(key);
list<int>::iterator key_loc = klist.end();
auto endOfList = --key_loc;
if (reinsert) {
itor->second.first = value;
itor->second.second = endOfList;
}
else {
const pair<int, list<int>::iterator> itempair = { value, endOfList };
umap.emplace(key, itempair);
}
}
Это насколько вы можете go, используя std::list
. Недостатком типа list
является то, что невозможно переместить существующий узел из середины вперед (или назад), не удалив его сначала, а затем добавив обратно. Это пара ненужных выделений памяти для обновления списка. Возможной альтернативой является то, что вы просто используете свой собственный тип двойного списка и вручную исправляете указатель prev / next самостоятельно.