Контейнер последовательности (C ++) - Sequence container (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.