Выбрать главу

6.13.2. Поиск элемента

Две операции, позволяющие отыскать в наборе определенное значение, – это find() и count(). find() возвращает итератор, указывающий на найденный элемент, или значение, равное end(), если он отсутствует. count() возвращает 1 при наличии элемента и 0 в противном случае. Добавим проверку на существование в функцию build_word_map():

if ( exclusion_set.count( textword ))

continue;

// добавим отсутствующее слово

6.13.3. Навигация по множеству

Для проверки наших кодов реализуем небольшую функцию, выполняющую поиск по одному слову (поддержка языка запросов будет добавлена в главе 17). Если слово найдено, мы будем показывать каждую строку, в которой оно содержится. Слово может повторяться в строке, например:

tomorrow and tomorrow and tomorrow

однако такая строка будет представлена только один раз.

Одним из способов не учитывать повторное вхождение слова в строку является использование множества, как показано в следующем фрагменте кода:

// получим указатель на вектор позиций

loc ploc = (*text_map)[ query_text ];

// переберем все позиции

// вставим все номера строк в множество

set short occurrence_lines;

loc::iterator liter = ploc-begin(),

liter_end = ploc-end();

while ( liter != liter_end ) {

occurrence_lines.insert( occurrence_lines.end(),

(*liter).first );

++liter;

}

Контейнер set не допускает дублирования ключей. Поэтому можно гарантировать, что occurrence_lines не содержит повторений. Теперь нам достаточно перебрать данное множество, чтобы показать все номера строк, где встретилось данное слово:

register int size = occurrence_lines.size();

cout "\n" query_text

" встречается " size

" раз(а):")

"\n\n";

set short ::iterator it=occurrence_lines.begin();

for ( ; it != occurrence_lines.end(); ++it ) {

int line = -it;

cout "\t( строка "

line + 1 " ) "

(*text_file)[line] endl;

}

(Полная реализация query_text() представлена в следующем разделе.)

Класс set поддерживает операции size(), empty() и erase() точно таким же образом, как и класс map, описанный выше. Кроме того, обобщенные алгоритмы предоставляют набор специфических функций для множеств, например set_union() (объединение) и set_difference() (разность). (Они использованы при реализации языка запросов в главе 17.)

Упражнение 6.23

Добавьте в программу множество слов, в которых заключающее 's' не подчиняется общим правилам и не должно удаляться. Примерами таких слов могут быть Pythagoras, Brahms и Burne_Jones. Включите в функцию suffix_s() из раздела 6.10 проверку этого набора.

Упражнение 6.24

Определите вектор, содержащий названия книг, которые вы собираетесь прочесть в ближайшие шесть виртуальных месяцев, и множество, включающее названия уже прочитанных произведений. Напишите программу, которая выбирает для вас книгу из вектора при условии, что вы ее еще не прочитали. Выбранное название программа должна заносить в множество прочитанных. Однако вы могли отложить книгу; следовательно, нужно обеспечить возможность удалять ее название из множества прочитанных. По окончании шести виртуальных месяцев распечатайте список прочитанного и непрочитанного.

6.14. Окончательная программа

Ниже представлен полный текст программы, разработанной в этой главе, с двумя модификациями: мы инкапсулировали все структуры данных и функции в класс TextQuery (в последующих главах мы обсудим подобное использование классов), кроме того, текст был изменен, так как наш компилятор поддерживал стандарт С++ не полностью.

Например, библиотека iostream не соответствовала текущему стандарту. Шаблоны не поддерживали значения аргументов по умолчанию. Возможно, вам придется изменить кое-что в этой программе, чтобы она компилировалась в вашей системе.

// стандартные заголовочные файлы С++

#include algorithm

#include string

#include vector

#include utility

#include map

#include set

// заголовочный файл iostream, не отвечающий стандарту

#include fstream.h

// заголовочные файлы С

#include stddef.h

#include ctype.h

// typedef для удобства чтения