Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 132
Текст из файла (страница 132)
Например: оонЦ(11к1<згг!лу>й Ь, оес1ог<к1ггпу й оз) ( Гя. ког1 () /Г сортировка списка Ц Г 7.2.2. Ц илщие сору (ГзЬец~п (), ГзелсГ(), Ьасй Глкег1ег(ок~); ) Гз копируется в оз, и в процессе копирования одинаковые значения удаляются, срункция зог1 () нужна для того, чтобы одинаковые значения оказались соседними. Как и другие стандартные алгоритмы, алгоритм ипщие () работает с итераторами. Он не знает тип контейнера, на который указывают зти итераторы, и потому не может модифицировать контейнер. Он может только изменять значение элементов. 597 18.6. Алгоритмы, модифицирующие последовательность Это приводит к тому, что ип1дие () не удаляет одинаковые элементы во входной пос- ледовательности, как мы наивно могли бы предположить, а помещает уникальные элементы в начало последовательности и возвращает итератор на конец последова- тельности уникальных элементов: !ет р!а!в<с!азз Рог> Рог и лгпи е (Рог 1!зт, гог !аз 8 !!ге!=пшавел! Гшд(/)гз1,1азф //у !В.Ь2 ге!игл ипй!ие сору (/)гз1, !аз!,Ягзф ) Элементы за «уникальной» последовательностью остаются неизменными.
Поэтому в векторе одинаковые значения не удаляются: //осторожно. олагннп код! оо!с!Яоес!ою зйт'лу> & из) ( зог! (оз. Ьеу!и (), оз.елд ()); ипй1ие (оз. де у!и Щ оз.еле( Щ, ) // сортировка вектора // удаляет одинаковые значения? нет! Фактически, помещая последние элементы последовательности вперед, чтобы уда- лить одинаковые значения, ип!с/ие () может ввести новые одинаковые значения. На- пример, результатом !и! пии'л () ( сйаг о[] = 'аЬЬсссде'; сдпг* р = ил!уие (о, о+з!г1еп (о)); сои! «о « ' ' «р-о «ччп'; будет аЬсдесч!е Б !етр1а!е<с1азз С> ооЫ ейтша!е ч!ир!!са!ез (С& с) ( зог! (с.Ьедтл (), с.епс/()); 1урелате Ссйега!огр = ил!уие (с Ьеу!л (), с епд Щ; с егазе (р, с.ела Щ, ) 0 сортируем // сжимаем // укорачиваем Отметим, что функция е1!т!па!е с!ир!!са!ез () не имела бы смысла для встроенного массива, но ип!с/ие () можно применять и к массивам.
Примерил!с/ие сору() можно найти в З 3.8.3. То есть р укажет на второе с. Алгоритмы, которые могли бы удалить элементы (но не делают этого), в основном сводятся к двум формам: «простые» версии, перестраивающие элементы как ип1уие (), и версии, создающие новую последовательность, похожие на ип1уие сору(). Суффикс сору используется для того, чтобы различать зти два вида алгоритмов. Чтобы удалить из контейнера одинаковые элементы, мы должны явно сжать его: 598 Глава 18, Алгоритмы и объекты-функции 18.6.3.1. Критерии сортировки к!тобы удалить одинаковые значения, входную последовательность нужно отсортировать Я 18.7.1). Оба алгоритма, н ип!дие (), и ишдие сору () по умолчанию в качестве критерия для сравнения пользуются оператором == и позволяют пользователю ввести собственный критерий.
Например, мы могли бы изменить пример из Ь 18.5.1 так, *!тобы удалить одинаковые имена. После извлечения имен обслуживающего персонала из контейнера С!иЬ, мы бы остались со списком !1к1<Регкоп'>, названным оЯ' Я 18.5.1). Мы могли бы удалить одинаковые имена так: е!!т!лаге Мир!гса1ек (оЯ; Однако, такой метод основывается на сортировке указателей и предполагает, что каждый указатель однозначно определяет человека.
Вообще говоря, нам бы пришлось более внимательно отнестись к записям Регкоп, чтобы определить, будем ли мы считать их одинаковыми. Мы могли бы написать: // равенство для обьекгпов Ьоо! орега1ог== (сопягРегкопйх, сопк1Регзопйу) ( // сравниваем х и у на равенство // «лленьше» для объектов Ьоо! орега1ог< (сопя! Регзопй х, сопя! Регяопй у) //сравниваем хи у //равенство через указатель Ьоо! Рвгк оп ед (сопя! Регзоп* х, сопк1 Регкоп* у) ( ге1игп *х == *у // «меньше» через указатель Ьоо! Регкоп й(сопз1Регкоп'х,сопя!Рескин'у) ге1игп *х < *у, ) ио!«(ех1гас! апс! Рг!п1(сопя! ЕИ<Регкоп*>й !с) !!к1<Регяоср> оЯ; ех1гас1 (!с, оЯ; оЯкогг (Регкоп й); !!я!<с!иЬ>к!1егагог р = итдие (о//Ьеугп (), оДеп«! (), Регкоп ед); /ог еас!ь (о/УЬеугп (), р, Рпп! пате (сои!)); Выло бы разумно убедиться, что критерий равенства при сортировке совпадений тот же, что и при удалении одинаковых элементов.
Смысл по умолчанию = и < для указателей редко годится для сравнения объектов, на которые эти указатели указывают. 18.6.4. Алгоритмы гер(асе Ллп оритмы гер!асе () проходят по последовательности, заменяя указанные значения. Эти алгоритмы следуют моделиЯпс(фпс! сору и ип1дие/ип!дие сору, что дает четыре варнанта алгоритма. И снова, код достаточно прост и не требует пояснений: 599 18.6. Алгоритмы, модифицирующие последовательность 1етр!а1е<с1азк Рог, с1аяз Т> ооЫ гер1асе (Рогг)гз1, Рог 1акг, сопя! Тй оа1, соля! Тй пет оа!) ( тд11е (!)гвг!= 1аз1) ( (1' ('(ггз1 ==оп!) *У!гк1 = пет оа1, ++1) гкг; ) 1етр!а1е<с1авз Рог, с1акк Рге<1, с1азк Т> ооЫ гер1асе (1 (ГогЯк1 Рог !ав1, Ргеа р, сопк1 Тй оа1) ( той!1е (Г)гз1!= 1ав1) ( (Т (р(*,)!гзг)) '!)гкг= оа1; +>Л я1; ) ) гетрга1е<с(азз 1п, с1азк Ои1, с(азз Т> Ои1 гер(асе сору (ТлЛгв1, 1п !авг, Ои1 гея, сопз1 Тй оа!, солв1 Тй пеа! оа1) ( п1и1е (!)гкг!= !ак1) ( *~ ек.н- = ~*гсвг = =оа1) З пего иа1: *Т)гкг; +<у) гв1; ге1игл гез; гетр1а1е<с!акк 1л, с1акя Оиг, с1авз Ргег! с!аяз Т> Ои1 гергасе сору (г (Тот)гкг, Тп 1аз1, Ои1 гез, Реей р, сопя! Тй лего оа1) ( и!зйе (!)гк1 м гия1) ( *гев+ = р Д]гкг) 2 лекс оа! *йгк1; <->11гк1; ге1игл гез; Допустим нам понадобилось пройти по списку строк, заменяя обычную английскую транслитерацию имени моего родного города Ааглпк его истинным названием АгЬпя; ооЫХ)!1кг<к1пау>й 1огспз) гер(асе (гоилзоеу!п () 1огопкел<1()ГАаглик, ">!глаз"), Этот пример использует расширенный набор символов (9 В.З.З).
18.6.5. Алгоритмы гепто1ге Алгоритмы геглоое () перемещают элементы из последовательности, основываясь на значении или предикате: 1етр!а1е<с1акв Рог, с1азз Т Рог гетоое (Рог() гк1, Рог 1ак1, сопя! Тй оа)); 1етр!а1е<с1авз Рог, с!оке Рге<1> Рог гет осе (!(Рогргк1, Рог 1акг, Реей р), Глава 18, Алгоритмы и объекты-функции 800 1етрlа1еясlакк !л, сlазз Ои1 сlакк Т> Ои1 гетоое сору (1п)1 гз1 1п !азг, Оиг гея, солк1 Тй оа!), 1етрlа1еяс!аяя !и, сlаякОи1, с!аякР«ес!> Оиггетоое сору (Г(1пЯ«з1,1п !аз1, Оиггез,ргейр), Допустив, что С1иЬ (клуб) имеет адрес, мы можем создать список клубов с адресом в Копенгагене; с!аяя !оса1ес! ш:риЬИс ипату !ипсноп яС!иЬ, Ьоо!> ( кгг!лу 1отл; риЫ!с; !оса1ед т (сопя1 ясппуй зя); 1отл (зя) () Ьоо! орегаяог () (сопя!С!иуй с) солк1 ( ге!игл с.гота == 1огвп; ) иоЩ(!!к1чС!иЬ>й !с) (' гетоие сору (!(!с.Ьеу!и (),!с.елс!(), озггеат уега1огчСlиЬ> (сои!), пос! (!оса1ес! т ( КвЬелйаоп'))) Таким образом, алгоритм «стоне сору (1 () — это сору (1() Я 18.6.1) с обратным условием.
То есть элемент помещается алгоритмом «еспоое сору (1 () на выход, если он нс удовлетворяет предикату. «Простой>тетоне () записывает все несоответствующие элементы в начало последовательности и возвращает итсратор на конец этой уплотненной подпоследовательности (см. также 9 18.6.3). 18.6.6. Алгоритмы 1(П и делега1е Алгоритмы и!! () и депе«иге () созданы для того, чтобы систематически присваивать последовательностям значения: !етрlа1еяс!аяз Рог, с!аяз Т> ооЫ /П((Го«1) ге 1 Рог lаз1, сопя! Тй оаl), (етр!а1е<с!акк Оиг, с!акк Иге, сlакя Т> ооЫ)!!! п (Ои1 гея, Яее л, сон з1Тй са!); 1етр!а1еясlакк Рог, с!аяк бел> иоЫуелегаге (Ро«1!«к1, Рог !ая1, беп у), 1е~плр!а1е<с!акз Ои1, сlакк 5!ее, с!азз бел> ооЫуелега1е л (Ои1 гея, Яике л, беп у); Ллгоритмл(! () присваивает указанное значение, ззп оритм уелега1е () присваивает значения путем многократного вызова функции, являющейся его аргументом.
Таким образом,у) !! () — это просто специальный случай депе«иге (), в котором функция-генератор многократно возвращает одно и то же значение, Версии с суффиксом и производят присваивание только первым л элементам последовательности. Например, используя генераторы случайных чисел кгапйл1 и (1«апг( из Э 22 7, можно написать: !п1и!(900); !п1 о2(900); иес1ог оу; иоиЩ 11 присваиванве всем яяеиентам о! значения 99 Я!1(И, &о!(900),99); б01 18.6. Алгоритмы, модифицирующие последовательность // лрисваивание случайных значений !Я 22.7) уепега1е (и2, 8 и2(900], йапг!!п1 ()); // вывод 200 случайных Левых чисел: в интервале (0..99): уепега1е п(окйеат Вега1ог<!п1> (сои!),200, Пгапд(!00)), // см. 9 22.7 // добавляем в иу 20 клементов со значением 99 7<!! п (Ьасб !пзеггег(и2),20,991 Функции уепега1е () и2>12! () скорее присваивают, а не инициализируют.