WikiDer > Контейнер последовательности (C ++)
Эта статья может требовать уборка встретиться с Википедией стандарты качества. Конкретная проблема: Смотрите разговор (Декабрь 2011 г.) (Узнайте, как и когда удалить этот шаблон сообщения) |
Стандартная библиотека C ++ |
---|
Контейнеры |
Стандартная библиотека C |
В вычислениях контейнеры последовательности относятся к группе контейнер шаблоны классов в стандартная библиотека из Язык программирования C ++ реализующие хранение элементов данных. Существование шаблоны, их можно использовать для хранения произвольных элементов, таких как целые числа или пользовательские классы. Общим свойством всех последовательных контейнеров является то, что к элементам можно обращаться последовательно. Как и все другие компоненты стандартной библиотеки, они находятся в пространство имен стандартное.
Следующие контейнеры определены в текущей версии стандарта C ++: множество
, вектор
, список
, forward_list
, дек
. Каждый из этих контейнеров реализует разные алгоритмы хранения данных, что означает, что они имеют разные гарантии скорости для разных операций:[1]
множество
реализует массив без изменения размера во время компиляции.вектор
реализует массив с быстрым произвольный доступ и возможность автоматического изменения размера при добавлении элементов.дек
реализует двусторонняя очередь со сравнительно быстрым произвольным доступом.список
реализует двусвязный список.forward_list
реализует односвязный список.
Поскольку каждый из контейнеров должен иметь возможность копировать свои элементы для правильного функционирования, тип элементов должен соответствовать Копировать
и Назначаемый
требования.[2] Для данного контейнера все элементы должны принадлежать к одному типу. Например, нельзя хранить данные в виде обоих char и int в одном экземпляре контейнера.
История
Эта секция нуждается в расширении. Вы можете помочь добавляя к этому. (Декабрь 2011 г.) |
Изначально только вектор
, список
и дек
были определены. До стандартизации языка C ++ в 1998 году они были частью Стандартная библиотека шаблонов (STL), опубликованный SGI.
В множество
контейнер сначала появился в нескольких книгах под разными названиями. Позже он был включен в Способствовать росту библиотека, и была предложена для включения в стандартную библиотеку C ++. Мотивация включения множество
заключалась в том, что он решает две проблемы массива в стиле C: отсутствие интерфейса, подобного STL, и невозможность копирования, как любой другой объект. Впервые он появился в C ++ TR1 а позже был включен в C ++ 11.
В forward_list
контейнер был добавлен в C ++ 11 как компактная альтернатива список
когда обратная итерация не нужна.
Характеристики
множество
, вектор
и дек
все поддерживают быстрый произвольный доступ к элементам. список
поддерживает двунаправленную итерацию, тогда как forward_list
поддерживает только однонаправленную итерацию.
множество
не поддерживает вставку или удаление элементов. вектор
поддерживает быструю вставку или удаление элементов в конце. Любая вставка или удаление элемента не в конце вектора требует, чтобы элементы между положением вставки и концом вектора были скопированы. В итераторы к затронутым элементам, таким образом, недействительны. Фактически, любая вставка потенциально может сделать недействительными все итераторы. Кроме того, если выделенное хранилище в вектор
слишком мал для вставки элементов, выделяется новый массив, все элементы копируются или перемещаются в новый массив, а старый массив освобождается. дек
, список
и forward_list
все они поддерживают быструю вставку или удаление элементов в любом месте контейнера. список
и forward_list
сохраняет действительность итераторов при такой операции, тогда как дек
делает их все недействительными.
Вектор
Элементы вектор
хранятся непрерывно.[3] Как все динамический массив реализации, векторы имеют низкое использование памяти и хорошие местонахождение ссылки и кеш данных утилизация. В отличие от других контейнеров STL, таких как дек и списки, векторы позволяют пользователю обозначать начальную емкость контейнера.
Векторы позволяют произвольный доступ; то есть на элемент вектора можно ссылаться так же, как на элементы массивов (по индексам массива). Связанные списки и наборы, с другой стороны, не поддерживают произвольный доступ или арифметику указателей.
Векторная структура данных способна быстро и легко выделить необходимую память, необходимую для конкретного хранилища данных, и сделать это за амортизированное постоянное время. Это особенно полезно для хранения данных в списках, длина которых может быть неизвестна до создания списка, но где удаление (кроме, возможно, в конце) редко. Удаление элементов из вектора или даже полная очистка вектора не обязательно освобождает какую-либо память, связанную с этим элементом.
Емкость и перераспределение
Типичная векторная реализация внутри состоит из указателя на динамически распределяется множество,[1] и, возможно, элементы данных, содержащие емкость и размер вектора. Размер вектора относится к фактическому количеству элементов, а емкость относится к размеру внутреннего массива.
При вставке новых элементов, если новый размер вектора становится больше его емкости, перераспределение происходит.[1][4] Обычно это приводит к тому, что вектор выделяет новую область памяти, перемещает ранее удерживаемые элементы в новую область хранения и освобождает старую область.
Поскольку адреса элементов изменяются во время этого процесса, любые ссылки или итераторы чтобы элементы в векторе стали недействительными.[5] Использование недействительной ссылки вызывает неопределенное поведение.
Для предотвращения ненужного перераспределения можно использовать операцию reserve (). После вызова функции Reserve (n) емкость вектора гарантированно будет не менее n.[6]
Вектор поддерживает определенный порядок своих элементов, так что, когда новый элемент вставляется в начало или в середину вектора, последующие элементы перемещаются назад с точки зрения их оператор присваивания или же конструктор копирования. Следовательно, ссылки и итераторы на элементы после точки вставки становятся недействительными.[7]
Векторы C ++ не поддерживают перераспределение памяти на месте намеренно; т.е. при перераспределении вектора память, которую он хранит, всегда будет скопирована в новый блок памяти с использованием конструктора копирования его элементов, а затем освобождена. Это неэффективно для случаев, когда вектор выполняется простые старые данные и дополнительное непрерывное пространство за пределами удерживаемого блока памяти доступно для распределения.
Специализация на bool
Стандартная библиотека определяет специализацию вектор
шаблон для bool
. Описание этой специализации указывает, что реализация должна упаковать элементы так, чтобы каждый bool
использует только один бит памяти.[8] Это широко считается ошибкой.[9][10] вектор
не соответствует требованиям для Стандартная библиотека C ++ контейнер. Например, контейнер
должно быть правдой lvalue типа Т
. Это не так с вектор
, который является прокси-класс конвертируемый в bool
.[11] Точно так же vector
не дает bool &
когда разыменованный. Комитет по стандартизации C ++ и Рабочая группа по библиотекам пришли к общему мнению, что вектор
должны быть исключены и впоследствии удалены из стандартной библиотеки, в то время как функциональность будет повторно введена под другим именем.[12]
Список
В список
структура данных реализует двусвязный список. Данные хранятся в памяти не непрерывно, что позволяет структуре данных списка избегать перераспределения памяти, которое может быть необходимо с векторами, когда новые элементы вставляются в список.
Структура данных списка выделяет и освобождает память по мере необходимости; следовательно, он не выделяет память, которую в данный момент не использует. Память освобождается при удалении элемента из списка.
Списки эффективны при вставке новых элементов в список; это операция. Сдвиг не требуется, как в случае с векторами.
Списки не имеют возможности произвольного доступа, как векторы ( операция). Доступ к узлу в списке - это операция, требующая обхода списка для поиска узла, к которому необходимо получить доступ.
С небольшими типами данных (такими как int) накладные расходы на память намного более значительны, чем у вектора. Каждый узел занимает размер(тип) + 2 * размер(тип*)
. Указатели обычно бывают одним слово (обычно четыре байта в 32-разрядных операционных системах), что означает, что список из четырех байтов целых чисел занимает примерно в три раза больше памяти, чем вектор целых чисел.
Переслать список
В forward_list
структура данных реализует односвязный список.
Deque
дек
- это шаблон класса контейнера, который реализует двусторонняя очередь. Он предоставляет аналогичные вычислительная сложность к вектор
для большинства операций, за исключением того, что он обеспечивает амортизированная постоянная вставка и удаление с обоих концов последовательности элементов. В отличие от вектор
, дек
использует несмежные блоки памяти и не предоставляет средств для управления емкостью контейнера и моментом перераспределения памяти. Нравиться вектор
, дек
предлагает поддержку итераторы произвольного доступа, а вставка и удаление элементов делает недействительными все итераторы в двухсторонней очереди.
Множество
множество
реализует неизменяемый размер во время компиляции множество. Размер определяется во время компиляции параметром шаблона. По конструкции контейнер не поддерживает распределители. В отличие от других стандартных контейнеров, множество
не обеспечивает постоянное время замена.
Обзор функций
Контейнеры определены в заголовках, названных по именам контейнеров, например вектор
определено в заголовке <vector>
. Все контейнеры соответствуют требованиям Контейнер концепция, что означает, что у них есть начинать()
, конец()
, размер()
, max_size ()
, пустой()
, и замена()
методы.
Функции-члены
Функции | множество (C ++ 11) | вектор | дек | список | forward_list (C ++ 11) | Описание |
---|---|---|---|---|---|---|
Основы | (скрытый) | (конструктор) | (конструктор) | (конструктор) | (конструктор) | Создает контейнер из множества источников |
(деструктор) | (деструктор) | (деструктор) | (деструктор) | Разрушает контейнер и содержащиеся в нем элементы | ||
оператор = | оператор = | оператор = | оператор = | Присваивает значения контейнеру | ||
Нет данных | назначать | назначать | назначать | назначать | Присваивает значения контейнеру | |
Распределители | get_allocator | get_allocator | get_allocator | get_allocator | Возвращает распределитель, используемый для выделения памяти для элементов. | |
Элемент доступ | в | в | в | Нет данных | Нет данных | Доступ к указанному элементу с проверкой границ. |
оператор [] | оператор [] | оператор [] | Доступ к указанному элементу без проверки границ. | |||
передний | передний | передний | передний | передний | Доступ к первому элементу | |
назад | назад | назад | назад | Нет данных | Доступ к последнему элементу | |
данные | данные | Нет данных | Нет данных | Доступ к базовому массиву | ||
Итераторы | начинать | начинать | начинать | начинать | начинать | Возвращает итератор в начало контейнера |
конец | конец | конец | конец | конец | Возвращает итератор в конец контейнера | |
rbegin | rbegin | rbegin | rbegin | Нет данных | Возвращает обратный итератор в обратное начало контейнера | |
раздирать | раздирать | раздирать | раздирать | Возвращает обратный итератор на обратный конец контейнера | ||
Емкость | пустой | пустой | пустой | пустой | пустой | Проверяет, пустой ли контейнер |
размер | размер | размер | размер | Нет данных | Возвращает количество элементов в контейнере. | |
max_size | max_size | max_size | max_size | max_size | Возвращает максимально возможное количество элементов в контейнере. | |
Нет данных | бронировать | Нет данных | Нет данных | Нет данных | Хранение резервов в таре | |
емкость | Возвращает количество элементов, которые могут храниться в выделенной в данный момент памяти. | |||||
Уменьшать до размеров | Уменьшать до размеров | Уменьшает использование памяти за счет освобождения неиспользуемой памяти (C ++ 11) | ||||
Модификаторы | Чисто | Чисто | Чисто | Чисто | Очищает содержимое | |
вставлять | вставлять | вставлять | Нет данных | Вставляет элементы | ||
поставить | поставить | поставить | Создает элементы на месте (C ++ 11) | |||
стереть | стереть | стереть | Стирает элементы | |||
Нет данных | push_front | push_front | push_front | Вставляет элементы в начало | ||
emplace_front | emplace_front | emplace_front | Создает элементы на месте в начале (C ++ 11) | |||
pop_front | pop_front | pop_front | Удаляет первый элемент | |||
отталкивать | отталкивать | отталкивать | Нет данных | Вставляет элементы до конца | ||
emplace_back | emplace_back | emplace_back | Создает элементы на месте в конце (C ++ 11) | |||
pop_back | pop_back | pop_back | Удаляет последний элемент | |||
Нет данных | Нет данных | Нет данных | insert_after | Вставляет элементы после указанной позиции (C ++ 11) | ||
emplace_after | Создает элементы на месте после указанной позиции (C ++ 11) | |||||
erase_after | Стирает элементы на месте после указанной позиции (C ++ 11) | |||||
изменить размер | изменить размер | изменить размер | изменить размер | Изменяет количество хранимых элементов | ||
замена | замена | замена | замена | замена | Меняет местами содержимое с другим контейнером того же типа | |
наполнять | Нет данных | Нет данных | Нет данных | Нет данных | Заполняет массив заданным значением |
Есть другие операции, которые доступны как часть класса списка, и есть алгоритмы, которые являются частью C ++ STL (Алгоритм (C ++)), который можно использовать с список
и forward_list
учебный класс:
Операции
list :: merge
иforward_list :: слияние
- Объединяет два отсортированных спискаlist :: splice
иforward_list :: splice_after
- перемещает элементы из другого спискаlist :: remove
иforward_list :: remove
- Удаляет элементы равные заданному значениюlist :: remove_if
иforward_list :: remove_if
- Удаляет элементы, удовлетворяющие определенным критериямlist :: reverse
иforward_list :: reverse
- Меняет порядок элементов на обратныйlist :: unique
иforward_list :: уникальный
- Удаляет последовательные повторяющиеся элементыlist :: sort
иforward_list :: sort
- Сортирует элементы
Функции, не являющиеся членами
Пример использования
В следующем примере демонстрируются различные методы с использованием вектора и Стандартная библиотека C ++ алгоритмы, в частности шаркающий, сортировка, найти самый большой элемент и стереть вектор с помощью стереть-удалить идиомы.
#включают <iostream>#включают <vector>#включают <array>#включают <algorithm> // sort, max_element, random_shuffle, remove_if, lower_bound #включают <functional> // больше#включают <iterator> // начало, конец, cbegin, cend, расстояние// используется здесь для удобства, разумно использовать в реальных программах. с помощью пространство имен стандартное;с помощью пространство имен стандартное::заполнители;авто главный(int, char**) -> int{ множество<int,4> обр{ 1, 2, 3, 4 }; // инициализируем вектор из массива вектор<int> числа( cbegin(обр), уступать(обр) ); // вставляем больше чисел в вектор числа.отталкивать(5); числа.отталкивать(6); числа.отталкивать(7); числа.отталкивать(8); // вектор в настоящее время содержит {1, 2, 3, 4, 5, 6, 7, 8} // случайным образом перемешиваем элементы random_shuffle( начинать(числа), конец(числа) ); // находим самый большой элемент, O (n) авто самый большой = max_element( cbegin(числа), уступать(числа) ); cout << «Наибольшее число» << *самый большой << " п"; cout << "Он находится в индексе" << расстояние(самый большой, cbegin(числа)) << " п"; // сортируем элементы Сортировать( начинать(числа), конец(числа) ); // находим позицию числа 5 в векторе авто пять = нижняя граница( cbegin(числа), уступать(числа), 5 ); cout << «Число 5 находится в индексе» << расстояние(пять, cbegin(числа)) << " п"; // стираем все элементы больше 4 числа.стереть( remove_if(начинать(числа), конец(числа), связывать(больше<>{}, _1, 4) ), конец(числа) ); // выводим все оставшиеся числа за(const авто& элемент : числа) cout << элемент << " "; возвращаться 0;}
Результат будет следующим:
Наибольшее число - 8, оно находится в индексе 6 (зависит от реализации). Число 5 - в индексе 41 2 3 4.
Рекомендации
- Уильям Форд, Уильям Топп. Структуры данных с C ++ и STL, Второе издание. Прентис Холл, 2002. ISBN 0-13-085850-1. Глава 4: Класс Vector, стр. 195–203.
- Йосуттис, Николай М. (1999). Стандартная библиотека C ++. Эддисон-Уэсли. ISBN 0-201-37926-0.
Примечания
- ^ а б c Йосуттис, Николай (1999). Стандартная библиотека C ++ - Учебное пособие и справочник. Эддисон-Уэсли.
- ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.1 Требования к контейнеру [lib.container.requirements] пункт 4
- ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.2.4 Вектор шаблона класса [lib.vector] пункт 1
- ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.2.4.3 векторные модификаторы [lib.vector.modifiers] пункт 1
- ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.2.4.2 емкость вектора [lib.vector.capacity] пункт 5
- ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.2.4.2 емкость вектора [lib.vector.capacity] пункт 2
- ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.2.4.3 векторные модификаторы [lib.vector.modifiers] пункт 3
- ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.2.5 Вектор класса
[lib.vector.bool] пункт 1 - ^ "vector
: больше проблем, лучшие решения" (PDF). Август 1999 г.. Получено 28 ноября 2017. - ^ "Спецификация, запрещающая vector
" . Март 2007 г.. Получено 28 ноября 2017. - ^ ISO/IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §23.2.5 Вектор классов
[lib.vector.bool] пункт 2 - ^ «96. Vector
не является контейнером» . Получено 28 июн 2018.