260 lines
6.0 KiB
Markdown
260 lines
6.0 KiB
Markdown
# Третий семинар
|
||
|
||
## Шаблоны
|
||
|
||
```cpp
|
||
// template <typename>
|
||
template <class T>
|
||
void swap(T& a, T& b) {
|
||
T tmp;
|
||
tmp = a;
|
||
a = b;
|
||
b = tmp;
|
||
}
|
||
```
|
||
|
||
Можно применять и от нескольких неизвестных параметров
|
||
|
||
```cpp
|
||
template <typename T, typename K>
|
||
void transfer(T fromAccount, T toAccount, K code, int sum)
|
||
{
|
||
std::cout << "From: " << fromAccount << "\nTo: " << toAccount
|
||
<< "\nSum: " << sum << "\nCode: " << code << std::endl;
|
||
}
|
||
```
|
||
|
||
Пример кода для абсолютного значения:
|
||
|
||
```cpp
|
||
template <class T> T abs(const T& x) {
|
||
// template <class T> T abs(T x) {
|
||
return x >= 0 ? x : -x;
|
||
}
|
||
```
|
||
|
||
Суммирование элементов массива
|
||
|
||
```cpp
|
||
template <class T> T sum(T* mas, int N) {
|
||
T res = 0;
|
||
|
||
for (int i = 0; i < N; ++i) {
|
||
res += mas[i];
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
int main() {
|
||
double mas[5] = {...};
|
||
std::cout << sum(mas, 5);
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
```cpp
|
||
template <class T> T sum(T* mas, int N) {
|
||
T res = 0;
|
||
|
||
for (int i = 0; i < N; ++i) {
|
||
res += mas[i];
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
|
||
int main() {
|
||
double mas[5] = {...};
|
||
std::cout << sum<double, 5>(mas);
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
## Что-то про стэк
|
||
|
||
Вторая задача:
|
||
Суть была реализовывать динамически расширяемый массив
|
||
|
||
```cpp
|
||
template<class T, int SIZE>
|
||
class st {
|
||
T st[SIZE];
|
||
int top = 0;
|
||
public:
|
||
void push(T a) {
|
||
if (top == SIZE) {
|
||
// error
|
||
} else {
|
||
st[top++] = a;
|
||
}
|
||
}
|
||
T pop();
|
||
}
|
||
|
||
template<class T, int SIZE>
|
||
T st<T, SIZE>::pop() {
|
||
|
||
return st[--top];
|
||
}
|
||
|
||
```
|
||
|
||
Если указать стандартное значение для каких-то параметров, вызов обычный
|
||
|
||
## Библиотеки
|
||
|
||
### Контейнеры
|
||
|
||
#### Последовательности
|
||
|
||
- list - двунаправленный список
|
||
- vector
|
||
- deque - очередь
|
||
|
||
На их основе создаются:
|
||
|
||
- stack
|
||
- queue
|
||
|
||
#### Ассоциативные массивы
|
||
|
||
- map - отображения
|
||
- multimap - ключ может несколько раз встречаться
|
||
- set - уникальные упорядоченные ключи
|
||
- multiset - совпадающие ключи
|
||
|
||
### Итераторы
|
||
|
||
`#include <algorithm>` - подключение библиотеки
|
||
|
||
- value_type - тип значений в контейнере
|
||
- size_type - аналог size_t
|
||
- reference/ const reference - ссылки на элемент
|
||
- pointer/const pointer - указатели
|
||
|
||
Исполняют роль указателей
|
||
|
||
Для каждого контейнера определён:
|
||
|
||
- iterator - идёт от начала
|
||
- reverse_iterator - идёт с конца
|
||
- const_iterator - не меняет значений
|
||
- const_reverse_iterator - не меняет значений, ревёрс
|
||
|
||
```cpp
|
||
begin(), end();
|
||
rbegin(), rend();
|
||
|
||
cbegin(), cend(); // для константных
|
||
```
|
||
|
||
Виды итераторов:
|
||
|
||
- input
|
||
- output
|
||
- forward
|
||
- bidirectional - list, map, set
|
||
- random_access - для vector deque, можно индексировать, += n
|
||
|
||
```cpp
|
||
#include <vector>
|
||
|
||
int main() {
|
||
vector<int> v1; // длина 0
|
||
vector<int> v2(5); // длина 5, занулены
|
||
vector<int> v3(10, '*');
|
||
int m[] = {1, 2, 3, 4};
|
||
vector<int> v4(m, m + 4);
|
||
// vector<int> v4(m.begin(), m.end());
|
||
}
|
||
```
|
||
|
||
```cpp
|
||
for (int i = 0; i < v.size(); ++i)
|
||
cout << v[i] << " "; // только для random_access контейнера
|
||
|
||
v[i] == v.at(i) // выдаёт out_of_range, если нет элемента
|
||
```
|
||
|
||
Печать элементов в прямом и обратном при помощи итераторов
|
||
|
||
```cpp
|
||
#include <vector>
|
||
#include <iostream>
|
||
|
||
// прямой с помощью прямого
|
||
void f1(std::vector<int> mas) {
|
||
std::vector<int>::std::iterator iter = mas.begin();
|
||
while (iter != mas.end()) {
|
||
std::cout << *iter << " ";
|
||
iter++;
|
||
}
|
||
}
|
||
|
||
// обратный с помощью реверсивного
|
||
void f2(std::vector<int> mas) {
|
||
std::vector<int>::std::reverse_iterator iter = mas.rbegin();
|
||
while (iter != mas.rend()) {
|
||
std::cout << *iter << " ";
|
||
iter++;
|
||
}
|
||
}
|
||
|
||
// обратный с помощью прямого
|
||
void f3(std::vector<int> mas) {
|
||
std::vector<int>::std::iterator iter = mas.end();
|
||
while (iter != mas.begin()) {
|
||
--iter;
|
||
std::cout << *iter << " ";
|
||
}
|
||
}
|
||
```
|
||
|
||
Или же код нормального человека:
|
||
|
||
```cpp
|
||
for (auto x : v) cout << x << " ";
|
||
```
|
||
|
||
### Алгоритмы
|
||
|
||
Некоторые методы контейнеров:
|
||
|
||
- `size_type size()` - количество элементов в контейнере
|
||
- `bool empty()` - пустой ли контейнер
|
||
- `void clear()` - очищает контейнер
|
||
- `void push_back()` - добавляет в конец value_type<>
|
||
- `void pop_back()` - удаляет последний элемент
|
||
- `reference back()` - возвращает ссылку на последний элемент
|
||
- `reference front()` - возвращает ссылку на первый элемент
|
||
- `iterator insert(iterator p, value_type<>)` - вставка перед позицией p, возвращает на новый элемент
|
||
- `iterator erase(iterator p)` - удаляет, куда указывает, возвращает итератор на некст элемент
|
||
- `iterator erase(iterator p1, iterator p2)` - c первого до последнего (не включительно)
|
||
|
||
для list, deque
|
||
|
||
- `void push_front(value_type<>)`
|
||
- `void pop_front(value_type<>)`
|
||
|
||
Для bidirectional итераторов можно использовать
|
||
|
||
- `advance(p1, 3)` для плюса
|
||
- `n = distance(p1, p2)` для вычитания
|
||
|
||
```cpp
|
||
void f(vactor<char>& mas) {
|
||
auto iter = mas.begin();
|
||
|
||
while (iter < mas.end()) {
|
||
++iter;
|
||
|
||
if (iter != mas.end())
|
||
iter = mas.erase(iter);
|
||
}
|
||
}
|
||
```
|