Программирование >>  Унарные и бинарные операторы 

1 ... 5 6 7 [ 8 ] 9 10 11 ... 37


Листинг 4.11

#include <iostream> include <fstream> #include <string> include <algorithtn> include <niap> using namespace std: int main(){ int n:

char buff[80]; string sbuff:

multimap<string.string> an;

multimap<string. string >::iterator im.am.ane;

ifstream infileCdiction ):

while (1) {

infile.getlineCbuff. sizeofCbuff)): ifCinfile.eofO) break; sbuffbuff:

sort С sbuff.beg i n().sbu ff.end С));

an.insertCpai r<string.string>Csbuff. buff));

ani=ane=an.beginC):

n=0:

whileC++ane != an.endC) &&

C*ane).first == C*ani).first) n++: ifCn){

forCim=ani: im!=ane; im++)

cout C*im).second endl: n=0: cout endl:

ani=ane: } whileCane !-an.endC)): infile.closeC); }

Основная структура данных в этой программе - контейнер an, объявляемый инструкцией: multimap<string.string> an:

Далее в программе создаются итераторы im, ani, ane, помогающие двигаться от одной пары строк, хранимой в контейнере, к другой.

Затем открывается файл diction, содержании! английские слова (его тоже можно найти на сайте издательства Питер www.piter.com среди исходных текстов программ).

Теперь все готово к заполнению ко1гтейнсра. Делается это в цикле whileCl){}. Первая инструкция в цикле читает очередную строку из словаря и сохраняет ее в массиве buff. Далее функция infile.eofC) проверяет, удачно ли считаг1а очередная строка. Отрицательный результат говорит о том, что мы вышли за границу (5анла, то есть все слова прочитаны, и пора выходить из цикла (делает это инструкция break). Если же конец файла не достигнут, прочитанное слово переписывается в строку sbuff, и следующая инструкция расставляет буквы в этой строке по алфавиту (сортирует):

sort С sbu ff.beg i п С).sbuff.end С)):

Теперь у нас есть желагшая пара: отсортированное слово (в строке sbuff) и нетронутое слово (в массиве buff). Для отправки этой пары в коптейггср использует- ся функция insertO:

an.insertCpair<string.string>(sbuff.buff)):

Обратите внимание: перед записью Csbuff .buff) стоит описание pair<string.string>, говорящее компилятору, что в контейнер засылается пара строк.

Мы дошли до конца цикла whileC){}, но так и не поняли, где же сортируется сам контейнер. Оказывается, функция insertO устроена так, что автоматически вставляет очередную пару строк в нужное место, и контейнер огсазывается отсортированным по ключу sbuff на любом этапе создания.

Казалось бы, с окончанием цикла whileC){} все самое страшное позади. Остается только вывести на экран слова с одинаковым ключом, хранимом в эле-Менте sbuff. Ноименпоэта задача и оказывается самой



СЛОЖНОЙ - по той причине, что, занимгшсь поиском элементов с одинаковым ключом, нужно все время опасаться выхода за пределы контейнера. Одно HCBepFFoe движение - и программа аварийно завершится.

Но давайте по порядку. Первым делом нужно обнулить счетчик анаграмм п и гюдготовить два итератора - ani и апе. Итератор ani будет указывать на первый элемент коьггейнера, содержащий анаграмму, апе - на элемент, сравниваемый с первым. В чачгте вывода оба итератора равны an.beginC). За поиск очередной анафаммы отвечает цикл:

while(++ane !- an.endO &&

(*ane).first == (*an1).first) n++:

Чтобы лучше понять, как работает механизм поиска анаграмм, представим себе, что в самом начале контейнера расположены две анаграммы - gateway и gela-\vay (рис. 4.1).

aaegiwy Eau; aj naegivvy geiaway

Рис. 4.1. Поиск анаграмм

Перед поиском итераторы ani и апе указывают на начало контсйггера. Далее апе увеличивается при проверке условия ++апе != an.endO и указывает теперь на элемент контейнера <aaegtwy .getaway>, после чего проверяется условие (*ane).first=- (*ani).first), и ггоскольку оба ключа (*ane).first и (*ani).first равны, условие выполняется, п увеличивается, становится равным единице, и мы вновь переходим к проверке условия ++апе !-an.endO. Раз мы в начале контейнера, условие вынол-няется, а итератор апе указывает на элемент, стоящи!* непосредственно за последовательностью из двух ана-

грамм. Его ключ иной, поэтому условие (*апе).first == (*ani).first) не выполняется, и мы переходим к условной инстру кци и i f( п), стоящей непосредственно за ци к-ЛOMwhile().

В этот момент п=1. Это указывает Fia то, что найдены две анаграммы. Любое отличное от нуля число соответствует значению истина . Поэтому условие if(n) выполняется, и на экран выводятся только что 1гайдснные анафаммы. Делает это следующий цикл:

for( ini=ani: im != апе: im++) cout (*im).second endl:

Затем n обращается в ноль (n=0), переводится строка (cout endl:), чтобы отделить одпу группу анаграмм от другой, значение ani снова становится равным апе - и все готово к поиску новых анаграмм.

Теперь самое время вспомнить о том, что контейнер не бесконечен и, занимаясь поиском анаграмм, нужно постоянно проверять, не достигну г ли его конец. Этой цели служит до сих нор не встречавшийся нам цикл:

do {} whileCane !=an.end())

Этот цикл обрамляет инструкции поиска анаграмм и вывода их на экран. Цикл do {} whileO отличается от цикла while О {} тем, что проверка условия происходит после выполнения цикла. Это значит, что цикл do{ }whi 1е() выполняется, по крайней мере, один раз. Чтобы понять, почему необходим этотвнентий цикл, представим себе, Что при проверке ++апе != an.end() обнаружен выход ите-

Итераторы, позволяющие передвигаться по контейнеру multimap, необычные. Они указывают па элемент контейнера, состоящий из двух частей - ктюча (например, aaegtwy ) и строки (например, gatcway -). Для доступа к первой части элемента (ключу) используется выражение ( ani).first, для доступа ко второй части - выражение (*ani).second. Поскольку такая запись встречается довольно часто, для пес придумано специальное сокращение: вместо (*ani).first пишется ani->first.



ратора апе за иредельг коггтейнера. Сразу прекращать работу нельзя, потому что значение п может быть отлично от нуля и нужно еще вывести на экраи последнюю анаграмму. Но если убрать проверку апе !=an.end() в конце цикла do{} wtii 1е(), при следую]Цсй проверке ++апе != an.endC) итератор апе будет указывать на несуществующий элемент, следующий за an. end(), то есть итератор апе нико1ла уже не станет равным an.endO, наши проверки окажутся бесполезными и все пойдет враз1юс !

Задача, решенггая в этом разделе, на порядок сложнее всего того, что нам встречалось до сих нор. Но все-таки в ней стоит разобраться - если не сейчас, то спустя некоторое время. Прежде всего потому, что она настоящая , очень похожая на те, что приходится решать про(])сссиональным программистам. Эта .задача - своеобразный тест. Тот, кто легко сможет в ней разоб])агь-ся, зря читает эту книжку. Немедленно прекратите и отдайте книгу менее искушенному товарип1у.

ГЛАВА 5 Функции, указатели и ссылки




1 ... 5 6 7 [ 8 ] 9 10 11 ... 37

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика