Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Программирование – 2 курс осень 2020 – 6 занятие

ТиМПИ
October 07, 2020

Программирование – 2 курс осень 2020 – 6 занятие

ТиМПИ

October 07, 2020
Tweet

More Decks by ТиМПИ

Other Decks in Education

Transcript

  1. dscs.pro spbu.ru 2/27 Обобщённые алгоритмы? Обобщённые алгоритмы (generic algorithms) —

    алгоритмы, применимые к различным контейнерам различных типов.
  2. dscs.pro spbu.ru 3/27 Контейнеры Контейнер (container) — это шаблонный тип,

    хранящий в себе коллекцию элементов заданного типа. Последовательные контейнеры (sequence containers) — это типы контейнеров, которые позволяют контролировать порядок, в котором хранятся элементы и предоставляется доступ к ним. • Определены в библиотеке Standard Template Library, в пространстве имён std; • Осуществляют эффективное управление памятью; • Объединены единым интерфейсом.
  3. dscs.pro spbu.ru 4/27 Пример 1. std::vector<T> #include <iostream> #include <vector>

    using namespace std; int main() { vector<int> vec = { 1, 1, 2, 3, 5 }; vec.push_back(vec[vec.size() - 1] + vec[vec.size() - 2]); for (auto i = 0; i < vec.size(); i++) { cout << vec[i] << endl; } return 0; }
  4. dscs.pro spbu.ru 5/27 Типы контейнеров Типы Доступ к элементу Вставка

    в начало Вставка в конец Вставка в произвольное место Удаление из начала Удаление из конца Удаление из произвольног о места std::vector / std::string O(1) O(N) O(1) O(N) O(N) O(1) O(N) std::list / std::forward _list Начало / конец / по итератору: O(1); Индекс: O(N) O(1) O(1) по итератору: O(1); Индекс: O(N) O(1) O(1) по итератору: O(1); Индекс: O(N) std::deque O(1) O(1) O(1) O(N) O(1) O(1) O(N) Таблица 1. Сложность различных операций с контейнерами.
  5. dscs.pro spbu.ru 6/27 Вопрос 1. Контейнеры. Почему типы контейнеров не

    определяют функций вроде sort, find, fill, for_each, etc.? Такой подход очень плохо масштабируется: ➢ Функции придётся определять для каждого контейнера; ➢ Если мы решим написать новый контейнер, реализацию этих функций придётся написать заново; ➢ Пользователю придётся писать свои реализации этих функций.
  6. dscs.pro spbu.ru 7/27 Итераторы Итератор (iterator) — тип, объекты которого

    синтаксически ведут себя, как указатели на элементы контейнера. • Можно получить посредством функций cbegin(), begin(), cend(), end(); • Как контейнеры обладают общим интерфейсом; • Поддерживают операторы инкремента и декремента (кроме случаев, когда не поддерживают; • Поддерживают операторы сравнения (==, >=, <=, >, <); • iterator поддерживает запись, в то время, как const_iterator поддерживает только чтение.
  7. dscs.pro spbu.ru 8/27 Пример 2. Итераторы #include <iostream> #include <vector>

    using namespace std; int main() { vector<int> vec = { 1, 1, 2, 3, 5 }; auto it = vec.cbegin(); cout << *it << endl; it += 3; cout << *it << endl; it--; cout << *it << endl; return 0; }
  8. dscs.pro spbu.ru 9/27 cbegin() cend() crbegin() crbegin() cbegin() cend() crbegin()

    crbegin() crbegin() + 5 (crbegin() + 5).base Реверсивный оператор
  9. dscs.pro spbu.ru 10/27 Пример 3. Инверсия слов. int main() {

    string word = "foobar"; cout << string(word.crbegin(), word.crend()); return 0; }
  10. dscs.pro spbu.ru 11/27 std::istream_iterator<T> • istream_iterator<T> in_iterator(in_stream) — создаёт итератор,

    читающий значения из потока in_stream. • istream_iterator<T> in_iterator — конструктор по умолчанию создаёт итератор, указывающий на конец потока. • Для чтения из потока используется оператор инкремента, который читает следующее значение, используя оператор >>, определённый для потока. • Можно создать для любого типа, в котором определён оператор >>.
  11. dscs.pro spbu.ru 12/27 std::ostream_iterator<T> • ostream_iterator<T> out_iterator(out_stream) — создаёт итератор,

    пишущий значения в поток out_stream. • Запись в поток осуществляется посредством оператора присваивания =. • Операторы *out_iterator, ++out_iterator, out_iterator++ определены, но возвращают только out_iterator.
  12. dscs.pro spbu.ru 13/27 Пример 4. Потоковые итераторы int main() {

    istream_iterator<int> in(cin), eof; ostream_iterator<int> out(cout); vector<int> v(in, eof); for (auto e : v) { out = e * 10; } return 0; }
  13. dscs.pro spbu.ru 14/27 Итераторы вставки Функция вставки inserter insert back_inserter

    push_back front_inserter push_front Итераторы вставки — специальные итераторы, которые служат для записи новых элементов в контейнер при помощи адаптеров inserter, back_inserter, front_inserter. • Вызов *it = elem; вставляет место, на которое ссылается итератор элемент elem.
  14. dscs.pro spbu.ru 15/27 Категории итераторов Категория Характеристика Итератор ввода Обеспечивает

    чтение, но не запись; поддерживает только инкремент. Итератор вывода Обеспечивает запись, но не чтение; поддерживает только инкремент. Прямой итератор Обеспечивает чтение и запись; поддерживает только инкремент. Двунаправленный итератор Обеспечивает чтение и запись; поддерживает инкремент и декремент. Итератор произвольного доступа Обеспечивает чтение и запись; поддерживает любые операции итераторов.
  15. dscs.pro spbu.ru 16/27 Библиотека <algorithm> Библиотечные функции, реализующие обобщённые алгоритмы

    определены в заголовке <algorithm>: • Содержит более 100 функций, которые служат для обработки коллекций элементов; • Содержит заголовок <numeric>, в котором определен набор обобщённых числовых алгоритмов; • Имеет единообразную структуру; • В качестве параметров функции библиотеки принимают итераторы;
  16. dscs.pro spbu.ru 17/27 Алгоритмы только для чтения vector<string> dic =

    { "Some", "body", "once", "told", "me", "the", "world" }; auto res = find(dic.begin(), dic.end(), "me"); string f = "SNAFUBAR"; string l = std::accumulate(f.crbegin(), f.crend(), string("")); Примеры: find, find_if, accumulate, equal…
  17. dscs.pro spbu.ru 18/27 Примеры: fill, fill_n, copy, replace, replace_copy… vector<int>

    v; auto inserter = back_inserter(v); fill_n(inserter, 10, 0); vector<int> v; fill_n(v.begin(), 10, 0); vector<int> v1 = {1, 1, 2}; vector<int> v2; copy(v1.begin(), v1.end(), back_inserter(v2)); Записывающие алгоритмы
  18. dscs.pro spbu.ru 19/27 Примеры: sort, sort_stable, unique… int main() {

    vector<string> dic = { "Some", "body", "once", "told", "me", "the", "world" }; sort(dic.begin(), dic.end()); for (auto a : dic) { cout << a << endl; } return 0; } Алгоритмы переупорядочивания
  19. dscs.pro spbu.ru 20/27 Предикаты Предикат (predicate) — это допускающее вызов

    выражение, возвращающее значение, применимое в условии. int main() { vector<string> dic = { "Some", "body", "once", "told", "me", "the", "world" }; sort(dic.begin(), dic.end(), firstShorter); for (auto a : dic) { cout << a << endl; } return 0; } bool firstShorter(string first, string second) { return first.size() < second.size(); }
  20. dscs.pro spbu.ru 21/27 Лямбда-выражения [=]() mutable throw() -> int {...};

    1 2 3 4 5 6 1. Список захваченных переменных; 2. Список параметров; 3. Модификатор mutable или constexpr (опционально); 4. Модификатор throw() (опционально); 5. trailing-return-type (опционально); 6. Тело лямбда-выражения.
  21. dscs.pro spbu.ru 22/27 int func() { vector<string> dic = {

    "Some", "body", "once", "told", "me", "the", "world" }; sort(dic.begin(), dic.end(), [](string a, string b) {return a.size() < b.size(); }); for (auto a : dic) { cout << a << endl; } return 0; } Пример 5. Лямбда-выражения
  22. dscs.pro spbu.ru 23/27 Захват переменных int func() { int a

    = 0, b = 0, c = 0, d = 0; return […]() {return a + b + c; }(); } […] Результат [] Ошибка: нельзя ссылаться на локальную переменную в теле лямбды. [=] a, b, c захвачены по значению. [&] a, b, c захвачены по ссылке. [=, &a, &b] a, b захвачены по ссылке, все остальные переменные в теле лямбды — по значению. [&, c] с захвачена по значению, все остальные переменные в теле лямбды — по ссылке.
  23. dscs.pro spbu.ru 24/27 Пример 6. Захват по ссылке int main()

    { auto a = 0, b = 0, c = 0, d = 0; auto f = [&a, b, &c, d] {return 1000 * a + 100 * b + 10 * c + d; }; a = 2; b = 2; c = 2; d = 2; cout << f(); return 0; }
  24. dscs.pro spbu.ru 25/27 #include <functional> int main() { auto e

    = 4; auto func = [](int a, int b, int c, int d, int e) {return a + b + c + d + e; }; auto binded_func = bind(func, 1, placeholders::_1, e, placeholders::_3, placeholders::_2); cout << binded_func(0, 0, 0); return 0; } Функция bind()
  25. dscs.pro spbu.ru 26/27 Структура библиотеки Все алгоритмы в библиотеке следуют

    единым правилам формулирования сигнатур: 1. Большинство алгоритмов следуют следующим формам: 1. alg(beg, end, parameter_list); 2. alg(beg, end, dest, parameter_list); 3. alg(beg, end, beg2, parameter_list); 4. alg(beg, end, beg2, end2, parameter_list); 2. Если алгоритм использует операторы == или < и не имеет других параметров, диапазона, то этот алгоритм перегружается следующим образом: alg(beg, end); alg(beg, end, predicate); 3. Если алгоритм получает значение элемента, то обычно у этого алгоритма есть версия с суффиксом _if, которая принимает предикат. 4. Некоторые алгоритмы имеют копирующие версии, обозначенные суффиксом _copy.