1 / 44

Предпоследнее д.з.

Предпоследнее д.з. 1. Кто больше всех зарабатывает?. struct person { string name; int salalry; }; vector<person> persons; int max = 0; // Вводим и запоминаем все for (;;) { person p; cin >> p.name; if (p.name == "*") break; cin >> p.salalry; persons.push_back(p);.

Download Presentation

Предпоследнее д.з.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Предпоследнее д.з. 1

  2. Ктобольше всех зарабатывает? struct person { string name; int salalry; }; vector<person> persons; int max = 0; // Вводим и запоминаем все for (;;) { person p; cin >> p.name; if (p.name == "*") break; cin >> p.salalry; persons.push_back(p); // Ищем максимумif (p.salary> max) max = p.salalry; } // Печатаем for(auto it = persons.begin(); it != persons.end(); it++) { if (it->salalry == max) cout<< it->name; } Варианты: • Один проход • хранить список самых богатых • Стандартные функции • sort • еще?

  3. shared_string class shared_string { char* p; // lenдля краткости не используем // Воспомогaтельные методы // Поставить указатель p на // данную строку и увеличить // в ней счетчик. void set_ptr(char * newp) { p = newp; (*newp)++; } // Уменьшить счетчик в строке, // на которую указывает p. // Если надо, удалить строку. void drop_ptr() { (*p)--; if (*p == 0) { cout << "Deleting " << p + 1; delete [] p; } } public: 3

  4. shared_string - продолжение shared_string(const char* s = "") { p = new char[strlen(s)+2]; *p = 1; strcpy(p + 1, s); } ~shared_string() { drop_ptr(); } shared_string(const shared_string& from) { set_ptr(from.p); } shared_string& operator= (const shared_string& from) { if (p != from.p) { drop_ptr(); set_ptr(from.p); } return *this; } void print() const { cout << p+1; } }; // Конец определения класса 4

  5. shared_string - замечания 1 2 "abc" Называется: reference counting (счетчик ссылок) Похожая вещь: smart pointers (умные указатели). shared_ptrв новой стандартной библиотеке(позже пройдем) Еще вариант – non-intrusive (храним счетчики отдельно от самих объектов) 5

  6. Последнее д.з. 6

  7. foreach для дерева void foreach(tree* p, function<void (int&)> f) { if (p == nullptr) return; f(p->val); foreach(p->left, f); foreach(p->right, f); } // Пример вызова foreach(t, [] (int& i) { i *= 2; }); foreach(t, [] (int& i) { cout << i; }); // Пример со списком захвата int k; cin >> k; foreach(t, [k] (int& i) { i *= k; });

  8. Пятерки – вариант 1, не совсем правильный map<string, int> fives; string name; int n, grade; cin >> n; for (int i = 0; i<n; i++) { cin >> name >> grade;// Читаем имяи оценкуif (grade == 5)fives[name]++;// Увеличиваем счетчик } // (или можно find и insert) // Печатаем ответ for (auto p = fives.begin(); p != fives.end(); p++) { cout << p->first << " - " << p->second << "\n"; } • Не печатает людей без пятерок..

  9. Пятерки – правильные варианты • Более правильно, например, так: cin >> name >> grade; int& num = fives[name]; // Если человека не было, добавит if (grade == 5) // Если пятерка num++; • Еще вариант: cin >> name >> grade; fives[name] += (grade == 5);

  10. Еще про ассоциативные контейнеры 10

  11. multimap #include <map> … multimap<double, int> m; Может быть несколько значений для одного ключа m.insert(make_pair(4.5, 2)); m.insert(make_pair(4.5, 8)); [] не работает find возвращает первую пару См. также: set multiset unordered_map unordered_set(используют хэш таблицы) boost::multi_index(несколько индексов) 11

  12. Д.з.про шаблоны 12

  13. Шаблон swp template <class T> void swp(T& x, T& y) { T tmp = x; x = y; y = tmp; } Замечание: T tmp; // Так хуже, чем T tmp = x; tmp = x; - Немного медленнее - Работает только если в классе есть конструктор по умолчанию (более существенно!) Новый критерий качества: про шаблоны мы хотим, чтобы они были, по возможности, более общими. 13

  14. Реализация swp для string class string { char* p; int len; public: friend void swp(string& x, string& y); … }; void swp(string& x, string& y) { swp(x.p, y.p); swp(x.len, y.len); } Используем общий шаблон swp 14

  15. Замечание Когда мы пишем шаблоны – это мы пишем код, который работает для разных типов. Называется: полиморфизм • Статический полиморфизм • (А динамический полиморфизм – это наследование и виртуальные функции) 15

  16. Как лучше писать шаблоны алгоритмов для работы с контейнерами? 16

  17. // Вариант 0 template <class T> void print(T c) { … обязательно надо передавать по ссылке! // Вариант 1a template <class T> void print(T& c) { T::iterator p; for (p = c.begin(); p != c.end(); p++) cout << *p << " "; } // Вариант 1б - исправленный template <class T> void print(T& c) { typename T::iterator p; for (p = c.begin(); p != c.end(); p++) cout << *p << " "; } // Пример вызова list<int> l; vector<string> v; … print(l); print(v); Д.з. про шаблон для печати - 1 17

  18. // Вариант 1в – const correctness template <class T> void print(const T& c) { typename T::const_iterator p; for (p = c.begin(); p != c.end(); p++) cout << *p << " "; } // Вариант 1г – C++11 template <class T> void print(const T& c) { for (auto p = c.begin(); p != c.end(); p++) cout << *p << " "; } // Вариант 1д – C++11 template <class T> void print(const T& c) { for (auto& x: c) cout << x << " "; } Д.з. про шаблон для печати - 2 18

  19. Д.з. про шаблон для печати - 3 // Вариант 2 template <class T> void print(T from, T to) { for (T p = from; p != to; p++) cout << *p << " "; } // Пример вызова vector<int> v; list<string> l; … print(v.begin(), v.end()); print(l.begin(), l.end()); Преимущества: • Можно вызывать не только для всего контейнера print(v.begin() +2, v.end()-3); • Очень мало требует от T Только *, ++, !=. int a[10]; … print(a, a+10); Недостатки: • Дольше писать 19

  20. Алгоритмы STL 20

  21. Пример • max_element(итератор начала, итератор конца); #include <algorithm> … vector<int> v; … Заполняем v … int m = max_element(v.begin(), v.end()); 21

  22. Итераторы и алгоритмы STL • Весь интерфейс алгоритмов - через итераторы Схема: Контейнеры  Итераторы  Алгоритмы "Алгоритмы и контейнеры хорошо работают вместе, потому что ничего не знают друг о друге“ • Вопрос: а как жеremove(v.begin(), v.end(), k);- на самом деле ничего не удаляет, только перемещает элементы, содержащие k в конец Подробнее про алгоритмы – в следующий раз 22

  23. Стандартный алгоритм sort #include <algorithm> … vector<int> v; … // Заполняем v sort(v.begin(), v.end()); • Замечание: sort работает только для vector и deque 23

  24. Как задать свой порядок sort Третий параметр – функция сортировки. Пример: хотим отсортировать по двум последним цифрам. 123 89 903 45964  903 123 4596489 bool mycmp(int i, int j) { return i % 100 < j % 100; } // Пример вызова vector<int> v; … sort(v.begin(), v.end(), mycmp); Может быть не только функция, но и лямбда выражение 24

  25. Как написать шаблон, который что-то делает с контейнером (вектором, списком и т.д.)

  26. value_type Пусть мыхотим написать шаблон, который ищет сумму элементов контейнера.Есть проблема.. Какой тип переменной для суммы? • T::value_type – тип того, что содержится в контейнере Например, если T – это list<int>, то T::value_type – это int • И тоже для итераторов Если T – это list<int>::iterator, то T::value_type – это int • Используется, в основном, в шаблонах template <class T> typename T::value_type sum(T b, T e) { typename T::value_type s = 0; for (T p = b; p < e;p++) s += * p; …

  27. decltype и альтернативный синтаксис функций тут мы еще не знаем, что такое b decltype(выражение) – тип выражения Например,int x; double y; decltype(x+y) sum = 0; Вместе с decltypeчасто полезен альтернативный синтаксис функций. Вместо тип результата имя(список параметров) теперь можно писать auto имя(список параметров)->тип результата То есть: template <class T> sum(T b, T e) ->decltype(*b) { decltype(*b) s = 0; for (T p = b; p < e;p++) s += * p; Со старым синтаксисом была бы ошибка: template <class T> decltype(*b) sum(T b, T e) 27

  28. Шаблоны классов 28

  29. Пример: шаблон класса "стек" template <class T> class stack { T stk[100]; int size; public: stack() : size(0) {} void push(const T& x) { size[size++] = x; } T pop { return stk[--size]; } }; Использование stack<int> s1; stack<double> s2; stack<complex> s3; stack<stack<int>> s4; При использовании параметры надо указывать явно 29

  30. Замечания Методы можно описывать вне класса template <class T> void stack<T>::push(const T& x) { ...} В частности, конструктор: template <class T> stack<T>::stack(): size(0) {} 30

  31. Не типовые параметры: template <class T,int maxsize> class stack { T stk[maxsize]; … }; stack<int, 100> s; Такие параметры м.б. только целые (и в некоторых случаях указатели) При вызове д.б. константы Внутри - как константы Параметры по умолчаниюtemplate <class T, int maxsize= 100>class stack { … stack<int> s;// To же, что stack<int, 100> Еще возможности 31

  32. Программы из нескольких исходных файлов 32

  33. Что происходит, когда у нас в проекте несколько файлов? a.cpp b.cpp компилируем... а.obj b.obj  linker … a.exe (или a.dll) Как определить что-то в одном файле, а использовать в другом? a.cpp void f(int i) { … } b.cpp … f(56); … // f надо объявить Программа из нескольких файлов -1

  34. a.cpp void f(int i) { … } b.cpp void f(int i);// Сообщаем, что где-то// определена f... … f(56); … // ОК, так все работает, но: // обычно так не делают! Почему? Неудобно, особенно если файлов много При изменениях надо много где исправлять Легко забыть исправить. Программа из нескольких файлов -2

  35. Директива include:#include <имя_файла> смысл: включить в это место текст из файла a.cpp #include “a.h” void f(int i) { … } a.h void f(int i); b.cpp #include “a.h” ... … f(56); … с.cpp #include “a.h” ... … f(42); … Программа из нескольких файлов – обычно пишут так:

  36. a.cpp void ff(int i) { … } b.cpp void ff(int i) { … } // Ошибка линкера // функция определена два // раза a.cpp static void ff(int i) { … } Еще один смысл static - для функций и глобальных переменных: static функциявидна только в своем cpp файле, и не видна снаружи. Если мы хотим использовать функцию только в одном cpp файле.. (static)

  37. Сейчас вместо static рекомендуется писать так: a.cpp namespace { void ff(int i) { … } } b.cpp namespace { void ff(int i) { … } } Смысл примерно как у static –имена не видны из других файлов Безымянный namespace

  38. Что происходит, когда мы пишем безымянный namespace? Безымянные (анонимные) namespace namespace { int v; …} Генерируется уникальное имя + using директива namespace <уник.имя> { int v; …} using namespace <уник.имя>; Означает: Переменную v можно использовать только от того места, где она определена, и до конца файла То есть: Примерно то же, что static И лучше использовать безымянный namespace, a не static 38

  39. Где писать шаблоны? • Хотя шаблоны и очень похожи на функции, но их нельзя один раз скомпилировать, и потом использовать скомпилированными. • Потому что шаблон – это не функция, а "фабрика по производству функций" • Как следствие:Если мы хотим использовать шаблон в нескольких С++ файлах то надо: • Написать его в .h файле (полностью) • В .cpp файлах включать этот .h файл

  40. Замечание: Что будет, если в .h файл включить функцию полностью? • Что будет, если в h файл включить целиком функцию (а не только ее заголовок)? Abc.h void f(inti) { …какой-то код … } a.cpp … #include "abc.cpp" a.cpp … #include "abc.cpp" • Получиться, что у нас функция описана два раза в a.cpp и b.cpp.То-есть это ошибка линкера.

  41. Как же тогда писать inline функции? • Проблема:Но inline функции мы должны писать в h файле. (Иначе, как компилятор сможет выполнить inline подстановку, если он не видит тела функции). • Поэтому ввели дополнительное правило:inline функции по умолчанию имеют атрибут staticЭто сделано специально чтобы их можно было писать в h файлах Abc.h inline intsqr(inti) { return i*i; }

  42. Д.з 42

  43. Д.з. - 1 • Ввести несколько целых чисел пока не будет введен 0 и записать их в вектор.Отсортировать вектор в порядке возрастания сумм цифр с помощью sort и своей функции сравнения. • Задача 1 без sort, с помощью multimap. (Как это сделать мы обсуждали на занятии. Это не сложно, но если идей не будет – пишите, я подскажу). • Описать функцию с параметрами v и n, которая сортирует данныйвектор целых чисел v по последним n цифрам. При этом желательно использовать стандартную функцию sort (и, видимо, лямбда выражения со списком захвата) • Опишите шаблон функции, которая для любого последовательного контейнера (списка, вектора) ищет среднее арифметическое входящих в него положительных элементов.(1.5 балла за 2 варианта – с value_type и decltype) 43

  44. Д.з. – 2 • Шаблон queue - очередь (аналог stack, но first in – first out). // Пример использования queue<int> q; q.push(3); q.push(7);q.push(11); cout << q.pop(); // 3 cout << q.pop(); // 7 • Можно реализовать с использованием vector или list (или deque)(И тогда вы можете сказать, что применили шаблон «адаптер»…) • Или можете считать, что очередь фиксированной длины и реализовать, как массив (примерно как стек в слайдах)

More Related