#c #stl
#c #stl
Вопрос:
Есть ли хороший и простой способ найти nth element
в C
std::map
? В частности, я ищу алгоритм для удаления последних k
элементов из map
. Это имело бы смысл для извлечения итератора в nth element
и вызова std::map::erase
. Требование заключается в том, чтобы сложность не страдала — должно быть возможно стереть диапазон элементов в O(N)
.
Копирование данных не должно выполняться только для удаления элементов. Например, одно из решений состоит в том, чтобы скопировать данные в std::vector
, затем выполнить std::nth_element
on std::vector
, а затем std::map::find
найти итератор, чтобы узнать, откуда нужно стереть.
Одно из других решений — просто повторить итерацию std::map
с сохранением переменной счетчика количества удаляемых элементов. Это дало бы O(n)
. Возможно ли заменить for
цикл на STL algorithm
?
Ответ №1:
Карты не обеспечивают более чем линейный доступ к элементам по индексу, например, vector
или deque
. Вы можете сделать это с помощью std::advance
, но это требует времени, пропорционального k
. Если k
он маленький, часто это происходит достаточно быстро — в основном это связано с следованием за k
указателями. Вот пример:
template<typename Map>
void erase_last_elements(Map amp; map, ptrdiff_t k)
{
assert(k >= 0);
assert(map.size() >= (size_t)k);
typename Map::iterator i = map.end();
std::advance(i, -k);
map.erase(i, map.end());
}
В качестве альтернативы, если вы используете Boost, вы можете использовать boost::prior
:
template<typename Map>
void erase_last_elements(Map amp; map, ptrdiff_t k)
{
assert(k >= 0);
assert(map.size() >= (size_t)k);
typename Map::iterator i = boost::prior(map.end(), k);
map.erase(i, map.end());
}
В противном случае вам придется поддерживать отдельный индекс или использовать другой контейнер. Может подойти что-то вроде sorted vector
, если вы не слишком часто вставляете и удаляете элементы.
Комментарии:
1. Есть ли какая-либо причина, по которой
std::map
не предоставляетсяO(log(n))
решение для доступа к n-му элементу?2. Должно быть эффективнее удалять «end() — 1» k раз.
3. Это звучит как разумное решение, Стефан.
4. @Leonid — у них нет быстрого доступа к N-му элементу, потому что им пришлось бы поддерживать отдельный индекс, что потребовало бы больше памяти или замедлило бы вставку или удаление.
5. @Stefan — как ты думаешь, почему это было бы быстрее сделать? Асимптотически сложность та же, и потенциально требуется меньше перебалансировок дерева, если удалить их все одним вызовом erase.
Ответ №2:
Редактировать: Ответ не применим после редактирования исходного сообщения.
Комментарии:
1. Это именно то, чего я бы не хотел делать.