augue velit cursus nunc,.
12 words: Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus.
17 words: Maecenas tempus, tellus eget condimentum rhoncus,
sem quam semper libero, sit amet adipiscing sem neque sed ipsum.
Как это работает
Весь этот пример посвящен разбиению большой строки на предложения, после чего мы определяем их длину и помещаем в контейнер multimap
в упорядоченном виде. Поскольку контейнер std::multimap
сам по себе прост в использовании, сложной частью программы является цикл, который проходит по всем предложениям:
const auto end_it (end(content));
auto it1 (begin(content)); // (1) Начало строки
auto it2 (find(it1, end_it, '.')); // (1) Первая точка '.'
while (it1 != end_it && std::distance(it1, it2) > 0) {
string sentence {it1, it2};
// Что-то делаем со строкой предложения...
it1 = std::next(it2, 1); // Один символ справа от текущей точки '.'
it2 = find(it1, end_it, '.'); // Следующая точка или конец строки
}
Взглянем на код, имея при этом в виду следующий рисунок, на котором приведены три предложения (рис. 2.5).
Итераторы it1
и it2
всегда перемещаются вперед по строке вместе. Таким образом, они всегда указывают на начало и конец одного и того же предложения. Алгоритм std::find
заметно облегчает нам жизнь, поскольку работает по принципу «начинаем с текущей позиции, а затем возвращаем итератор, указывающий на следующий символ точки. Если такого итератора нет, то возвращаем конечный итератор».
После извлечения строки с предложением определим, сколько слов в ней содержится, а затем вставим ее в контейнер multimap
. Мы используем количество слов в качестве ключа для элементов массива, а саму строку — как объект, связанный с данным ключом. Мы не можем воспользоваться контейнером std::map
, так как предложений одинаковой длины может быть довольно много. Но это не проблема, поскольку мы задействуем контейнер std::multimap
, который легко справляется с совпадающими ключами. Данный контейнер хранит ключи в упорядоченном виде, что позволяет нам вывести предложения в порядке возрастания их длины.
Дополнительная информация
После того как мы считали весь файл в одну большую строку, мы проходим по ней и создаем копию каждого предложения. Однако это не обязательно, ведь можно воспользоваться std::string_view;
данный вопрос мы рассмотрим далее в книге.
Еще один способ получить строки между двумя соседними точками — задействовать класс std::regex_iterator
, который мы также рассмотрим несколько позже.
Реализуем личный список текущих дел с помощью std::priority_queue
Класс std::priority_queue
— еще один класс-адаптер для контейнеров, как и std::stack
. Он является оболочкой для другой структуры данных (по умолчанию это std::vector
) и предоставляет для нее интерфейс очереди. Т.е. элементы можно помещать туда и выталкивать оттуда пошагово. Все, что было помещено туда раньше, раньше очередь и покинет. Обычно данный принцип обозначается как FIFO (first in, first out — «первый вошел — первый вышел»). Он полностью противоположен принципу работы стека, где последний помещенный элемент будет вытолкнут первым.
Несмотря на то что мы описали, как работает контейнер std::queue
, в текущем разделе будет показана работа контейнера std::priority_queue
. Он особенный, поскольку не только имеет характеристики FIFO, но и объединяет их с приоритетами. Иными словами, содержимое, по сути, разбивается на подочереди, работающие по принципу FIFO, которые упорядочены в соответствии с указанным для них приоритетом.
Как это делается
В данном примере мы создадим простую структуру, которая может служить в качестве списка текущих дел. Для сокращения программы мы не будем анализировать входные данные и сконцентрируемся на std::priority_queue
. Поэтому просто заполняем очередь с приоритетом на основе неупорядоченного списка элементов, имеющих приоритет и описание. Затем считываем их как из структуры данных, работающей по принципу очереди FIFO, где все элементы сгруппированы по приоритетам отдельных элементов.
1. Сначала включим некоторые заголовочные файлы. Контейнер std::priority_queue
располагается в заголовочном файле <queue>
:
#include <iostream>
#include <queue>
#include <tuple>
#include <string>