Ответ 1
Этот чит-лист дает довольно хорошее резюме разных контейнеров.
См. блок-схему внизу в качестве руководства для использования в разных сценариях использования:
Создано Дэвид Мур и лицензированный CC BY-SA 3.0суб >
Я читал на контейнерах STL в своей книге на С++, в частности, в разделе STL и его контейнерах. Теперь я понимаю, что каждый из них имеет свои собственные специфические свойства, и я близок к запоминанию всех из них... Но то, что я еще не понимаю, в том, какой сценарий используется каждый из них.
Какое объяснение? Пример кода предпочтительнее.
Этот чит-лист дает довольно хорошее резюме разных контейнеров.
См. блок-схему внизу в качестве руководства для использования в разных сценариях использования:
Создано Дэвид Мур и лицензированный CC BY-SA 3.0суб >
Вот блок-схема, вдохновленная версией Дэвида Мура (см. выше), которую я создал, которая обновлена (в основном) с новым стандартом (С++ 11). Это только мое личное взятие на него, это не бесспорное, но я полагал, что это могло бы быть полезным для этой дискуссии:
Простой ответ: используйте std::vector
для всего, если только у вас нет реальной причины поступить иначе.
Когда вы обнаружите случай, когда вы думаете: "Ну и дела, std::vector
не работает здесь хорошо из-за X", иди на основе X.
Посмотрите на эффективный STL Скотта Мейерса. Это хорошо объясняет, как использовать STL.
Если вы хотите сохранить определенное/неопределенное количество объектов, и вы никогда не удалите их, то вектор - это то, что вы хотите. Это замена по умолчанию для массива C, и она работает как одна, но не переполняется. Вы можете установить его размер заранее, а также с помощью reserve().
Если вы хотите сохранить неопределенное количество объектов, но вы будете добавлять их и удалять, то вам, вероятно, нужен список... потому что вы можете удалить элемент, не перемещая никаких следующих элементов - в отличие от вектора. Это занимает больше памяти, чем вектор, но вы не можете последовательно обращаться к элементу.
Если вы хотите взять кучу элементов и найти только уникальные значения этих элементов, их чтение в набор будет делать это, и оно будет сортировать их для вас.
Если у вас много пар ключ-значение, и вы хотите отсортировать их по ключу, тогда карта полезна... но она будет содержать только одно значение за ключ. Если вам нужно больше одного значения за ключ, вы можете иметь вектор/список в качестве своего значения на карте или использовать мультимап.
Это не в STL, но он находится в обновлении TR1 для STL: если у вас много пар ключ-значение, которые вы собираетесь искать по ключу, и вам не все равно их порядок, вы можете использовать хэш - это tr1:: unordered_map. Я использовал его с Visual С++ 7.1, где он назывался stdext:: hash_map. Он ищет O (1) вместо поиска O (log n) для карты.
Я переработал блок-схему, чтобы иметь 3 свойства:
Более подробная информация предоставлена по этой ссылке.
Все зависит от того, что вы хотите сохранить и что вы хотите делать с контейнером. Вот некоторые (очень неисчерпывающие) примеры для классов контейнеров, которые я обычно использую больше всего:
vector
: Компактная компоновка с небольшими или отсутствующими издержками памяти для каждого содержащегося объекта. Эффективен для повторения. Добавление, вставка и стирание могут быть дорогими, особенно для сложных объектов. Дешево найти содержащийся объект по индексу, например. myVector [10]. Используйте, где бы вы использовали массив в C. Хорошо, где у вас много простых объектов (например, int). Не забудьте использовать reserve()
перед добавлением большого количества объектов в контейнер.
list
: небольшая нехватка памяти для каждого содержащегося объекта. Эффективен для повторения. Добавлять, вставлять и стирать дешево. Используйте, где бы вы использовали связанный список в C.
set
(и multiset
): значительная служебная нагрузка памяти для каждого содержащегося объекта. Используйте, где вам нужно быстро узнать, если контейнер содержит данный объект или эффективно слить контейнеры.
map
(и multimap
): Значительные издержки памяти для каждого содержащегося объекта. Используйте, где вы хотите сохранить пары ключ-значение и быстро найти значения по клавишам.
Блок-схема cheat sheet, предложенная zdan, содержит более исчерпывающий справочник.
Важным моментом, который только кратко упоминается до сих пор, является то, что если вам требуется непрерывная память (например, массив C), вы можете использовать только vector
, array
или string
.
Используйте array
, если размер известен во время компиляции.
Используйте string
, если вам нужно работать только с типами символов и вам нужна строка, а не только контейнер общего назначения.
Используйте vector
во всех остальных случаях (vector
должен быть выбором контейнера по умолчанию в любом случае).
Со всеми тремя из них вы можете использовать функцию члена data()
, чтобы получить указатель на первый элемент контейнера.
Один урок, который я усвоил: попытайтесь обернуть его в классе, поскольку изменение типа контейнера в один прекрасный день может принести большие сюрпризы.
class CollectionOfFoo {
Collection<Foo*> foos;
.. delegate methods specifically
}
Это не требует больших затрат и экономит время на отладку, когда вы хотите прервать работу, когда кто-то выполняет операцию x с этой структурой.
Приходя к выбору идеальной структуры данных для работы:
Каждая структура данных предоставляет несколько операций, которые могут быть различной временной сложности:
O (1), O (LG N), O (N) и т.д.
По сути, вам нужно сделать предположение, какие операции будут выполняться чаще всего, и использовать структуру данных, которая имеет эту операцию как O (1).
Просто, не правда ли (-:
Я расширил фантастическую блок-схему Микаэля Перссона. Я добавил некоторые категории контейнеров, контейнер массива и некоторые примечания. Если вам нужна ваша собственная копия, здесь является Google Drawing. Спасибо, Микаэль за работу! С++ Container Picker
Я ответил на это в другом вопросе, который помечен как дубликат этого. Но я чувствую, что приятно сослаться на некоторые хорошие статьи, касающиеся решения о выборе стандартного контейнера.
Как ответил @David Thornley, std :: vector - это то, что нужно, если нет других особых потребностей. Это совет, данный создателем C++ Бьярном Страуструпом в блоге 2014 года.
Вот ссылка на статью https://isocpp.org/blog/2014/06/stroustrup-lists
и цитата из этого,
И да, я рекомендую использовать std :: vector по умолчанию.
В комментариях пользователь @NathanOliver также предоставляет еще один хороший блог, в котором есть более конкретные измерения. https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html.