Анимация
JavaScript
|
Главная Библионтека Как обычно, алгоритм сору() продолжает работать до тех пор, пока первый (наращиваемый) аргумент не сравняется со вторым аргументом. Конечный потоковый итератор определяет конец обрабатываемого интервала; следовательно, алгоритм будет читать все строки из с(п до тех пор, пока дальнейшее чтение станет невозможным (из-за достижения конца потока данных или из-за ошибки). Подведем итог: источником данных для алгоритма сору() являются «все слова из cin*-. Прочитанные слова копируются в соН конечным итератором вставки. Алгоритм sort() сортирует все содержимое коллекции: sort Ccoll .beginO. coll.endO): Наконец, следующая команда копирует все элементы коллекции в приемник cout; unique copy (coll.beginO. coll.endO. ostreafn iteratQr<string>(CQut."\n")); В процессе копирования алгоритм unique copy исключает из копируемых данных дубликаты. Представленное ниже выражение создает потоковый итератор вывода, который записывает string в выходной поток данных cout, вызывая оператор << для каждого элемента: ostream iterator<5tring>(cout. "Лп")); Второй аргумент определяет разделитель, выводимый между элементами. Передавать этот аргумент не обязательно. В нашем примере разделителем является символ новой строки, поэтому каждый элемент будет выводиться в отдельной строке. Все компоненты программы реализованы в виде шаблонов, поэтому программа легко адаптируется для сортировки других типов данных (например, целых чисел или более сложных объектов). На с. 281 эта тема рассматривается более подробно и поясняется дополнительными примерами использования потоковых итераторов ввода-вывода. В нашем примере для сортировки всех слов в стандартном входном потоке данных понадобились одно объявление и три команды. Однако аналогичного результата можно добиться всего одним объявлением и одной командой. Пример приведен на с. 232. Обратные итераторы Третей разновидностью итераторных адаптеров STL являются обратные итераторы. Эти итераторы работают в противоположном направлении: вызов оператора -и- на внутреннем уровне преобразуется в вызов оператора --, и наоборот. Все контейнеры поддерживают создание обратных итераторов функциями rbeginO и rend(). Рассмотрим следующий пример: stl/riterl.cpp #include <iostream> #include <vector> linclude <algorith[n> using namespace std; 1nt mainO { vector<int> col 1: Вставка элементов со значениями от 1 до 9 for (int 1=1: i<=9: ++i) { coll,push back(i); Вывод всех элементов в обратном порядке сору (coll .rbeginO . coll.rendO. Источник ostream 1terator<1nt>(cout." ")); Приемник cout « endl: Выражение coll.rbegin() возвращает обратный итератор для коллекции coll. Полученный итератор может использоваты:я, чтобы начать обратный перебор элементов коллекции, поскольку он устанавливается на последний элемент коллекции. Таким образом, выражение *coll.rbegin() возвращает значение последнего элемента. Соответственно выражение coll.rend() возвращает обратный итератор для коллекции соП, который может использоваться для завершения перебора в обратном направлении. По аналогии с обычными интервалами он устанавливается за концом интервала, но в противоположном направлении - то есть перед первым элементом коллекции. Значение выражения *coll.rend() не определено, как, впрочем, и значение *coll.end(). Никогда не используйте операторы * и -> с позициями, пе представляющими реальных элементов коллекции. Основное достоинство обратных итераторов заключается в том, что все алгоритмы получают возможность работать в обратном направлении без модификации кода. Переход к следующему элементу оператором ++ преобразуется в переход к предыдущему элементу оператором -. В нашем примере алгоритм сору() перебирает все элементы соП от последнего к первому, поэтому результат работы программы выглядит так: 9 8 7 6 5 4 3 2 1 «Нормальные» итераторы можно переключать в режим обратного перебора и наоборот. Однако следует помнить, что при этом изменяется текущий элемент, связанный с итератором. Дополнительная информация об обратных итераторах приводится на с. 270. Модифицирующие алгоритмы Некоторые алгоритмы изменявэт содержимое своих приемных интервалов. В частности, возможно удаление элементов. При этом необходимо учитывать некоторые обстоятельства, которые будут описаны в этом разделе. Происходящее порой выглядит довольно странно, но это неизбежное следствие архитектуры STL, основанной на гибком разделении контейнеров и алгоритмов. «Удаление» элементов Алгоритм removeO удаляет элементы из заданного интервала. Но если вызвать его для всех элементов контейнера, происходит нечто неожиданное. Пример: stl/removel.cpp #1nclude <1ostrearn> #include <list> #1nclude <algor1thm> using namespace std: Int mainC) ( l1st<int> coll: Вставка элементов со значениями от 6 до 1 и от 1 до 6 for (int 1=1; 1<=6; ++1) { coll,push front(i); coll.push back(i): Вывод всех элементов коллекции cout « "pre; ": copy (coll.beginO. coll.endO. Источник ostream iterator<1nt>(cout." ")); Приемник cout « endl; Удаление всех элементов со значением 3 remove (coll.beginO. coll.endO, Интервал 3); Значение Вывод всех элементов коллекции cout « "post: "; copy (coll.beginO, coll.endO. Источник ostream iterator<int>(cout." ")); Приемник cout « endl; При поверхностном знакомстве с предметом напрашивается предположение, что эта программа удаляет из коллекции все элементы со значением 3. Но на самом деле результат выглядит так: pre; 654321123456 post: 654211245656 Алгоритм removeO не изменил количество элементов в коллекции, для которой он вызывался. Функция end() возвращает прежнее значение, а функция 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 [ 34 ] 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |