Чтение онлайн

ЖАНРЫ

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

std::remove_copy(lstStr.begin, lstStr.end, lstStr2, "cloudy");

При использовании

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

erase
и
remove
(и связанные с ними алгоритмы) предлагают удобный способ удалять определенные элементы последовательностей. Они предоставляют простую альтернативу самостоятельному перебору и поиску нужных элементов с последующим их удалением по одному.

Смотри также

Рецепты 6.2

и 7.1.

7.3. Случайное перемешивание данных

Проблема

Имеется последовательность данных и требуется перемешать их так, чтобы они были расположены в случайном порядке.

Решение

Используйте стандартный алгоритм

random_shuffle
, определенный в
<algorithm>
.
random_shuffle
принимает два итератора произвольного доступа и (необязательно) функтор генератора случайных чисел и реорганизует случайным образом элементы заданного диапазона. Пример 7.3 показывает, как это делается.

Пример 7.3. Случайное перемешивание последовательностей

#include <iostream>

#include <vector>

#include <algorithm>

#include <iterator>

#include "utils.h" // Для printContainer: см. 7.10

using namespace std;

int main {

 vector<int> v;

 back_insert_iterator<std::vector<int> > p = back_inserter(v);

 for (int i = 0; i < 10; ++i) *p = i;

 printContainer(v, true);

 random_shuffle(v.begin, v.end);

 printContainer(v, true);

}

Вывод должен выглядеть примерно так.

– ----

0123456789

– ----

8192057346

Обсуждение

random_shuffle
очень прост в использовании. Дайте ему диапазон, и он перемешает этот диапазон случайным образом. Имеется две версии, и их прототипы выглядят так.

void random_shuffle(RndIter first, RndIter last);

void random_shuffle(RndIter first, RndIter last, RandFunc& rand);

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

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

iterator_traits<RndIter>::difference_type
. В большинстве случаев для этого подойдет целое число. Например, вот мой псевдогенератор случайных чисел.

struct RanNumGenFtor {

 size_t operator(size_t n) const {

return(rand % n);

 }

} rnd;

random_shuffle(v.begin, vend, rnd);

Приложения

random_shuffle
ограничены последовательностями,
которые предоставляют итераторы случайного доступа (
string
,
vector
и
deque
), массивами или собственными контейнерами, удовлетворяющими этому требованию. Перемешать случайным образом ассоциативный контейнер невозможно, так как его содержимое всегда хранится в упорядоченном виде. На самом деле для ассоциативных контейнеров не всегда можно использовать алгоритм, изменяющий его диапазон (и который часто называется видоизменяющим (mutating) алгоритмом).

7.4. Сравнение диапазонов

Проблема

Имеется два диапазона и требуется сравнить их на равенство или определить, какой из них меньше, чем другой, основываясь на каком-либо порядке сортировки элементов.

Решение

В зависимости от типа выполняемого сравнения используйте один из стандартных алгоритмов —

equal
,
lexicographical_compare
или
mismatch
, определенных в
<algorithm>
. Пример 7.4 показывает некоторые из них в действии.

Пример 7.4. Различные типы сравнения

#include <iostream>

#include <vector>

#include <string>

#include <algorithm>

#include "utils.h"

using namespace std;

using namespace utils;

int main {

 vector<string> vec1, vec2;

 vec1.push_back("Charles");

 vec1.push_back("in");

 vec1.push_back("Charge");

 vec2.push_back("Charles");

 vec2.push_back("in");

 vec2.push_back("charge"); // Обратите внимание на строчную "с"

 if (equal(vec1.begin, vec1.end, vec2.begin)) {

cout << "Два диапазона равны!" << endl;

 } else {

cout << "Два диапазона HE равны!" << endl;

 }

 string s1 = "abcde";

 string s2 = "abcdf";

 string s3 = "abc";

 cout << boolalpha // Отображает логические значения как "true" или "false"

<< lexicographical_compare(s1.begin, s1.end,

s1.begin, s1.end) << endl;

 cout << lexicographical_compare(s1.begin, s1.end,

s2.begin, s2.end) << endl;

 cout << lexicographical_compare(s2.begin, s2.end,

s1.begin, s1.end) << endl;

 cout << lexicographical_compare(s1.begin, s1.end,

s3.begin, s3.end) << endl;

 cout << lexicographical_compare(s3.begin, s3.end,

s1.begin, s1.end) << endl;

 pair<string::iterator, string::iterator> iters =

mismatch(s1.begin, s1.end, s2.begin);

Поделиться с друзьями: