Готовлюсь к коллоквиуму по C++, у меня осталось не...
생성일: 2025년 5월 22일
생성일: 2025년 5월 22일
Ниже разберём по шагам все пункты из вашего задания и приведём образцы кода с пояснениями. Задание взято из вашего файла .
Arr89
для динамического массива (3 балла)Нам нужно реализовать класс, в котором хранятся:
int* Mas
на динамический массив;int size
.Не забудем про «правило пяти» (деструктор, копирующий/перемещающий конструкторы и операторы присваивания).
cpp#include <algorithm> // для std::swap #include <utility> // для std::move class Arr89 { private: int* Mas; int size; public: // 1) Деструктор ~Arr89() { delete[] Mas; } // 2) Конструктор по умолчанию Arr89() : Mas(nullptr), size(0) {} // 3) Конструктор с параметром (размер массива) explicit Arr89(int n) : Mas(new int[n]()), size(n) { // при желании можно инициализировать значениями } // 4) Конструктор копирования Arr89(const Arr89& other) : Mas(new int[other.size]), size(other.size) { std::copy(other.Mas, other.Mas + size, Mas); } // 5) Конструктор перемещения Arr89(Arr89&& other) noexcept : Mas(other.Mas), size(other.size) { other.Mas = nullptr; other.size = 0; } // 6) Оператор копирующего присваивания Arr89& operator=(const Arr89& other) { if (this != &other) { int* newMas = new int[other.size]; std::copy(other.Mas, other.Mas + other.size, newMas); delete[] Mas; Mas = newMas; size = other.size; } return *this; } // 7) Оператор перемещающего присваивания Arr89& operator=(Arr89&& other) noexcept { if (this != &other) { delete[] Mas; Mas = other.Mas; size = other.size; other.Mas = nullptr; other.size = 0; } return *this; } // Дополнительно: доступ к элементам и получение размера int& operator[](int idx) { return Mas[idx]; } const int& operator[](int idx) const { return Mas[idx]; } int getSize() const { return size; } };
Пояснения:
new int[n]()
— выделение массива и инициализация нулями.cpp#include <cmath> // Проверка простоты числа bool isPrime(int x) { if (x < 2) return false; for (int i = 2; i <= std::sqrt(x); ++i) if (x % i == 0) return false; return true; } std::pair<long long, long long> sumPrimesByParity(const Arr89& A) { long long sumEven = 0, sumOdd = 0; for (int i = 0; i < A.getSize(); ++i) { if (isPrime(A[i])) { if (i % 2 == 0) sumEven += A[i]; // 0,2,4… — чётные индексы else sumOdd += A[i]; } } return {sumEven, sumOdd}; }
cpplong long productDivBy7(const Arr89& A) { long long prod = 1; bool found = false; for (int i = 0; i < A.getSize(); ++i) { if (A[i] % 7 == 0) { prod *= A[i]; found = true; } } return found ? prod : 0; // если таких нет, вернём 0 }
cpp#include <unordered_map> #include <algorithm> int maxFrequency(const Arr89& A) { std::unordered_map<int,int> freq; for (int i = 0; i < A.getSize(); ++i) ++freq[A[i]]; int maxF = 0; for (auto [value, count] : freq) maxF = std::max(maxF, count); return maxF; }
cppint countDistinct(const Arr89& A) { std::unordered_set<int> s; for (int i = 0; i < A.getSize(); ++i) s.insert(A[i]); return static_cast<int>(s.size()); }
Переменная должна начинаться с буквы или подчёркивания, далее — буквы, цифры или подчёркивания:
regex^[A-Za-z_][A-Za-z0-9_]*$
дд:мм
, не позже 27 апреля 2022Разберём по частям:
01
до 31
, но для апреля — не более 27
.01
–12
, но ограничиваем до 04
(апрель).Одно из возможных решений:
regex^( (0[1-9]|[12]\d|3[01]):(0[13578]|1[02]) | # Январь, Март, Май, Июль, Август, Октябрь, Декабрь (31 день) (0[1-9]|[12]\d|30):(0[469]|11) | # Апрель—но ограничим после (0[1-9]|1\d|2[0-7]):04 # Апрель, дни 01–27 )$
Для компактности без комментариев:
regex^((0[1-9]|[12]\d|3[01]):(0[13578]|1[02])|(0[1-9]|[12]\d|30):(0[469]|11)|(0[1-9]|1\d|2[0-7]):04)$
std::cout
или дебаггер, чтобы отслеживать значения.Если появятся вопросы по конкретным моментам — пишите! Я помогу разобраться.
а теперь прочитай этот текст и доработай свой код под недостающие пункты заданий:
2 части
общая для всех
Описать класс, 3 конструктора минимум
По умолчанию, копирование, перемещение, с параметром
Деструктор виртуальный
персональный оператор
Для ввода, вывода, больше, меньше, оператор + и += (разные!)
Класс, конструкторы, операторы
Функция лёгкая (найти в массиве самый большой четный за один цикл) за один цикл перемножить элементы, которые делятся на 3
Среднее арифметическое дабл!
Без сложной функции 4 б
Функция сложная 2- 3б (найти 2 элемента, которые дают самое большое число в произведении)
Сортировка sort(Ar, ar+n)
По ссылке передать результат, вернуть 2 ответа
Лямбда выражения 1б
Например, для дека написать find_if(Ar, ar+n, лямбда)
Условие в лямбда выражение
Результативный или нет?
Сортировка
Тема Алгоритмы (в основном заканчиваются на if )
Регулярные выражения 2б, если простой 1б
Построить шаблон для определения правильности записанного
дата, email
Инклуды не прописывать)
Коллоквиум - 1/3 заходной на экзамен
далее я буду задавать тебе вопросы, будь готов объяснять очень подробно все свои действия!
Ниже — обновлённый вариант класса Arr89
и набор вспомогательных функций/операторов, учитывающий все ваши дополнения:
cpp#include <iostream> #include <algorithm> #include <utility> #include <cmath> #include <functional> #include <regex> #include <vector> // Класс Arr89 — динамический массив целых class Arr89 { protected: int* Mas; // указатель на данные int size; // размер массива public: // ВИРТУАЛЬНЫЙ ДЕСТРУКТОР (для правила «пяти») virtual ~Arr89() { delete[] Mas; } // 1) Конструктор по умолчанию Arr89() : Mas(nullptr), size(0) {} // 2) Конструктор с параметром (размер n, элементы == 0) explicit Arr89(int n) : Mas(new int[n]()), size(n) {} // 3) Конструктор копирования Arr89(const Arr89& other) : Mas(new int[other.size]), size(other.size) { std::copy(other.Mas, other.Mas + size, Mas); } // 4) Конструктор перемещения Arr89(Arr89&& other) noexcept : Mas(other.Mas), size(other.size) { other.Mas = nullptr; other.size = 0; } // Оператор копирующего присваивания Arr89& operator=(const Arr89& other) { if (this != &other) { int* tmp = new int[other.size]; std::copy(other.Mas, other.Mas + other.size, tmp); delete[] Mas; Mas = tmp; size = other.size; } return *this; } // Оператор перемещающего присваивания Arr89& operator=(Arr89&& other) noexcept { if (this != &other) { delete[] Mas; Mas = other.Mas; size = other.size; other.Mas = nullptr; other.size = 0; } return *this; } // Доступ к элементам и размер int& operator[](int idx) { return Mas[idx]; } const int& operator[](int idx) const { return Mas[idx]; } int getSize() const { return size; } // Операторы сравнения (по сумме всех элементов) bool operator<(const Arr89& o) const { long sum1 = 0, sum2 = 0; for(int i = 0; i < size; ++i) sum1 += Mas[i]; for(int i = 0; i < o.size; ++i) sum2 += o.Mas[i]; return sum1 < sum2; } bool operator>(const Arr89& o) const { return o < *this; } // Оператор += (поэлементное сложение до min(size)) Arr89& operator+=(const Arr89& o) { int m = std::min(size, o.size); for(int i = 0; i < m; ++i) Mas[i] += o.Mas[i]; return *this; } // Оператор + (новый массив, размер = max(size)) Arr89 operator+(const Arr89& o) const { int m = std::max(size, o.size); Arr89 result(m); for(int i = 0; i < m; ++i) { int a = (i < size ? Mas[i] : 0); int b = (i < o.size ? o.Mas[i] : 0); result.Mas[i] = a + b; } return result; } // Ввод / вывод friend std::ostream& operator<<(std::ostream& os, const Arr89& A) { os << "["; for(int i = 0; i < A.size; ++i) { os << A.Mas[i] << (i+1 < A.size ? ", " : ""); } return os << "]"; } friend std::istream& operator>>(std::istream& is, Arr89& A) { for(int i = 0; i < A.size; ++i) is >> A.Mas[i]; return is; } }; // ─── ПРОСТЫЕ ФУНКЦИИ (в один проход) ────────────────────────────────────── // 1) Найти самый большой чётный элемент и одновременно // перемножить все элементы, делящиеся на 3. // Возвращаем кортеж: (maxEvenOrMinusInf, productDivBy3Or1) #include <tuple> std::tuple<int, long long> simpleOnePass(const Arr89& A) { int maxEven = std::numeric_limits<int>::min(); long long prod3 = 1; bool found3 = false; for(int i = 0, n = A.getSize(); i < n; ++i) { int v = A[i]; if (v % 2 == 0 && v > maxEven) maxEven = v; if (v % 3 == 0) { prod3 *= v; found3 = true; } } if (maxEven == std::numeric_limits<int>::min()) maxEven = 0; // если чётных нет return { maxEven, found3 ? prod3 : 0 }; } // 2) Среднее арифметическое (double) double average(const Arr89& A) { long long sum = 0; for(int i = 0; i < A.getSize(); ++i) sum += A[i]; return A.getSize() ? static_cast<double>(sum) / A.getSize() : 0.0; } // ─── СЛОЖНАЯ ФУНКЦИЯ (2–3 балла) ────────────────────────────────────────── // Найти два элемента, дающие максимальное произведение. // Результат через ссылки: i1,i2 — индексы этих элементов. void maxProductPair(const Arr89& A, int& i1, int& i2) { int n = A.getSize(); if (n < 2) { i1 = i2 = -1; return; } // Для простоты: снимем копию и отсортируем std::vector<std::pair<int,int>> vals; vals.reserve(n); for(int i = 0; i < n; ++i) vals.emplace_back(A[i], i); std::sort(vals.begin(), vals.end(), [](auto& a, auto& b){ return a.first < b.first; }); // Либо два самых больших, либо два самых маленьких (отрицательные) long long prod1 = (long long)vals[0].first * vals[1].first; long long prod2 = (long long)vals[n-1].first * vals[n-2].first; if (prod1 > prod2) { i1 = vals[0].second; i2 = vals[1].second; } else { i1 = vals[n-1].second; i2 = vals[n-2].second; } } // ─── ПРИМЕР ЛЯМБДА‑ВЫРАЖЕНИЯ (1 балл) ────────────────────────────────────── // Найдём первый элемент > X: int findFirstGreater(const Arr89& A, int X) { auto it = std::find_if(A.Mas, A.Mas + A.getSize(), [X](int v){ return v > X; }); return (it != A.Mas + A.getSize()) ? static_cast<int>(it - A.Mas) : -1; } // ─── РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ (2 балла) ─────────────────────────────────────── // Проверка формата даты дд:мм 2022 года, не позже 27.04 const std::regex date2022( R"(^(?:(?:0[1-9]|1\d|2[0-7]):04|(?:0[1-9]|[12]\d|30):(0[13578]|1[02])|(?:0[1-9]|[12]\d|3[01]):(0[469]|11))$)" ); // Проверка email (простейший вариант) const std::regex emailRx( R"(^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$)" ); // Функции‑проверки bool isValidDate(const std::string& s) { return std::regex_match(s, date2022); } bool isValidEmail(const std::string& s) { return std::regex_match(s, emailRx); }
Краткие пояснения и что добавлено
>>
, <<
, <
, >
, +
, +=
.simpleOnePass
за один цикл находит макс. четный и перемножает числа, делящиеся на 3.average
возвращает среднее как double
.maxProductPair
сортирует пары (значение, индекс) и выбирает оптимальную пару.find_if
с лямбдой в findFirstGreater
.std::regex
: для даты 2022 г. до 27 апреля и для email.Если нужно что‑то подробно разобрать по шагам или есть вопросы по конкретным операторам/функциям — пишите, разберём каждую строчку!
покажи ещё раз на отдельном примере как писать конструктор перемещения и для чего он используется (мы решаем задачу в которой массив хранится в написанном нами классе)
Ниже — ещё один самостоятельный пример класса MyArray
, который хранит динамический массив, с полным набором конструкторов, включая конструктор перемещения, и демонстрацией его работы.
cpp#include <iostream> #include <algorithm> // для std::copy #include <utility> // для std::move class MyArray { private: int* data; // указатель на динамический массив size_t size; // его размер public: // 1) Конструктор по умолчанию MyArray() : data(nullptr), size(0) { std::cout << "Default ctor\n"; } // 2) Конструктор с параметром (создаёт массив заданного размера) explicit MyArray(size_t n) : data(new int[n]()), size(n) { std::cout << "Param ctor (" << size << ")\n"; } // 3) Конструктор копирования (глубокое копирование) MyArray(const MyArray& other) : data(new int[other.size]), size(other.size) { std::copy(other.data, other.data + size, data); std::cout << "Copy ctor\n"; } // 4) **Конструктор перемещения** (steal-семантика) MyArray(MyArray&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; // "обнуляем" источник, чтобы не удалять память дважды other.size = 0; std::cout << "Move ctor\n"; } // Деструктор ~MyArray() { delete[] data; std::cout << "Dtor (" << size << ")\n"; } // Оператор присваивания копированием MyArray& operator=(const MyArray& other) { if (this != &other) { delete[] data; size = other.size; data = new int[size]; std::copy(other.data, other.data + size, data); std::cout << "Copy op=\n"; } return *this; } // Оператор присваивания перемещением MyArray& operator=(MyArray&& other) noexcept { if (this != &other) { delete[] data; data = other.data; size = other.size; other.data = nullptr; other.size = 0; std::cout << "Move op=\n"; } return *this; } // Доступ по индексу int& operator[](size_t i) { return data[i]; } size_t getSize() const { return size; } };
std::move
) конструктор перемещения позволяет перебрать указатель на уже выделенную память, вместо того чтобы копировать весь массив.cpp// Функция, создающая и возвращающая массив MyArray makeArray(size_t n) { MyArray temp(n); // Param ctor // ... заполнение temp[i] ... return temp; // здесь вызывается Move ctor, а не Copy ctor } int main() { MyArray A = makeArray(5); // Вывод в консоли: // Param ctor (5) // Move ctor // Dtor (0) — уничтожен временный temp после перемещения // Dtor (5) — уничтожится A в конце main return 0; }
return temp;
происходит перемещение (Move ctor), а не дорогое копирование всех 5 элементов.temp
после этого очищается (его data == nullptr
).Таким образом, конструктор перемещения нужен, чтобы эффективно работать с ресурсами (динамической памятью) вашего класса, избегая лишних копирований .
мне нужна move-семантика
Ниже ещё раз концентрируемся на move-семантике для вашего класса Arr89
(см. постановку задачи ).
Когда вы возвращаете из функции или делаете std::move(obj)
при присваивании, компилятор пытается вызвать не копирующий, а перемещающий конструктор/оператор. Это позволяет:
delete[]
.Arr89
cppclass Arr89 { private: int* Mas; int size; public: // Конструктор перемещения Arr89(Arr89&& other) noexcept : Mas(other.Mas), size(other.size) { // «Украли» ресурс other.Mas = nullptr; other.size = 0; } // Оператор перемещающего присваивания Arr89& operator=(Arr89&& other) noexcept { if (this != &other) { // Удаляем свой старый ресурс delete[] Mas; // Перебираем указатель Mas = other.Mas; size = other.size; // Обнуляем источник other.Mas = nullptr; other.size = 0; } return *this; } // … остальной «правило пяти» код };
cppArr89 makeArr(int n) { Arr89 tmp(n); // … заполнение tmp … return tmp; // тут вызовется move-конструктор вместо копирования } int main() { Arr89 A = makeArr(100); // Порядок: // 1) tmp создаётся (конструктор с параметром) // 2) возвращение tmp → A (move-ctor) // 3) удаляется «опустошённый» tmp (деструктор, но Mas==nullptr) }
std::move
при присваиванииcppArr89 a(50), b(30); // … заполнили a и b … a = std::move(b); // вызывает operator=(Arr89&&) // теперь a «забрал» память b, а b.size == 0
std::move
при a = b;
вы бы скопировали все 30 элементов в a
.std::move(b)
вы перемещаете внутренний массив b
в a
.Mas
и размер size
из источника.Mas = nullptr; size = 0;
), чтобы его деструктор ничего не удалил.Таким образом, move-семантика позволяет передавать владение динамическими ресурсами быстрее и безопаснее, без глубокого копирования.
#include <iostream>
class Ar2020
{
public:
textint* M; int count; Ar2020() : count(5) { // по умолчанию M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = 0; } } Ar2020(const Ar2020& copy) : count(copy.count) { // копирования M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = copy.M[i]; } } Ar2020(int count) : count(count) { // с параметром M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = 1; } } ~Ar2020() { delete[] M; } // перегрузка оператора присваивания Ar2020& operator=(const Ar2020& left) { delete[] M; count = left.count; M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = left.M[i]; } return *this; } // перегрузка оператора [] int& operator[](const int index) { if (index < 0 or index >= count) { throw std::out_of_range("Text"); } return M[index]; } // перегрузка оператора вывода << friend std::ostream& operator<< (std::ostream& out, const Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) { out << Ar.M[i] << ' '; } return out; } // перегрузка оператора ввода >> friend std::istream& operator>> (std::istream& in, Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) { in >> Ar.M[i]; } return in; } int SrSum() { int sum = 0; for (int i = 0; i < count; ++i) { sum += M[i]; } int sr = sum / count; sum = 0; for (int i = 0; i < count; ++i) { if (M[i] < sr) { sum += M[i]; } } return sum; } void TwoIndex() { int max = INT_MIN, index1 = 0, index2 = 0; for (int i = 0; i < count; ++i) { if (M[i] >= max) { max = M[i]; index2 = index1; index1 = i; } } std::cout << "Indexs: " << index2 << ' ' << index1 << std::endl; }
};
int main() {
setlocale(LC_ALL, "rus");
text/*Ar2020 massiv(10); std::cout << "Введите 10 элементов массива: " << std::endl; for (int i = 0; i < 10; i++) { std::cin >> massiv.M[i]; } std::cout << "Вывод массива на экран: " << std::endl; for (int j = 0; j < 10; j++) { std::cout << massiv.M[j] << ' '; }*/ Ar2020 mas1(5); /*for (int i = 0; i < 5; i++) { std::cout << mas1.M[i]; }*/ Ar2020 mas2 = mas1; for (int i = 0; i < 5; i++) { std::cout << mas2.M[i]; } std::cout << std::endl; std::cout << "Заполнение массива произвольными значениями (ранее там были нули): "; std::cout << std::endl; for (int j = 0; j < 5; j++) { std::cin >> mas2.M[j]; } std::cout << std::endl; std::cout << "Вывод оператора []: "; std::cout << std::endl; std::cout << "для пятого номера: "; std::cout << mas2.M[4]; std::cout << std::endl; std::cout << "для третьего номера: "; std::cout << mas2.M[2]; return 0;
}
Добавь к этому коду конструктор перемещения (рядом напиши комментарий // конструктор перемещения)
и также в главной функции добавь какой-нибудь пример его работы
Ниже ваш класс Ar2020
с добавленным конструктором перемещения и примером его использования в main
. Я пометил его комментарием // конструктор перемещения
и добавил вызов через std::move
, чтобы продемонстрировать, как он работает:
cpp#include <iostream> #include <utility> // для std::move #include <climits> // для INT_MIN #include <stdexcept> // для std::out_of_range class Ar2020 { public: int* M; int count; // 1) Конструктор по умолчанию Ar2020() : count(5), M(new int[count]) { for (int i = 0; i < count; ++i) M[i] = 0; } // 2) Конструктор копирования Ar2020(const Ar2020& copy) : count(copy.count), M(new int[copy.count]) { for (int i = 0; i < count; ++i) M[i] = copy.M[i]; } // 3) Конструктор с параметром Ar2020(int count) : count(count), M(new int[count]) { for (int i = 0; i < count; ++i) M[i] = 1; } // 4) **Конструктор перемещения** Ar2020(Ar2020&& other) noexcept // конструктор перемещения : M(other.M), count(other.count) { other.M = nullptr; other.count = 0; std::cout << "Move ctor called\n"; } // Деструктор ~Ar2020() { delete[] M; } // Оператор присваивания копированием Ar2020& operator=(const Ar2020& left) { if (this != &left) { delete[] M; count = left.count; M = new int[count]; for (int i = 0; i < count; ++i) M[i] = left.M[i]; } return *this; } // Оператор присваивания перемещением Ar2020& operator=(Ar2020&& other) noexcept { if (this != &other) { delete[] M; M = other.M; count = other.count; other.M = nullptr; other.count = 0; std::cout << "Move op= called\n"; } return *this; } // Оператор [] int& operator[](int index) { if (index < 0 || index >= count) throw std::out_of_range("Index out of range"); return M[index]; } // Оператор вывода friend std::ostream& operator<<(std::ostream& out, const Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) out << Ar.M[i] << ' '; return out; } // Оператор ввода friend std::istream& operator>>(std::istream& in, Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) in >> Ar.M[i]; return in; } // Пример простой функции: сумма элементов меньше среднего int SrSum() { int sum = 0; for (int i = 0; i < count; ++i) sum += M[i]; int sr = sum / count; sum = 0; for (int i = 0; i < count; ++i) if (M[i] < sr) sum += M[i]; return sum; } // Пример сложной функции: два индекса максимального void TwoIndex() { int max = INT_MIN, idx1 = 0, idx2 = 0; for (int i = 0; i < count; ++i) { if (M[i] >= max) { idx2 = idx1; idx1 = i; max = M[i]; } } std::cout << "Indexes: " << idx2 << ' ' << idx1 << std::endl; } }; int main() { setlocale(LC_ALL, "rus"); // Создаём массив по умолчанию Ar2020 a1; // default ctor for (int i = 0; i < a1.count; ++i) a1.M[i] = i + 1; std::cout << "a1: " << a1 << std::endl; // Используем конструктор перемещения при возврате из lambda auto makeArr = []() -> Ar2020 { Ar2020 tmp(5); // param ctor for (int i = 0; i < 5; ++i) tmp.M[i] = (i + 1) * 10; return tmp; // здесь вызовется move ctor }; Ar2020 a2 = makeArr(); std::cout << "a2 (moved): " << a2 << std::endl; // Или явно через std::move Ar2020 a3(5); for (int i = 0; i < 5; ++i) a3.M[i] = i * 2; std::cout << "a3 before move: " << a3 << std::endl; Ar2020 a4 = std::move(a3); // конструктор перемещения std::cout << "a4 after move: " << a4 << std::endl; std::cout << "a3 after move (empty): " << a3 << std::endl; return 0; }
Ar2020(Ar2020&& other) noexcept
) «перехватывает» указатель M
и значение count
из временного объекта, обнуляя его, чтобы не было двойного освобождения памяти.main
показаны два сценария: возврат через лямбду (makeArr
) и явный std::move
— в обоих случаях вы увидите строку Move ctor called
.в задании было написано "повторить сортировку" и также как в ней использовать лямбда-выражения. Можешь помочь разобраться что под этим имеется в виду?
В задании «повторить сортировку» обычно подразумевается, что вам нужно:
std::sort
из <algorithm>
.std::sort
можно передать лямбда-выражение в качестве компаратора, чтобы сортировать по разным критериям.Допустим, у вас есть массив Mas
длины size
внутри класса. Чтобы отсортировать его по возрастанию, достаточно:
cpp#include <algorithm> // где-то в методах класса Arr89 (или вне, получив доступ к Mas и size): std::sort(Mas, Mas + size);
Это эквивалентно «повторению» того, что вы учили: алгоритм быстрой сортировки (обычно) применится к вашему динамическому массиву.
Иногда нужно необычное упорядочение:
Вместо того, чтобы писать отдельную функцию-компаратор, вы можете сразу в std::sort
описать лямбду:
cpp// 1) Сортировка по убыванию: std::sort(Mas, Mas + size, [](int a, int b) { return a > b; // "true", если a должно стоять раньше b }); // 2) По абсолютному значению (возрастание): std::sort(Mas, Mas + size, [](int a, int b) { return std::abs(a) < std::abs(b); }); // 3) Сначала чётные, потом нечётные: std::sort(Mas, Mas + size, [](int a, int b) { // если один чётный, другой нечётный — чётный вперёд if ((a % 2 == 0) != (b % 2 == 0)) return (a % 2 == 0); // иначе обычный порядок return a < b; });
Каждая лямбда имеет вид
cpp[ /*(захваты)*/ ](параметры) -> возвращаемый_тип { тело; }
но в простых случаях тип возвращаемого значения можно не указывать — компилятор выведет его сам.
Arr89
Добавим в ваш класс метод sortAsc()
и sortDesc()
:
cpp#include <algorithm> #include <cmath> class Arr89 { int* Mas; int size; public: // ... все ваши конструкторы, деструктор и т.п. // Сортировка по возрастанию void sortAsc() { std::sort(Mas, Mas + size); } // Сортировка по убыванию через лямбду void sortDesc() { std::sort(Mas, Mas + size, [](int a, int b) { return a > b; }); } // Сортировка по абсолютному значению void sortByAbs() { std::sort(Mas, Mas + size, [](int a, int b) { return std::abs(a) < std::abs(b); }); } };
И в main
можно увидеть:
cppint main() { Arr89 A(8); // заполним чем-нибудь for (int i = 0; i < A.getSize(); ++i) A[i] = (i % 2 == 0 ? i : -i*2); std::cout << "Исходный: " << A << "\n"; A.sortAsc(); std::cout << "По возрастанию: " << A << "\n"; A.sortDesc(); std::cout << "По убыванию: " << A << "\n"; A.sortByAbs(); std::cout << "По |value|: " << A << "\n"; return 0; }
Что происходит:
std::sort
без третьего аргумента используется <
для int
.[](int a,int b){ return a>b; }
«переворачивает» порядок.Таким образом, «повторить сортировку» означает вспомнить вызов std::sort
, а «использовать лямбда-выражения» — это дать внутрь std::sort
анонимную функцию-компаратор, не выносить её в отдельный bool cmp(int,int)
. Соответственно, вы показываете гибкость и знание стандартных алгоритмов и лямбд в C++.
#include <iostream>
#include <utility>
#include <climits>
#include <stdexcept>
class Ar2020
{
public:
textint* M; int count; Ar2020() : count(5) { // ПО УМОЛЧАНИЮ M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = 0; } } Ar2020(const Ar2020& copy) : count(copy.count) { // КОПИРОВАНИЯ M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = copy.M[i]; } } Ar2020(int count) : count(count) { // с ПАРАМЕТРОМ M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = 1; } } Ar2020(Ar2020&& other) noexcept // ПЕРЕМЕЩЕНИЯ : M(other.M), count(other.count) { other.M = nullptr; other.count = 0; std::cout << "Move ctor called\n"; } ~Ar2020() { delete[] M; } // перегрузка оператора присваивания Ar2020& operator=(const Ar2020& left) { delete[] M; count = left.count; M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = left.M[i]; } return *this; } // перегрузка оператора [] int& operator[](const int index) { if (index < 0 or index >= count) { throw std::out_of_range("Text"); } return M[index]; } // перегрузка оператора вывода << friend std::ostream& operator<< (std::ostream& out, const Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) { out << Ar.M[i] << ' '; } return out; } // перегрузка оператора ввода >> friend std::istream& operator>> (std::istream& in, Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) { in >> Ar.M[i]; } return in; } int SrSum() { int sum = 0; for (int i = 0; i < count; ++i) { sum += M[i]; } int sr = sum / count; sum = 0; for (int i = 0; i < count; ++i) { if (M[i] < sr) { sum += M[i]; } } return sum; } void TwoIndex() { int max = INT_MIN, index1 = 0, index2 = 0; for (int i = 0; i < count; ++i) { if (M[i] >= max) { max = M[i]; index2 = index1; index1 = i; } } std::cout << "Indexs: " << index2 << ' ' << index1 << std::endl; }
};
int main() {
setlocale(LC_ALL, "rus");
text// ПЕРЕГРУЖЕННЫЙ ВВОД /*Ar2020 massiv(10); std::cout << "Введите 10 элементов массива: " << std::endl; for (int i = 0; i < 10; i++) { std::cin >> massiv.M[i]; } // ПЕРЕГРУЖЕННЫЙ ВЫВОД std::cout << "Вывод массива на экран: " << std::endl; for (int j = 0; j < 10; j++) { std::cout << massiv.M[j] << ' '; }*/ Ar2020 mas1(5); // конструктор с параметром /*for (int i = 0; i < 5; i++) { std::cout << mas1.M[i]; }*/ Ar2020 mas2 = mas1; // operator = for (int i = 0; i < 5; i++) { std::cout << mas2.M[i]; } std::cout << std::endl; std::cout << "Заполнение массива произвольными значениями (ранее там были нули): "; std::cout << std::endl; for (int j = 0; j < 5; j++) { std::cin >> mas2.M[j]; } std::cout << std::endl;
// ---------------------------------------------------------------------
std::cout << "Вывод оператора []: ";
std::cout << std::endl;
std::cout << "для пятого номера: ";
std::cout << mas2.M[4];
std::cout << std::endl;
std::cout << "для третьего номера: ";
std::cout << mas2.M[2];
// ---------------------------------------------------------------------
textAr2020 a3(5); for (int i = 0; i < 5; ++i) { a3.M[i] = i * 2; } std::cout << "a3 before move: " << a3 << std::endl; Ar2020 a4 = std::move(a3); // конструктор перемещения std::cout << "a4 after move: " << a4 << std::endl; std::cout << "a3 after move (empty): " << a3 << std::endl; return 0;
}
А теперь можешь написать для этого кода сортировку sort и к ней закинуть какую-нибудь лямбду? на твой вкус, только объясни
а ещё добавь реализацию в main!
Ниже показано, как добавить в ваш код вызов std::sort
с лямбда-компаратором прямо в main
. В качестве примера я отсортирую массив a4
по убыванию (от большего к меньшему).
cpp#include <iostream> #include <utility> #include <climits> #include <stdexcept> #include <algorithm> // для std::sort #include <cmath> // если понадобятся функции из <cmath> class Ar2020 { public: int* M; int count; // ПО УМОЛЧАНИЮ Ar2020() : count(5), M(new int[count]) { for (int i = 0; i < count; ++i) M[i] = 0; } // КОПИРОВАНИЯ Ar2020(const Ar2020& copy) : count(copy.count), M(new int[count]) { for (int i = 0; i < count; ++i) M[i] = copy.M[i]; } // С ПАРАМЕТРОМ Ar2020(int count) : count(count), M(new int[count]) { for (int i = 0; i < count; ++i) M[i] = 1; } // ПЕРЕМЕЩЕНИЯ Ar2020(Ar2020&& other) noexcept : M(other.M), count(other.count) { other.M = nullptr; other.count = 0; std::cout << "Move ctor called\n"; } ~Ar2020() { delete[] M; } Ar2020& operator=(const Ar2020& left) { if (this != &left) { delete[] M; count = left.count; M = new int[count]; for (int i = 0; i < count; ++i) M[i] = left.M[i]; } return *this; } Ar2020& operator=(Ar2020&& other) noexcept { if (this != &other) { delete[] M; M = other.M; count = other.count; other.M = nullptr; other.count = 0; std::cout << "Move op= called\n"; } return *this; } int& operator[](int index) { if (index < 0 || index >= count) throw std::out_of_range("Index out of range"); return M[index]; } friend std::ostream& operator<<(std::ostream& out, const Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) out << Ar.M[i] << ' '; return out; } friend std::istream& operator>>(std::istream& in, Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) in >> Ar.M[i]; return in; } // ... SrSum(), TwoIndex() и т.п. }; int main() { setlocale(LC_ALL, "rus"); // Демонстрация move-семантики Ar2020 a3(5); for (int i = 0; i < 5; ++i) a3.M[i] = i * 2; std::cout << "a3 before move: " << a3 << std::endl; Ar2020 a4 = std::move(a3); // конструктор перемещения std::cout << "a4 after move: " << a4 << std::endl; std::cout << "a3 after move: " << a3 << std::endl; // пустой // ─── ВСТАВЛЯЕМ СОРТИРОВКУ ──────────────────────────────────────────────── // Отсортируем a4 по убыванию с помощью лямбда-выражения: // лямбда [](int x, int y){ return x > y; } возвращает true, // если x должен стоять перед y → будем получать порядок от большего к меньшему. std::sort(a4.M, a4.M + a4.count, [](int x, int y) { return x > y; }); std::cout << "a4 sorted descending: " << a4 << std::endl; return 0; }
Объяснение
<algorithm>
для std::sort
.Лямбда-выражение здесь — это анонимная функция, которая говорит «поместить элементcppstd::sort(a4.M, a4.M + a4.count, [](int x, int y) { return x > y; });
x
перед элементом y
, если x > y
». Таким образом, массив сортируется в убывающем порядке.[](int x,int y){ return x < y; }
[](int x,int y){ return std::abs(x) < std::abs(y); }
Это и есть «повторить сортировку» и «использовать лямбда-выражения» в вашем задании.
как работать с регулярными выражениями? мне нужно построить шаблон для определения правильности записанной даты и почта (email)
Ниже кратко о том, как в C++ работать с регулярными выражениями (<regex>
), и два готовых шаблона — для даты (формат дд:мм
, 2022-й год, до 27 апреля включительно) и для email.
std::regex
cpp#include <iostream> #include <regex> #include <string> bool match(const std::string& s, const std::regex& rx) { return std::regex_match(s, rx); } int main() { std::regex rx("\\d{2}:\\d{2}"); // простой пример std::string test = "28:02"; if (match(test, rx)) { std::cout << test << " — OK\n"; } else { std::cout << test << " — NOT OK\n"; } return 0; }
std::regex rx("PATTERN");
— компилирует шаблон.std::regex_match(str, rx)
— проверяет, что вся строка целиком соответствует шаблону.std::regex_constants::icase
для нечувствительности к регистру).дд:мм
2022 года, не позже 27 апреляcpp// шаблон (обратите внимание на экранирование слэшей в строке C++) const std::regex dateRx( R"(^(?:(?:0[1-9]|1\d|2[0-7]):04|(?:0[1-9]|[12]\d|30):(0[13578]|1[02])|(?:0[1-9]|[12]\d|3[01]):(0[469]|11))$)" );
Пояснение :
(?:0[1-9]|1\d|2[0-7]):04
— дни 01
–27
апреля.(?:0[1-9]|[12]\d|30):(0[13578]|1[02])
— месяцы с 31 днём (янв, мар, май, …) до 30-го.(?:0[1-9]|[12]\d|3[01]):(0[469]|11)
— месяцы с 30 днём (апрель уже ограничили выше, но здесь май нет — тк 31 день).cppconst std::regex emailRx( R"(^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$)" );
[A-Za-z0-9._%+-]+
— локальная часть (до @
), хотя в реальности может быть сложнее.@[A-Za-z0-9.-]+
— домен (буквы, цифры, точки и дефисы).\.[A-Za-z]{2,}
— точка и доменная зона из 2+ букв.main()
cpp#include <iostream> #include <regex> #include <string> int main() { std::regex dateRx( R"(^(?:(?:0[1-9]|1\d|2[0-7]):04|(?:0[1-9]|[12]\d|30):(0[13578]|1[02])|(?:0[1-9]|[12]\d|3[01]):(0[469]|11))$)" ); std::regex emailRx( R"(^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$)" ); std::string s1 = "27:04"; std::string s2 = "31:02"; std::string e1 = "[email protected]"; std::string e2 = "[email protected]"; std::cout << s1 << ": " << (std::regex_match(s1, dateRx) ? "valid\n" : "invalid\n"); std::cout << s2 << ": " << (std::regex_match(s2, dateRx) ? "valid\n" : "invalid\n"); std::cout << e1 << ": " << (std::regex_match(e1, emailRx) ? "valid\n" : "invalid\n"); std::cout << e2 << ": " << (std::regex_match(e2, emailRx) ? "valid\n" : "invalid\n"); return 0; }
Вывод будет примерно:
Таким образом, вы получаете готовые C++-шаблоны и демонстрацию их использования в коде. Надеюсь, это поможет!
#include <iostream>
#include <utility>
#include <climits>
#include <stdexcept>
class Ar2020
{
public:
textint* M; int count; Ar2020() : count(5) { // ПО УМОЛЧАНИЮ M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = 0; } } Ar2020(const Ar2020& copy) : count(copy.count) { // КОПИРОВАНИЯ M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = copy.M[i]; } } Ar2020(int count) : count(count) { // с ПАРАМЕТРОМ M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = 1; } } Ar2020(Ar2020&& other) noexcept // ПЕРЕМЕЩЕНИЯ : M(other.M), count(other.count) { other.M = nullptr; other.count = 0; std::cout << "Move ctor called\n"; } ~Ar2020() { delete[] M; } // перегрузка оператора присваивания Ar2020& operator=(const Ar2020& left) { delete[] M; count = left.count; M = new int[count]; for (int i = 0; i < count; ++i) { M[i] = left.M[i]; } return *this; } // перегрузка оператора [] int& operator[](const int index) { if (index < 0 or index >= count) { throw std::out_of_range("Text"); } return M[index]; } // перегрузка оператора вывода << friend std::ostream& operator<< (std::ostream& out, const Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) { out << Ar.M[i] << ' '; } return out; } // перегрузка оператора ввода >> friend std::istream& operator>> (std::istream& in, Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) { in >> Ar.M[i]; } return in; } int SrSum() { int sum = 0; for (int i = 0; i < count; ++i) { sum += M[i]; } int sr = sum / count; sum = 0; for (int i = 0; i < count; ++i) { if (M[i] < sr) { sum += M[i]; } } return sum; } void TwoIndex() { int max = INT_MIN, index1 = 0, index2 = 0; for (int i = 0; i < count; ++i) { if (M[i] >= max) { max = M[i]; index2 = index1; index1 = i; } } std::cout << "Indexs: " << index2 << ' ' << index1 << std::endl; }
};
int main() {
setlocale(LC_ALL, "rus");
text// ПЕРЕГРУЖЕННЫЙ ВВОД /*Ar2020 massiv(10); std::cout << "Введите 10 элементов массива: " << std::endl; for (int i = 0; i < 10; i++) { std::cin >> massiv.M[i]; } // ПЕРЕГРУЖЕННЫЙ ВЫВОД std::cout << "Вывод массива на экран: " << std::endl; for (int j = 0; j < 10; j++) { std::cout << massiv.M[j] << ' '; }*/ Ar2020 mas1(5); // конструктор с параметром /*for (int i = 0; i < 5; i++) { std::cout << mas1.M[i]; }*/ Ar2020 mas2 = mas1; // operator = for (int i = 0; i < 5; i++) { std::cout << mas2.M[i]; } std::cout << std::endl; std::cout << "Заполнение массива произвольными значениями (ранее там были нули): "; std::cout << std::endl; for (int j = 0; j < 5; j++) { std::cin >> mas2.M[j]; } std::cout << std::endl;
// ---------------------------------------------------------------------
std::cout << "Вывод оператора []: ";
std::cout << std::endl;
std::cout << "для пятого номера: ";
std::cout << mas2.M[4];
std::cout << std::endl;
std::cout << "для третьего номера: ";
std::cout << mas2.M[2];
// ---------------------------------------------------------------------
textAr2020 a3(5); for (int i = 0; i < 5; ++i) { a3.M[i] = i * 2; } std::cout << "a3 before move: " << a3 << std::endl; Ar2020 a4 = std::move(a3); // конструктор перемещения std::cout << "a4 after move: " << a4 << std::endl; std::cout << "a3 after move (empty): " << a3 << std::endl;
// СОРТИРОВКА И ЛЯМБДА-ВЫРАЖЕНИЕ ДЛЯ УПОРЯДОЧИВАНИЯ ПО УБЫВАНИЮ
textstd::sort(a4.M, a4.M + a4.count, [](int x, int y) { return x > y; }); std::cout << "a4 sorted descending: " << a4 << std::endl;
// ---------------------------------------------------------------------
return 0;
}
Добавь к этому коду ещё парочку перегруженных операторов:
оператор + для поэлементного сложения массива
оператор - ( для двух массивов одинаковой размерности)
оператор * (перемножение двух массивов)
оператор / (деления) для поэлементного деления двух массивов
Ниже — ваш класс Ar2020
с добавленными операторами поэлементных операций +
, -
, *
и /
. При несовпадении размеров бросается std::length_error
.
cpp#include <iostream> #include <utility> #include <climits> #include <stdexcept> #include <algorithm> #include <cmath> class Ar2020 { public: int* M; int count; // ПО УМОЛЧАНИЮ Ar2020() : count(5), M(new int[count]) { std::fill(M, M + count, 0); } // КОПИРОВАНИЯ Ar2020(const Ar2020& copy) : count(copy.count), M(new int[count]) { std::copy(copy.M, copy.M + count, M); } // С ПАРАМЕТРОМ Ar2020(int count) : count(count), M(new int[count]) { std::fill(M, M + count, 1); } // ПЕРЕМЕЩЕНИЯ Ar2020(Ar2020&& other) noexcept : M(other.M), count(other.count) { other.M = nullptr; other.count = 0; std::cout << "Move ctor called\n"; } ~Ar2020() { delete[] M; } // Оператор присваивания копированием Ar2020& operator=(const Ar2020& left) { if (this != &left) { delete[] M; count = left.count; M = new int[count]; std::copy(left.M, left.M + count, M); } return *this; } // Оператор присваивания перемещением Ar2020& operator=(Ar2020&& other) noexcept { if (this != &other) { delete[] M; M = other.M; count = other.count; other.M = nullptr; other.count = 0; std::cout << "Move op= called\n"; } return *this; } // Оператор [] int& operator[](int index) { if (index < 0 || index >= count) throw std::out_of_range("Index out of range"); return M[index]; } // Ввод / вывод friend std::ostream& operator<<(std::ostream& out, const Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) out << Ar.M[i] << ' '; return out; } friend std::istream& operator>>(std::istream& in, Ar2020& Ar) { for (int i = 0; i < Ar.count; ++i) in >> Ar.M[i]; return in; } // ПОЭЛЕМЕНТНЫЕ ОПЕРАЦИИ Ar2020 operator+(const Ar2020& o) const { if (count != o.count) throw std::length_error("Size mismatch for operator+"); Ar2020 res(count); for (int i = 0; i < count; ++i) res.M[i] = M[i] + o.M[i]; return res; } Ar2020 operator-(const Ar2020& o) const { if (count != o.count) throw std::length_error("Size mismatch for operator-"); Ar2020 res(count); for (int i = 0; i < count; ++i) res.M[i] = M[i] - o.M[i]; return res; } Ar2020 operator*(const Ar2020& o) const { if (count != o.count) throw std::length_error("Size mismatch for operator*"); Ar2020 res(count); for (int i = 0; i < count; ++i) res.M[i] = M[i] * o.M[i]; return res; } Ar2020 operator/(const Ar2020& o) const { if (count != o.count) throw std::length_error("Size mismatch for operator/"); Ar2020 res(count); for (int i = 0; i < count; ++i) { if (o.M[i] == 0) throw std::domain_error("Division by zero in operator/"); res.M[i] = M[i] / o.M[i]; } return res; } // Примеры прочих функций (SrSum, TwoIndex)... }; // Пример использования в main int main() { Ar2020 A(5), B(5); // Заполним A = {1,2,3,4,5}, B = {5,4,3,2,1} for (int i = 0; i < 5; ++i) { A.M[i] = i + 1; B.M[i] = 5 - i; } Ar2020 C = A + B; Ar2020 D = A - B; Ar2020 E = A * B; Ar2020 F = A / B; std::cout << "A+B = " << C << "\n"; std::cout << "A-B = " << D << "\n"; std::cout << "A*B = " << E << "\n"; std::cout << "A/B = " << F << "\n"; return 0; }
Пояснения
operator/
дополнительно проверяется деление на ноль.main
, демонстрирующий все четыре операции.