МИНИСТРЕСТВО ПО РАЗВИТИЮ ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ И КОМУНИКАЦИЙ РЕСПУБЛИКИ УЗБЕКИСТАНА ТАШКЕНТСКИЙ УНИВЕРСИТЕТ ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ ИМЕНИ МУХАММАД АЛЬ-ХОРАЗМИЙ САМОСТОЯТЕЛЬНАЯ РАБОТА по дисциплине «Структуры данных и алгоритмов» На тему: «Контейнер QUEUE стандартной библиотеки шаблонов STL» Студента группы: _____ Выполнил: ____________ Принял: ______________ ТАШКЕНТ – 2022 Оглавление 1. Введение……………………………………………………………………..3 2. Основная часть………………………………………………………...……3 2.1. Контейнер QUEUE…………………………………………..…….8 3. Заключение…………………………………………………………………13 4. Источники…………………………………………………………………..14 1. Введение Практическая деятельность программистов в течение нескольких десятков лет привела к широкому распространению ряда способов организации структур данных, например, массив, список, очередь и т.д. Эти структуры данных стали стандартными. Для использования стандартных структур данных при решении различных задач была разработана стандартная библиотека шаблонов (англ. Standard Template Library), предназначенных для формирования контейнерных классов. Стандартная библиотека шаблонов до включения в стандарт C++ была сторонней разработкой, в начале — фирмы HP, а затем SGI. Стандартная библиотека шаблонов STL предоставляет шаблонные классы и функции общего назначения, которые реализуют многие популярные и часто используемые алгоритмы и структуры данных. Например, она включает поддержку векторов, списков, очередей и стеков, а также определяет различные процедуры, обеспечивающие доступ к этим объектам. Поскольку библиотека STL состоит из шаблонных классов, алгоритмы и структуры данных могут быть применены к данным практически любого типа. 2. Основная часть С точки зрения программиста, STL содержит подборку классов коллекций для различных целей, а также поддерживает ряд алгоритмов для работы с этими коллекциями. Все компоненты STL оформлены в виде шаблонов и поэтому могут использоваться с произвольными типами элементов. В библиотеке выделяют пять основных компонентов: 1. Контейнер (container) — хранение набора объектов в памяти. 2. Итератор (iterator) — обеспечение средств доступа к содержимому контейнера. 3. Алгоритм (algorithm) — определение вычислительной процедуры. 4. Адаптер (adaptor) — адаптация компонентов для обеспечения различного интерфейса. 5. Функциональный объект (functor) — сокрытие функции в объекте для использования другими компонентами. Разделение позволяет уменьшить количество компонентов. Например, вместо написания отдельной функции поиска элемента для каждого типа контейнера обеспечивается единственная версия, которая работает с каждым из них, пока соблюдаются основные требования. STL обладает рядом преимуществ: Код библиотеки написан профессиональными программистами, проверен и отлажен. Вам не придётся искать ошибки в реализации контейнеров или алгоритмов STL. Скорее, ошибки будут связаны с неверным пониманием концепций STL, но это вопрос опыта использования. Код библиотеки написан очень эффективно с точки зрения использования оперативной памяти и быстродействия для типовых вариантов применения. Библиотека предлагает унифицированный интерфейс, однообразный для всех контейнеров и алгоритмов, что после получения навыка использования библиотеки позволяет значительно повысить читаемость программы. Использование библиотеки позволяет приступить сразу к решению проектных задач, не задумываясь о реализации низкоуровневых контейнеров и алгоритмов. В случае работы проектной группы это позволяет избежать дублирования кода у различных разработчиков. Библиотека хорошо документирована и описана в книгах. В случае разработки собственных контейнеров и алгоритмов документация будет, скорее всего, значительно беднее, что повысит стоимость подготовки нового специалиста. Код, написанный с использованием STL легко переносится на другие компиляторы, операционные системы и платформы. К недостаткам STL можно отнести: Неприспособленность к работе со структурными типами данных. Низкая эффективность (быстродействие, память) при решении частных задач, где возможны целевые оптимизации кода. Неадекватный интерфейс шаблона для работы со строками Сложность управления пулом памяти при работе с контейнерами STL. Рассмотрим контейнеры библиотеки STL. Контейнеры — это структуры данных такие как списки, очереди и так далее. Доступ к данным, находящимся внутри контейнера, осуществляется с помощью итераторов. Каждый контейнер предоставляет строго определённый интерфейс, через который с ним будут взаимодействовать алгоритмы. Этот интерфейс обеспечивают соответствующие контейнеру итераторы. Важно подчеркнуть, что никакие дополнительные функции-члены для взаимодействия алгоритмов и контейнеров не используются. Это сделано потому, что стандартные алгоритмы должны работать, в том числе со встроенными контейнерами языка C++, у которых есть итераторы (указатели), но нет ничего, кроме них. Таким образом, при создании собственного контейнера реализация итератора - необходимый минимум. Каждый контейнер реализует определённый тип итераторов. При этом выбирается наиболее функциональный тип итератора, который может быть эффективно реализован для данного контейнера. "Эффективно" означает, что скорость выполнения операций над итератором не должна зависеть от количества элементов в контейнере. Например, для вектора реализуется итератор с произвольным доступом, а для списка - двунаправленный. Поскольку скорость выполнения операции для списка линейно зависит от его длины, итератор с произвольным доступом для списка не реализуется. Вне зависимости от фактической организации контейнера (вектор, список, дерево) хранящиеся в нём элементы можно рассматривать как последовательность. Итератор первого элемента в этой последовательности возвращает функция begin(), а итератор элемента, следующего за последним, функция end(). Это очень важно, так как все алгоритмы в STL работают именно с последовательностями, заданными итераторами начала и конца. Кроме обычных итераторов в STL существуют обратные итераторы (reverse iterator). Обратный итератор отличается тем, что просматривает последовательность элементов в контейнере в обратном порядке. Другими словами, операции + и - у него меняются местами. Это позволяет применять алгоритмы как к прямой, так и к обратной последовательности элементов. Например, с помощью функции find можно искать элементы как "с начала", так и "с конца" контейнера. Контейнеры библиотеки STL можно разделить на четыре категории: последовательные, ассоциативные, контейнеры-адаптеры и псевдоконтейнеры. Последовательные контейнеры vector C - подобный динамический массив произвольного доступа с автоматическим изменением размера при добавлении/удалении элемента. Доступ по индексу за O(1). Добавление-удаление элемента в конец vector занимает амортизированное O(1) время, та же операция в начале или середине vector — O(n). Стандартная быстрая сортировка за O(n * log(n)). Поиск элемента перебором занимает O(n). Существует специализация шаблона vector для типа bool, которая требует меньше памяти за счёт хранения элементов в виде битов, однако она не поддерживает всех возможностей работы с итераторами. list двусвязный список, элементы которого хранятся в произвольных кусках памяти, в отличие от контейнера vector, где элементы хранятся в непрерывной области памяти. Поиск перебором медленнее, чем у вектора из за большего времени доступа к элементу. Доступ по индексу за O(n). В любом месте контейнера вставка и удаление производятся очень быстро - за O(1). deque Дэк. Контейнер похож на vector, но с возможностью быстрой вставки и удаления элементов на обоих концах за O(1). Реализован в виде двусвязанного списка линейных массивов. Ассоциативные контейнеры set Упорядоченное множество уникальных элементов. При вставке/удалении элементов множества итераторы, указывающие на элементы этого множества, не становятся недействительными. Обеспечивает стандартные операции над множествами типа объединения, пересечения, вычитания. Тип элементов множества должен реализовывать оператор сравнения operator< или требуется предоставить функцию-компаратор. Реализован на основе самобалансирующего дерева двоичного поиска. multiset то же что и set, но позволяет хранить повторяющиеся элементы. map упорядоченный ассоциативный массив пар элементов, состоящих из ключей и соответствующих им значений. Ключи должны быть уникальны. Порядок следования элементов определяется ключами. При этом тип ключа должен реализовывать оператор сравнения operator<, либо требуется предоставить функцию-компаратор. multimap то же что и map, но позволяет хранить несколько одинаковых ключей. Контейнеры-адаптеры stack Стек — контейнер, в котором добавление и удаление элементов осуществляется с одного конца. queue Очередь — контейнер, с одного конца которого можно добавлять элементы, а с другого — вынимать. priority_queue Очередь с приоритетом, организованная так, что самый большой элемент всегда стоит на первом месте. Псевдоконтейнеры bitset Служит для хранения битовых масок. Похож на vector<bool> фиксированного размера. Размер фиксируется тогда, когда объявляется объект bitset. Итераторов в bitset нет. Оптимизирован по размеру памяти. basic_string Контейнер, предназначенный для хранения и обработки строк. Хранит в памяти элементы подряд единым блоком, что позволяет организовать быстрый доступ ко всей последовательности. Элементы должны быть POD'ами. Определена конкатенация с помощью +. valarray Шаблон оптимизирован служит для для достижения хранения числовых повышенной массивов и вычислительной производительности. В некоторой степени похож на vector, но в нём отсутствует большинство стандартных для контейнеров операций. Определены операции над двумя valarray и над valarray и скаляром (поэлементные). Эти операции возможно эффективно реализовать как на векторных процессорах, так и на скалярных процессорах с блоками SIMD. В контейнерах для хранения элементов используется семантика передачи объектов по значению. Другими словами, при добавлении контейнер получает копию элемента. Если создание копии нежелательно, то используют контейнер указателей на элементы. Присвоение элементов реализуется с помощью оператора присваивания, а их разрушение происходит с использованием деструктора. 2.1. Контейнер QUEUE Очередь (англ. queue) - это структура данных, в которой доступ осуществляется только к самому раннему добавленному элементу. Новые элементы добавляются в конец очереди, а удаляются из начала очереди. В STL есть специальный контейнер queue, который реализует подобную функциональность. Для заголовочный файл queue: #include<queue> его использования необходимо подключить Объявляется очередь, например, целых чисел так: queue <int> S; В очереди, если вы добавите элемент, который вошел самый первый, то он выйдет тоже самым первым. Получается, если вы добавите 4 элемента, то первый добавленный элемент выйдет первым. Чтобы понять принцип работы очереди вы можете представить себе магазинную очередь. И вы стоите посреди нее, чтобы вы оказались напротив кассы, сначала понадобится всех впереди стоящих людей обслужить. А вот для последнего человека в очереди нужно, чтобы кассир обслужил всех людей кроме него самого. На рисунке находятся 7 чисел: 2, 4, 7, 1, 4, 9, 10. Если нам понадобится их извлечь, то извлекать мы будем в таком же порядке как они находятся на рисунке! Так, например, чтобы извлечь число 4 нам понадобится сначала обслужить число 2, а потом уже и само число 4. Хотя в стеке присутствует функция peek() (она позволяет обратится к элементу по индексу), в шаблоне очереди невозможно обратится к определенному элементу. Но если вам нужно иметь доступ ко всем элементам очереди, то можете реализовать очередь через массив. Чуть ниже рассмотрим, как это сделать. Как создать очередь в С++ Если вы хотите использовать шаблон очереди в C++, то вам сначала нужно подключить библиотеку — <queue>. Дальше для объявления очереди нужно воспользоваться конструкцией ниже. queue <тип данных> <имя>; Сначала нам нужно написать слова queue. Дальше в <тип данных> мы должны указать тот тип, которым будем заполнять нашу очередь. И в конце нам остается только указать название очереди. Вот пример правильного объявления: queue <int> q; Методы очереди Метод — это та же самая функция, но она работает только с контейнерами STL. Например, очередь и стек. 1. Для работы с очередью понадобится знать функции: push(), pop(), front(), back(), empty(). 2. Для добавления в очередь нового элемента нужно воспользоваться функцией — push(). В круглых скобках должно находится значение, которое мы хотим добавить. 3. Если нам понадобилось удалить первый элемент нужно оперировать функцией pop(). В круглых скобках уже ничего не нужно указывать, но по правилам они в обязательном порядке должны присутствовать! Эти функции тоже не нуждаются в указании аргумента: empty(), back() и front(). 4. Если вам понадобилось обратиться к первому элементу очереди, то вам понадобится функция front(). 5. Чтобы обратиться к последнему элементу в очереди вам поможет функция back(). 6. Чтобы узнать пуста ли очередь нужно воспользоваться функцией empty(). Если ваша очередь пуста — возвратит true. Если же в ней что-то есть — возвратит false. Ниже мы использовали все вышеперечисленные методы: Создание очереди с помощью массива Как мы говорили выше, очередь можно реализовать через массив. Обычно, если кто-то создает такую очередь, то массив называют queue. Мы бы также назвали массив, но это уже зарезервированное слова в C++. Поэтому его назовем так, как назвали выше шаблон очереди — q. Для реализации нам понадобится создать две дополнительные переменные start и ends. start будет указывать на первый элемент очереди, a ends на последний элемент. Чтобы обратится к последнему элементу нам придется использовать эту конструкцию — queue[ends]. Обращение к первому элементу будет выглядеть аналогично queue[start]. Если понадобится удалить элемент из очереди, то придется всего лишь уменьшить переменную start на один. «А как же проверить пуста ли очередь?» — спросите вы. Для этого мы просто проверим условие start == ends: Если результатом условия будет true, то очередь пуста. Если же результат условия false, значит очередь чем-то заполнена. Ниже находится живой пример создания такой очереди: Очередь с приоритетом Очередь с приоритетом (priority_queue) — это обычная очередь, но в ней новый элемент добавляется в то место, чтобы очередь была отсортирована по убыванию. Так самый большой элемент в приоритетной очереди будет стоять на первом месте. Для объявления шаблона очереди с приоритетом нужно использовать конструкцию ниже: priority_queue <тип данных> <имя>; В начале нужно написать priority_queue. Потом в скобках указать тип данных, который будет находится в очереди. И конечно же в самом конце мы должны дать ей имя. Для добавления элемента в очередь с приоритетом мы должны использовать функцию push(). Но чтобы обратится к первому элементу должны использоваться именно функция — top() (как и в стеке). А не функция — front(). Также нельзя использовать функцию back() для обращения к последнему элементу. Для приоритетной очереди она также не работает, как функция front(). Вот пример использования очереди с приоритетом в программе: 3. Заключение Сегодня мы изучили два способа реализации очереди: Реализация через шаблон C++. Реализация через массив. Какой же вид создания очереди использовать? Можно использовать первый способ реализации очереди. Он работает быстрее чем второй способ и реализация совсем простая. К достоинствам библиотеки шаблонов STL можно отнести то, что библиотека действительно является кроссплатформенной. И это не пустая декларация, как происходит со многими другими технологиями. Я думаю, что существует больше платформ, не поддерживающих Java, чем компиляторов C++ для этих же платформ, не поддерживающих STL. Конечно, не существует абсолютной гарантии, что она встроена абсолютно во все компиляторы C++. Например, некоторые компиляторы для мобильных устройств и микроконтроллеров не включают эту библиотеку. Это обусловлено тем, что она является относительно неэффективной в плане использования памяти, поскольку оптимизирована для обеспечения максимальной скорости. В мобильных устройствах, как известно, самый дорогой ресурс - это память, в то время как на вашем PC сегодня его в избытке. Поэтому иногда придётся писать шаблонные классы, похожие на классы STL, самостоятельно для того, чтобы например перенести приложение, работающее под Windows или Linux на мобильное устройство. 4. Источники https://wreferat.baza-referat.ru/ https://studfile.net/ https://works.doklad.ru/ https://www.skachatreferat.ru/ https://codelessons.ru/ http://www.codenet.ru/