Мне будет дано около 100 тыс. Координат в файле. Но число элементов не фиксировано. И я хочу сохранить их в структуре данных, которая будет самой быстрой для вставки/последовательного чтения/удаления. Хотя структура данных последовательно повторяется в цикле. От 25 до 70% элементов необходимо удалить. Кроме того, порядок координат имеет значение.
В таком случае, какие будут самые быстрые структуры данных для вставки/последовательного чтения/удаления в C++?
Ответ во многом зависит от того, как вы действительно собираетесь использовать свой контейнер.
Не паникуйте: используйте typedef
для std::vector
чтобы начать с (или любого другого conatiner, это не имеет значения) и сделать ваш код общим для контейнера (как это делают алгоритмы STL):
typedef std::vector<Points> Coordinates
После того, как ваша программа будет запущена (и вы знаете, сколько добавить/удалить и т.д.), Выполните ее.
Вы можете бесплатно изменить тип контейнера (возможно, в std::list<>
или std::deque
), только изменив этот typedef
и правильно проверив каждый контейнер в реальных сценариях.
В этот момент вы узнаете, какой контейнер вам нужен.
std::list
обеспечит самую быструю установку, удаление и чтение SEQUENTIAL. Вы не хотите использовать std::vector
так как ему придется перераспределять весь массив при вставках (если вы не укажете предварительно выделенный буфер).
Ознакомьтесь с http://www.cplusplus.com/reference/list/list/. Как вы можете видеть, std :: list является двусвязным списком. Это позволит вам делать вставки/удаление в голове или хвосте списка в постоянное время. Итерация по списку в последовательности также (по существу) происходит так же быстро, как итерация через вектор. Я имею в виду, что обе операции являются постоянными. См. Комментарии ниже о проблемах, связанных с фрагментацией памяти.
Там не хватает информации, чтобы действительно предложить лучшее место здесь. Как часто вы вставляете и удаляете? Но некоторая пища для размышлений:
Если ваши координаты trivially copyable
std::vector
trivially copyable
действительно может быть довольно быстрым с memmove
. Во время итерации и вы хотите стереть текущий элемент, перемотайте его и уменьшите i
или iterator
(не имеет значения, если он переполняется для size_t
пока вы делаете это последнее, так как он будет правильно переполняться с шагом). То же самое можно сделать с вставкой до тех пор, пока вы позаботитесь о повторном распределении, вы всегда должны reserve
если capacity() == size()
.
Я советовал std::list
, мне трудно найти случай для этого. Если вы хотите поведение двойного связанного списка, вы можете сохранить std::tuple< size_t, size_t, Coordinate >
а первые два элемента означают смещение к предыдущему и следующему элементу. Это могло бы улучшить поведение кэша, но со временем все равно будет фрагментироваться (в этом случае вы могли бы периодически разложить его, если это возможно). Другой подход заключается, по крайней мере, в использовании пользовательского распределителя для std::list
, посмотрите на boost::pool
.