C++. STL. Алгоритми. Алгоритми, які змінюють значення елементів послідовності

Модифікуючі алгоритми. Частина 1.
Алгоритми, які змінюють значення елементів послідовності


Зміст


Пошук на інших ресурсах:

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;
}

 


Споріднені теми