Модифицирующие алгоритмы. Часть 1.
Алгоритмы, изменяющие все элементы последовательности
Содержание
- 1. Алгоритм for_each. Выполнить операцию над каждым элементом последовательности.
- 2. Алгоритм transform. Выполнить действие для каждого элемента последовательности
- 3. Алгоритм fill. Заполнить диапазон нужными значениями
- 4. Алгоритм fill_n. Заполнить диапазон нужными значениями
- 5. Алгоритм generate. Выполнить операцию над каждым элементом последовательности
- 6. Алгоритм generate_n. Выполнить операцию над каждым элементом последовательности
- Связанные темы
Поиск на других ресурсах:
1. Алгоритм for_each. Выполнить операцию над каждым элементом последовательности.
Алгоритм for_each позволяет делать заданную операцию над каждым элементом последовательности. Эта операция задается функцией. Общая форма распространенной реализации алгоритма выглядит следующим образом
template <class InputIterator, class Function> Function for_each( InputIterator first, InputIterator last, Function func);
здесь
- first – итератор ввода, указывающий на первый элемент диапазона, над которым нужно выполнить операцию;
- last – итератор ввода, указывающий на последний элемент диапазона, над которым нужно выполнить операцию;
- func – функция, определяющая операцию.
Пример 1.
В примере каждый элемент вектора умножается на 2. Для умножения используется функция Mult2().
#include <iostream> #include <vector> #include <queue> #include <list> #include <algorithm> #include <functional> using namespace std; void Mult2(int& value) { value = value * 2; } void main() { // Алгоритм for_each. Выполнить операцию над каждым элементом последовательности // 1. Создать динамический массив vector<int> V = { 4, 8, 9, 2, 10, 15 }; // 2. Вызвать алгоритм for_each // Здесь используется функция Mult2() for_each(V.begin(), V.end(), Mult2); // каждый элемент вектора умножается на 2 // 3. Вывести результирующий массив vector<int>::iterator p1; p1 = V.begin(); while (p1 != V.end()) { cout << *p1 << " "; p1++; } cout << endl; }
Пример 2.
В нашем примере каждая строка списка list<string> реверсируется с помощью алгоритма for_each. Функция реверсирования Reverse().
#include <iostream> #include <list> #include <algorithm> #include <functional> using namespace std; // Функция реверсирующая строку void Reverse(string& s) { string s2 = ""; for (int i = 0; i < s.length(); i++) { s2 = s[i] + s2; } s.assign(s2); } void main() { // Алгоритм for_each. Выполнить операцию над каждым элементом последовательности // 1. Создать список строк list<string> L = { "abc", "def", "ghi", "jkl" }; // 2. Вызвать алгоритм for_each // Здесь используется функция Mult2() for_each(L.begin(), L.end(), Reverse); // кажый элемент списка реверсируется // 3. Вывести результирующий список list<string>::iterator it; it = L.begin(); while (it != L.end()) { cout << *it << endl; it++; } cout << endl; }
Результат
cba fed ihg lkj
⇑
2. Алгоритм transform. Выполнить действие для каждого элемента последовательности
Алгоритм transform позволяет задать операцию, выполняемую над каждым элементом последовательности или над парой элементов в двух выходных диапазонах. Операция может быть задана унарной или бинарной функцией. Объявление наиболее распространенных реализаций алгоритма имеет вид
template <class InputIterator, class OutputIterator, class UnaryFunction> OutputIterator transform( InputIterator first1, InputIterator last1, OutputIterator result, UnaryFunction func ); template <class InputIterator1, class InputIterator2, class OutputIterator, class BinaryFunction> OutputIterator transform( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryFunction func );
здесь
- first1, last1 – итераторы ввода, задающие первый выходной диапазон для обработки;
- first2 – итератор ввода, задающий второй диапазон для обработки;
- result – итератор вывода, указывающий на позицию первого элемента в диапазоне назначения;
- func – унарная или бинарная функция, задающая операцию, которую нужно выполнить над одним элементом или над несколькими элементами.
Пример.
#include <iostream> #include <list> #include <algorithm> using namespace std; // Предикат, выполняющий операцию над отдельным элементом последовательности, // умножить значение параметра value на 5 int Mult_5(int value) { return value * 5; } //Предикат, выполняющий операцию над двумя отдельными элементами. // Эти элементы могут быть из разных последовательностей. int Mult_AB(int a, int b) { return a * b; // вернуть произведение элементов } int main() { // Алгоритм transform – выполнить функцию для каждого элемента этой последовательности // 1. Использование алгоритма в сочетании с предикатом // 1.1. Создать последовательность чисел и вывести ее на консоль list<int> L1 = { 2, 8, 1, 4, 3, 5, 7, 0, -2, 6, 3 }; cout << "L1 => "; for (int i : L1) cout << i << " "; cout << endl; // 1.2. Создать другую последовательность размером исходной list<int> L2(L1.size()); // 1.3. Вызвать алгоритм transform для списка L1 на основе предиката Mult_5, // создается новая последовательность L2 transform(L1.begin(), L1.end(), L2.begin(), Mult_5); // 1.4. Вывести результирующую последовательность L2 cout << "L2 => "; for (int i : L2) cout << i << " "; cout << endl; // 2. Использование алгоритма на основе лямбда-выражения // 2.1. Создать последовательность L3 нулевых значений размером L1.size() list<int> L3(L1.size()); // 2.2. Создать вторую последовательность, каждый элемент которой // является умноженным на 2 – вызвать алгоритм transform transform(L1.begin(), L1.end(), L3.begin(), [](int a) { return a * 2; }); // 2.3. Вывести результирующую последовательность cout << "L3 => "; for (int i : L3) cout << i << " "; cout << endl; // 3. Использование алгоритма transform для выполнения операции над двумя последовательностями. // Необходимо умножить элементы последовательности L1 на элементы последовательности L2 // 3.1. Создать новую последовательность размером L1.size() list<int> L4(L1.size()); // 3.2. Заполнить последовательность L4 значениями L1[i]*L2[i] transform(L1.begin(), L1.end(), L2.begin(), L4.begin(), Mult_AB); // 3.3. Вывести последовательность L4 cout << "L1[i]*L2[i] => "; for (int i : L4) cout << i << " "; cout << endl; // 4. Использование алгоритма transform для выполнения операции над двумя последовательностями // на основе лямбда-выражения. // Получить новую последовательность, в которой добавляются поэлементно последовательности L1 и L2. // 4.1. Создать новую нулевую последовательность L5 размером L1.size(). list<int> L5(L1.size()); // 4.2. Заполнить последовательность L5 значениями L1[i]+L2[i] на основе лямбда-выражения. transform( L1.begin(), // начало L1 L1.end(), // конец L1, L1.end()-L1.begin() => это длина результирующей последовательности L2.begin(), // начало второй последовательности, прилагаемой к L1 L5.begin(), // начало результирующей последовательности [](int a, int b) { return a + b; } // лямбда-выражение, возвращающее сумму параметров a и b ); // 4.3. Вывести результирующую последовательность cout << "L1[i]+L2[i] => "; for (int i : L5) cout << i << " "; cout << endl; }
Результат
L1 => 2 8 1 4 3 5 7 0 -2 6 3 L2 => 10 40 5 20 15 25 35 0 -10 30 15 L3 => 4 16 2 8 6 10 14 0 -4 12 6 L1[i]*L2[i] => 20 320 5 80 45 125 245 0 20 180 45 L1[i]+L2[i] => 12 48 6 24 18 30 42 0 -12 36 18
⇑
3. Алгоритм fill. Заполнить диапазон нужными значениями
Алгоритм fill предназначен для присвоения каждому элементу в заданном диапазоне некоторого значения. Объявление алгоритма имеет вид
template <class ForwardIterator, class Type> void fill( ForwardIterator first, ForwardIterator last, const Type& value);
здесь
- first, last – прямые итераторы, используемые для задания диапазона;
- value – значение, которым заполняется диапазон.
Пример.
#include <iostream> #include <queue> #include <vector> #include <list> #include <functional> #include <algorithm> using namespace std; int main() { // Алгоритм fill - заполнить диапазон нужными значениями // 1. Объявление вектора из 5 элементов vector<int> V(5); // 2. Заполнить вектор значением 10 fill(V.begin(), V.end(), 10); // 3. Вывести вектор на экран cout << "V => "; for (int i : V) cout << i << " "; cout << endl; // 4. Объявить список из 10 элементов list<double> L(10); // 5. Заполнить список значением 5.0 fill(L.begin(), L.end(), 5.0); // 6. Вывести список на экран cout << "L => "; for (double d : L) cout << d << " "; cout << endl; }
Результат
V => 10 10 10 10 10 L => 5 5 5 5 5 5 5 5 5 5
⇑
4. Алгоритм fill_n. Заполнить диапазон нужными значениями
Алгоритм fill_n присваивает новое значение указанному количеству элементов в диапазоне начиная с определенного элемента.
Распространенная реализация алгоритма следующая
template <class OutputIterator, class Size, class Type> OutputIterator fill_n( OutputIterator first, Size count, const Type& value);
здесь
- first – итератор, указывающий на начало диапазона;
- count – количество присваиваемых элементов;
- value – значение, которое присваивается элементам диапазона.
Пример.
#include <iostream> #include <queue> #include <vector> #include <list> #include <functional> #include <algorithm> using namespace std; int main() { // Алгоритм fill - заполнить диапазон нужными значениями // 1. Объявить вектор из 5 элементов vector<int> V(5); // 2. Заполнить первые 3 элемента вектора значением 10 fill_n(V.begin(), 3, 10); // 3. Вывести вектор на экран cout << "V => "; for (int i : V) cout << i << " "; cout << endl; // 4. Объявить список из 10 элементов list<double> L(10); // 5. Заполнить первые 7 элементов списка значением 1.0 fill_n(L.begin(), 7, 1.0); // 6. Вывести список на экран cout << "L => "; for (double d : L) cout << d << " "; cout << endl; }
Результат
V => 10 10 10 0 0 L => 1 1 1 1 1 1 1 0 0 0
⇑
5. Алгоритм generate. Выполнить операцию над каждым элементом последовательности
Алгоритм generate присваивает значения каждому элементу в диапазоне создаваемым объектом функции. Общая форма алгоритма следующая
template <class ForwardIterator, class Generator> void generate( ForwardIterator first, ForwardIterator last, Generator gen);
здесь
- first, last – итераторы, определяющие диапазон обрабатываемых значений;
- gen – объект функции, вызываемой без аргументов для создания значений, присваиваемых каждому элементу в диапазоне.
Пример 1.
В примере с помощью лямбда-выражения записывается значение «abcd» в каждой строке списка L.
#include <list> #include <algorithm> #include <functional> using namespace std; void main() { // Алгоритм generate. Выполнить операцию над каждым элементом последовательности // 1. Создать список строк list<string> L = { "abc", "def", "ghi", "jkl" }; // 2. Вызвать алгоритм generate // Записать "abcd" в каждый элемент списка с помощью лямбда-выражения generate(L.begin(), L.end(), []() { return "abcd"; }); // 3. Вывести результирующий список list<string>::iterator it; it = L.begin(); while (it != L.end()) { cout << *it << endl; it++; } cout << endl; }
Пример 2.
В примере генерируется массив чисел 5.0 путём вызова функции Get5().
#include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std; // Функция, возвращающая число 5 double Get5() { return 5.0; } void main() { // Алгоритм generate. Выполнить операцию над каждым элементом последовательности // 1. Создать массив из 10 чисел vector<double> V(10); // 2. Вызвать алгоритм generate // Записать число в каждый элемент массива с помощью функции Get5() generate(V.begin(), V.end(), Get5); // 4. Вывести результирующий массив vector<double>::iterator it; it = V.begin(); while (it != V.end()) { cout << *it << " "; it++; } cout << endl; }
Результат
5 5 5 5 5 5 5 5 5 5
⇑
6. Алгоритм generate_n. Выполнить операцию над каждым элементом последовательности
Алгоритм generate_n присваивает значение заданному количеству элементов последовательности, которые были созданы объектом функции. Алгоритм возвращает позицию за последним присвоенным значением
template <class OutputIterator, class Diff, class Generator> void generate_n( OutputIterator first, Diff count, Generator gen);
здесь
- first – итератор, указывающий на начало диапазона;
- count – количество элементов, которым присваивается значение;
- gen – объект функции без аргументов, используемый для формирования значений.
Пример 1.
#include <iostream> #include <list> #include <algorithm> #include <functional> using namespace std; void main() { // Алгоритм generate_n. Выполнить операцию над каждым элементом последовательности // 1. Создать список строк list<string> L; // 2. Создать 5 пустых строк L.resize(5, ""); // 3. Вызвать алгоритм generate_n // Записать "abcd" в каждый элемент списка с помощью лямбда-выражения generate_n(L.begin(), L.size(), []() { return "abcd"; }); // 4. Вывести результирующий список list<string>::iterator it; it = L.begin(); while (it != L.end()) { cout << *it << endl; it++; } cout << endl; }
Пример 2.
В примере формируется массив случайных чисел, значение которых лежит в диапазоне [1; 10].
#include <iostream> #include <vector> #include <algorithm> #include <functional> #include <time.h> using namespace std; // Функция, возвращающая случайное число в пределах от 1 до 10 включительно int Get_1_10() { int value = rand() % 10 + 1; return value; } void main() { // Алгоритм generate_n. Выполнить операцию над каждым элементом последовательности // 1. Создать массив из 10 чисел vector<int> V(10); // 2. Инициализировать ядро для получения случайных значений srand(time(NULL)); // 2. Вызвать алгоритм generate_n // Записать число в каждый элемент массива с помощью функции Get_1_10() generate_n(V.begin(), V.size(), Get_1_10); // 4. Вывести результирующий массив vector<int>::iterator it; it = V.begin(); while (it != V.end()) { cout << *it << " "; it++; } cout << endl; }
⇑
Связанные темы
- Модифицирующие алгоритмы. Часть 2. Алгоритмы обмена значениями элементов последовательности. Алгоритмы swap, swap_ranges, iter_swap
- Модифицирующие алгоритмы. Часть 3. Алгоритмы выполняющие замену элементов последовательности. Алгоритмы replace, replace_if, replace_copy_if, replace_copy
- Модифицирующие алгоритмы. Часть 4. Алгоритмы, извлекающие из последовательности элементы или группы элементов: remove, remove_if, remove_copy, remove_copy_if, unique, unique_copy
- Модифицирующие алгоритмы. Часть 5. Алгоритмы, обрабатывающие последовательность в целом не изменяя значений элементов: copy, copy_backward, reverse, reverse_copy, rotate, rotate_copy, random_shuffle
⇑