diff --git a/01_week/tasks/addition/addition.cpp b/01_week/tasks/addition/addition.cpp index 92872802..3ca160a1 100644 --- a/01_week/tasks/addition/addition.cpp +++ b/01_week/tasks/addition/addition.cpp @@ -1,7 +1,10 @@ -#include -#include - +#include // заголовочный файл с целочисленными типами фиксированного размера +#include // из этого мы ничего не используем +// функция принимает две перменных типа int и возвращает число типа int64_t int64_t Addition(int a, int b) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + + // Чтобы сложение выполнялось в int64_t, приводим a и b к этому типу +// static_cast<новый тип>(переменная) + return static_cast(a) + static_cast(b); +} diff --git a/01_week/tasks/char_changer/char_changer.cpp b/01_week/tasks/char_changer/char_changer.cpp index 3a7344d9..6cec0357 100644 --- a/01_week/tasks/char_changer/char_changer.cpp +++ b/01_week/tasks/char_changer/char_changer.cpp @@ -1,7 +1,88 @@ #include -#include - +#include // применял isspace, isdigit, isupper, islower, toupper size_t CharChanger(char array[], size_t size, char delimiter = ' ') { - throw std::runtime_error{"Not implemented"}; + if (size == 0) { + return 0; + } + + size_t read = 0; // это индекс для чтения + size_t write = 0; // это индекс для запси символов + + // идем по массиву пока не выйдем за него + // и пока текущий символ не конец строки, конец строки по условию это '\0' + while (read < size && array[read] != '\0') { + // в cppreference указано, что isspace должно принимать безнаковый символ, + // поэтому преобразуем текущий символ из char в unsigned char + unsigned char uc = static_cast(array[read]); + // если текущий символ пробельный + if (std::isspace(uc)) { + + // пропускаем все подряд идущие пробельные символы + while (read < size && array[read] != '\0') { + unsigned char c = static_cast(array[read]); + if (!std::isspace(c)) { + break; // текущий символ больше не пробел — выходим + } + ++read; // пробел — пропускаем и идём дальше + } + // теперь когда мы прочитали все пробелы записывыем в write только один пробел + array[write++] = delimiter; + + } else { + // Теперь рассматриваем случай когда у нас идут подряд одинаковые символы + // Текущий символ массива + char current = array[read]; + size_t count = 0; // это как счетчик, то есть сколько повторябщихся символов + // идем пока текущий символ не превзойдет размер массива и + // символ не конец строки и символ на текущей позиции такой же как и currentт + while (read < size && array[read] != '\0' && array[read] == current) { + ++count; + ++read; + } + + // Определяем, какой символ писать по правилам + // в cppreference указано, что isdigit,isupper,islower должно принимать безнаковый символ, + // поэтому преобразуем текущий символ current из char в unsigned char + unsigned char cu = static_cast(current); + char Char; + + if (std::isdigit(cu)) { // цифры заменяем на '*' + Char = '*'; + } else if (std::isupper(cu)) { //прописные латинские не меняем + Char = current; + } else if (std::islower(cu)) { // строчные на прописные + Char = static_cast(std::toupper(cu)); + } else { // остальное на '_' + Char = '_'; + } + + // записываем символ в write + array[write++] = Char; + + // пишем количество повторений, если count > 1 + if (count > 1) { + if (count >= 10) { // Если повторений не менее 10, указывается `0` после символа + array[write++] = '0'; + } else { + // записываем в write число посторений (то есть елси 2222, то 4), + // Например, если было "2222", то count = 4, и мы должны записать символ '4'. + // В кодировке ASCII код символа '0' равен 48 + // Поэтому, чтобы получить символ '4', берём код '0' (48) и прибавляем 4 (48 + 4 = 52 — это код '4') + array[write++] = static_cast('0' + count); // + } + } + } + } + + // завершаем строку + if (write >= size) { + write = size - 1; + } + array[write] = '\0'; + + return write; } + + + diff --git a/01_week/tasks/check_flags/check_flags.cpp b/01_week/tasks/check_flags/check_flags.cpp index 75e7c652..665139dd 100644 --- a/01_week/tasks/check_flags/check_flags.cpp +++ b/01_week/tasks/check_flags/check_flags.cpp @@ -1,8 +1,8 @@ -#include -#include + #include + #include - -enum class CheckFlags : uint8_t { + // каждый флаг это один бит в маске, флаг занимает ровно один + enum class CheckFlags : uint8_t { NONE = 0, TIME = (1 << 0), DATE = (1 << 1), @@ -12,7 +12,82 @@ enum class CheckFlags : uint8_t { DEST = (1 << 5), ALL = TIME | DATE | USER | CERT | KEYS | DEST }; + void PrintCheckFlags(CheckFlags flags) { + // мы не можем напрямую работать с flags, поэтому преобразуем + // flags из типа CheckFlags в обычное число типа uint8_t + // uint8_t потому что все флаги храняться в одном байте + uint8_t mask = static_cast(flags); + // так как маска = 8 бит, то и все разрешенные флаги тоже 8 бит (поэтому uint8_t) + // но в целом как для mask, так и для allowedFlags могли написать int и не париться, но с uint8_t корректнее + uint8_t allowedFlags = static_cast(CheckFlags::ALL); + + // Если передано значение выходит из возможного диапазона значений, то вывод следует оставить пустым. + // к примеру если мы на вход подаем значение 128, а 128 в двочиной это 10000000 (mask), allowedFlags = 01111111, то + // 10000000 + // 11000000 (инверсия) + // -------- + // 10000000 (такого флага в маске нет) + if (mask & ~allowedFlags) { + return; + } + + // Если передан флаг отсутствия проверок, то выводим пустые `[]` + if (mask == 0) { + std::cout << "[]"; + return; + } + + // дальше расматриваем все возможные случаи проверок + std::cout << "["; + // флаг состояний для запятой + bool first = true; + + if (mask & static_cast(CheckFlags::TIME)) { + if (!first) { + std::cout << ","; + } + std::cout << "TIME"; + first = false; + } + + if (mask & static_cast(CheckFlags::DATE)) { + if (!first) { + std::cout << ","; + } + std::cout << "DATE"; + first = false; + } + + if (mask & static_cast(CheckFlags::USER)) { + if (!first) { + std::cout << ","; + } + std::cout << "USER"; + first = false; + } + + if (mask & static_cast(CheckFlags::CERT)) { + if (!first) { + std::cout << ","; + } + std::cout << "CERT"; + first = false; + } + + if (mask & static_cast(CheckFlags::KEYS)) { + if (!first) { + std::cout << ","; + } + std::cout << "KEYS"; + first = false; + } + + if (mask & static_cast(CheckFlags::DEST)) { + if (!first) { + std::cout << ","; + } + std::cout << "DEST"; + } -void PrintCheckFlags(CheckFlags flags) { - throw std::runtime_error{"Not implemented"}; + std::cout << "]"; } diff --git a/01_week/tasks/length_lit/length_lit.cpp b/01_week/tasks/length_lit/length_lit.cpp index e69de29b..d90ec9f8 100644 --- a/01_week/tasks/length_lit/length_lit.cpp +++ b/01_week/tasks/length_lit/length_lit.cpp @@ -0,0 +1,62 @@ +// в метрах +const double INCH = 0.0254; +const double FOOT = 0.3048; +const double CM = 0.01; + +// перевод из дюймов в метры +double operator"" _in_to_m(long double v) { + return v * INCH; +} +// перевод из дюймов в сантиметры +double operator"" _in_to_cm(long double v) { + double m = v * INCH; + return m / CM; +} +// перевод из дюймов в футы +double operator"" _in_to_ft(long double v) { + double m = v * INCH; + return m / FOOT; +} + +// перевод из футов в метры +double operator"" _ft_to_m(long double v) { + return v * FOOT; +} +// перевод из футов в сантиметры +double operator"" _ft_to_cm(long double v) { + double m = v * FOOT; + return m / CM; +} +// перевод из футов в дюймы +double operator"" _ft_to_in(long double v) { + double m = v * FOOT; + return m / INCH; +} + +// перевод из сантиметров в метры +double operator"" _cm_to_m(long double v) { + return v * CM; +} +// перевод из сантиметров в дюймы +double operator"" _cm_to_in(long double v) { + double m = v * CM; + return m / INCH; +} +// перевод из сантиметров в футы +double operator"" _cm_to_ft(long double v) { + double m = v * CM; + return m / FOOT; +} + +// перевод из метров в сантиметры +double operator"" _m_to_cm(long double v) { + return v / CM; +} +// перевод из метров в дюймы +double operator"" _m_to_in(long double v) { + return v / INCH; +} +// перевод из метров в футы +double operator"" _m_to_ft(long double v) { + return v / FOOT; +} diff --git a/01_week/tasks/print_bits/print_bits.cpp b/01_week/tasks/print_bits/print_bits.cpp index a48a43c1..69e712a7 100644 --- a/01_week/tasks/print_bits/print_bits.cpp +++ b/01_week/tasks/print_bits/print_bits.cpp @@ -1,7 +1,30 @@ #include #include - +// value - целое число, его нужно вывести в двоичной форме +// bytes типа size_t потому что bytes это количсевто байт void PrintBits(long long value, size_t bytes) { - throw std::runtime_error{"Not implemented"}; + // по условию мы не можем выполнить функцию когда у нас + // количсевто байт = 0, либо количесвто байт > 8 + if (bytes == 0 || bytes > 8) { + return; + } + // Считаем общее количсевто бит, 1 байт = 1 бит + size_t bits = bytes * 8; + // выводим префикс "0b", дальше будет идти предствление числа + std::cout << "0b"; + // цикл будет выполняться bits раз + for (size_t i = 0; i < bits; ++i) { + size_t bit_index = bits - 1 - i; + // побитовый сдвиг, сравниваем младший бит с 1 и выводим результат + std::cout << ((value >> bit_index) & 1); + + // если i + 1 делится на 4 без остатка и это не полседний бит, + // ставим "'" + if ((i + 1) % 4 == 0 && (i + 1) != bits) { + std::cout << "'"; + } + } + // перевод строки + std::cout << '\n'; } diff --git a/01_week/tasks/quadratic/quadratic.cpp b/01_week/tasks/quadratic/quadratic.cpp index abf7d632..daa8eb20 100644 --- a/01_week/tasks/quadratic/quadratic.cpp +++ b/01_week/tasks/quadratic/quadratic.cpp @@ -1,6 +1,85 @@ -#include +#include +#include +#include void SolveQuadratic(int a, int b, int c) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + // первый случай: если a = b = c = 0, то уравнение примнимает бесконченое количесвто решений + if (a == 0 && b == 0 && c == 0) { + std::cout << "infinite solutions"; + return; + } + + // второй случай: если a = b = 0, то уравнение решений не имеет + if (a == 0 && b == 0) { + std::cout << "no solutions"; + return; + } + + std::cout << std::setprecision(6); + + // третий случай: a == 0, b != 0 → b*x + c = 0 + if (a == 0) { + double x = -static_cast(c) / static_cast(b); // x = -c / b + + // Убираем возможный "-0" + if (x == -0.0) { + x = 0.0; + } + + std::cout << x; + return; + } + + // 4) четвертый случай: a неравно 0, то есть уже само квадартное уравнение + double A = static_cast(a); + double B = static_cast(b); + double C = static_cast(c); + + // Дискриминант + double D = B * B - 4 * A * C; + + // Нет вещественных корней + if (D < 0) { + std::cout << "no solutions"; + return; + } + + // Один вещественный корень + if (D == 0) { + double root = -B / (2 * A); + double x = static_cast(root); + + // Убираем "-0" + if (x == -0.0) { + x = 0.0; + } + + std::cout << x; + return; + } + + // если D > 0, то имеем два различных корня + double sqrtD = std::sqrt(D); + + double root1 = (-B - sqrtD) / (2 * A); + double root2 = (-B + sqrtD) / (2 * A); + + double x1 = static_cast(root1); + double x2 = static_cast(root2); + + // Убираем "-0" для каждого корня + if (x1 == -0.0) { + x1 = 0.0; + } + if (x2 == -0.0) { + x2 = 0.0; + } + + // выводим так, чтобы x1 < x2 + if (x1 > x2) { + std::swap(x1, x2); + } + + std::cout << x1 << ' ' << x2; +} diff --git a/01_week/tasks/rms/rms.cpp b/01_week/tasks/rms/rms.cpp index 6882f0a9..afc9b67c 100644 --- a/01_week/tasks/rms/rms.cpp +++ b/01_week/tasks/rms/rms.cpp @@ -1,7 +1,19 @@ -#include +#include #include - +#include double CalculateRMS(double values[], size_t size) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + + // в случае пустовго массива возращаем 0.0 + if (size == 0 || values == nullptr) { + return 0.0; + } + + double sumSq = 0.0; + // сумма квадратов + for (size_t i = 0; i < size; ++i) { + sumSq += values[i] * values[i]; + } + // RMS + return std::sqrt(sumSq /size); +} diff --git a/02_week/tasks/func_array/func_array.cpp b/02_week/tasks/func_array/func_array.cpp index b327e68d..3b332cb6 100644 --- a/02_week/tasks/func_array/func_array.cpp +++ b/02_week/tasks/func_array/func_array.cpp @@ -1,6 +1,29 @@ #include +double ApplyOperations( + double a, + double b, + double (*mathOperations[])(double, double), // массив указателей, который принимает два числа типа double + size_t size // рамзер массива +) { + // если массив пуст - возвращаем 0.0 + if (size == 0) { + return 0.0; + } + // переменная для суммы мат операций + double sum = 0.0; + // проходим по каждому элементу массива + for (size_t i = 0; i < size; ++i) { -double ApplyOperations(double a, double b /* other arguments */) { - throw std::runtime_error{"Not implemented"}; + // если один из указателей массива пустой, то пропускаем + if (mathOperations[i] == nullptr) { + continue; // пропускаем пустую функцию + } + // вызываем i-ю функцию с числами a и b, кладем в v + double v = mathOperations[i](a, b); + // прибавляем к общей сумме + sum += v; + } + + return sum; } \ No newline at end of file diff --git a/02_week/tasks/last_of_us/last_of_us.cpp b/02_week/tasks/last_of_us/last_of_us.cpp index c7bf1a25..ae0eeec2 100644 --- a/02_week/tasks/last_of_us/last_of_us.cpp +++ b/02_week/tasks/last_of_us/last_of_us.cpp @@ -1,6 +1,29 @@ #include +// для случая (nullptr, nullptr) +int* FindLastElement(std::nullptr_t, std::nullptr_t, bool (*)(int)) { + return nullptr; +} +// Функция ищет последний элемент, удовлетворяющий предикату, +// в диапазоне [begin, end). Возвращает указатель на найденный элемент. +// Если элемент не найден или диапазон некорректный, возвращает end. +int* FindLastElement(int* begin, int* end, bool (*predicate)(int)) { + if (begin == nullptr || end == nullptr || begin > end || predicate == nullptr) { + return end; + } + // Перебираем элементы с конца диапазона + for (int* i = end - 1; i >= begin; --i) { + if (predicate(*i)) { + return i; // сразу возвращаем первый подходящий справа + } + } -/* return_type */ FindLastElement(/* ptr_type */ begin, /* ptr_type */ end, /* func_type */ predicate) { - throw std::runtime_error{"Not implemented"}; + // если ничего не нашли, то возвращаем end + return end; +} + +// Перегрузка для const int*. +// Снимаем const, чтобы переиспользовать логику из версии для int*. +const int* FindLastElement(const int* begin, const int* end, bool (*predicate)(int)) { + return FindLastElement(const_cast(begin), const_cast(end), predicate); } \ No newline at end of file diff --git a/02_week/tasks/longest/longest.cpp b/02_week/tasks/longest/longest.cpp index 04b3c354..e4a78575 100644 --- a/02_week/tasks/longest/longest.cpp +++ b/02_week/tasks/longest/longest.cpp @@ -1,6 +1,57 @@ -#include +#include +// Функция ищет самую длинную подпоследовательность одинаковых символов +// в диапазоне [begin, end). Длину подпоследовательности записывает в count. +// Возвращает указатель на начало найденной подпоследовательности. +// В случае ошибки возвращает nullptr. В count записывает 0. +char* FindLongestSubsequence(char* begin, char* end, size_t& count) { + // проверка корректнсти + if (begin == nullptr || end == nullptr || begin >= end) { + count = 0; + return nullptr; + } -/* return_type */ FindLongestSubsequence(/* ptr_type */ begin, /* ptr_type */ end, /* type */ count) { - throw std::runtime_error{"Not implemented"}; + char* best_start = begin; // начало лучшей подпоследовательности + size_t best_length = 1; // длина лучшей последовательности + + char* curr_start = begin; // начало текущей последовательности + size_t curr_length = 1; // длина текущей последовательности + + // Перебираем символы, начиная со второго + for (char* i = begin + 1; i < end; ++i) { + // тут проверка на совпадения + // если совпадает, то увеличивам длину текущей подпоследовательности curr_length + if (*i == *(i - 1)) { + ++curr_length; + } else { + // Если текущая последовательность строго длиннее лучшей, то + // обновляем результат. При равных длинах не обновляем, так как + // по условию возвращается первая + if (curr_length > best_length) { + best_start = curr_start; + best_length = curr_length; + } + curr_start = i; // начинаем новую подпоследовательность с текущего символа + curr_length = 1; // начало новой подпоследовательность + } + } + // Проверяем последнюю подпоследовательность (она могла закончится концом строки) + if (curr_length > best_length) { + best_length = curr_length; + best_start = curr_start; + } + // записываем в count лучшую длину + count = best_length; + return best_start; +} + + +// Перегрузка для const char*. +// Код поиска наибольшей подпоследовтаельности уже реализован в версии для char*, +// поэтому здесь будем использовать его, +// временно снимаем const, чтобы вызвать существующую логику +const char* FindLongestSubsequence(const char* begin, const char* end, size_t& count) { + char* result = FindLongestSubsequence(const_cast(begin), const_cast(end), count); + return result; } + diff --git a/02_week/tasks/swap_ptr/swap_ptr.cpp b/02_week/tasks/swap_ptr/swap_ptr.cpp index 93db625d..dc835ee2 100644 --- a/02_week/tasks/swap_ptr/swap_ptr.cpp +++ b/02_week/tasks/swap_ptr/swap_ptr.cpp @@ -1,6 +1,57 @@ #include +#include +// Есть три вида Template parameters: +// 1. constant template parameter +// 2. type template parameter (нам нужен этот) +// 3. template template parameter +template // параметр-тип +void SwapPtr(T*& a, T*& b) { + T* tmp = a; // сохраняем адрес из a + a = b; // кладём в a адрес из b + b = tmp; // в b кладём старый адрес a +} -void SwapPtr(/* write arguments here */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +// версия без использования парметр-тип: +/* void SwapPtr(int*& a, int*& b) { + int* tmp = a; + a = b; + b = tmp; +} + +void SwapPtr(const int*& a, const int*& b) { + const int* tmp = a; + a = b; + b = tmp; +} + +void SwapPtr(int**& a, int**& b) { + int** tmp = a; + a = b; + b = tmp; +} +*/ + + + +// это для визуальной проверки +/* int main() { + int x = 1; + int y = 2; + + int* a = &x; + int* b = &y; + + std::cout << "До SwapPtr\n"; + std::cout << "Адрес a = " << a << ", *a = " << *a << "\n"; + std::cout << "Адрес b = " << b << ", *b = " << *b << "\n"; + + SwapPtr(a, b); + + std::cout << "После SwapPtr\n"; + std::cout << "Адрес a = " << a << ", *a = " << *a << "\n"; + std::cout << "Адрес b = " << b << ", *b = " << *b << "\n"; + + return 0; +} */ + \ No newline at end of file