}
Обсуждение
list— это последовательность, обеспечивающая постоянную сложность операций вставки и удаления элементов в произвольную позицию, но обладающая линейной сложностью их поиска. Обычно listреализуется как двухсвязный список, что означает, что каждый элемент хранится в узле, содержащем указатели на предыдущий и следующий элементы последовательности. Он обеспечивает все требования к контейнеру стандартной последовательности, полюс предоставляет несколько уникальных методов.
Объявление listне вызывает сложностей — просто укажите тип элементов, которые в нем будут храниться, и, опционально, класс распределителя памяти.
list
typename Allocator = allocator > // Используемый распределитель
// памяти
Параметр шаблона Value— это тип элементов, которые будут храниться в list. Это должен быть тип, который поддерживает конструктор копирования и присвоение. Allocator— это используемый класс распределителя памяти. По умолчанию используется стандартный распределитель (и в большинстве случаев его вполне достаточно).
Далее приведено типичное объявление list(см. пример 6.5).
list lstOne;
После объявления списка поместите в него что-нибудь с помощью push_frontили push_back, как здесь.
lstOne.push_back("Red"); // Добавление элементов в конец списка
lstOne.push_back("Green");
lstOne.push_back("Blue");
lstTwo.push_front("Orange"); // Добавление элементов в начало
lstTwo.push_front("Yellow");
lstTwo.push_front("Fuschia");
Помещение элементов в listзанимает постоянное время, а не амортизированное постоянное время , как в случае с vector. Реализации listне требуется периодически изменять размер буфера, так что в них не будет возникать периодических падений производительности, как при использовании vector. listпросто должен обновить набор указателей, и больше ничего.
Для удаления элементов из начала или конца listиспользуйте pop_frontили pop_back(без аргументов). Несмотря на их имя, методы «pop» не возвращают извлекаемый элемент, как это можно ожидать, исходя из обычной семантики стеков.
Обычно listвыглядит так, как показано на рис. 6.2. Каждый узел содержит (по меньшей мере) три части: объект, в нем содержащийся, указатель на предыдущий узел и указатель на следующий узел. В оставшейся части рецепта я буду ссылаться на указатели на следующий и предыдущий узлы как next_и prev_.
Рис. 6.2. Список с двунаправленными связями
Когда вы увидите, как реализован list, станет очевидно, почему некоторые операции имеют сложность, отличную от их сложности для vector. Добавление элемента в любое место listтребует только изменения указателей next_и prev_предыдущего и следующего элементов. Приятным моментом в listявляется то, что при вставке и удалении элементов в помощью insertи eraseустаревают значения только тех итераторов, которые указывают на затрагиваемый(е) объект(ы). Итераторы для других элементов не теряют актуальности.
Методы вставки и удаления — это insertи erase, insertв качестве первого аргумента принимает итератор, а в качестве второго — либо объект типа T, либо количество и затем объект типа T, либо начальный и конечный итераторы. Первый аргумент-итератор указывает на элемент, непосредственно перед которым должна произойти вставка. Перегрузки insertиспользуются вот так.
list strlst;
list::iterator p;
// ...
string s = "Scion";
p = find(strLst.begin(), strLst.end(), // std::find из
"Toyota");
strLst.insert(p, s); // Вставить s сразу перед p
strLst.insert(p, 16, s); // Вставить 16 копий s непосредственно перед p
strLst insert(p, myOtherStrLst.begin(), // Вставить все, что содержится
myOtherStrLst.end()); // в myOtherStrLst, перед p
Удаление элементов аналогично.
p = find(strLst.begin(), strLst.end(), // std::find из
"Toyota");
strLst1.erase(p); // Удаляем этот элемент
strLst2.erase(p, strLst.end()); // Удаляем от p до конца
strLst3.clear(); // Удаляем все элементы
В дополнение к методам стандартных контейнеров listпредоставляет несколько своих. Первый — это splice.
spliceделает то, что означает его имя: он объединяет два listв один. Вот как можно объединить lstTwoс lstOneиз примера 6.5.
Читать дальше