diff --git a/task_01/src/sum_two_num.cpp b/task_01/src/sum_two_num.cpp new file mode 100644 index 0000000..205107a --- /dev/null +++ b/task_01/src/sum_two_num.cpp @@ -0,0 +1,21 @@ +#include "sum_two_num.h" + +#include + +void FindSumTwoNum(std::vector& vec, int len, int num) { + int left = 0; + int right = len - 1; + + while (left < right) { + int sum = vec[left] + vec[right]; + if (right - left == 0) std::cout << "There are no necessary numbers"; + if (sum == num) { + std::cout << vec[left] << "+" << vec[right] << "=" << num; + break; + } + if (sum < num) + ++left; + else + --right; + } +} \ No newline at end of file diff --git a/task_01/src/sum_two_num.h b/task_01/src/sum_two_num.h new file mode 100644 index 0000000..fc0b84f --- /dev/null +++ b/task_01/src/sum_two_num.h @@ -0,0 +1,3 @@ +#include + +void FindSumTwoNum(std::vector& vec, int len, int num); \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..c5ded81 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,48 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include + +#include "sum_two_num.h" + +static std::string captureOutput(std::vector& vec, int len, int num) { + std::stringstream buffer; + std::streambuf* old = std::cout.rdbuf(buffer.rdbuf()); + + FindSumTwoNum(vec, len, num); + + std::cout.rdbuf(old); + return buffer.str(); +} + +TEST(SumTwoNum, Simple) { + std::vector vec = {1, 2, 3, 4, 6, 8}; + std::string output = captureOutput(vec, 6, 6); + EXPECT_TRUE(output == "2+4=6" || + output == "There are no necessary numbers 2+4=6"); +} + +TEST(SumTwoNum, NoPairFound) { + std::vector vec = {1, 2, 3, 4, 6, 8}; + std::string output = captureOutput(vec, 6, 20); + EXPECT_TRUE(output.empty() || output == "There are no necessary numbers"); +} + +TEST(SumTwoNum, EmptyInput) { + std::vector vec = {}; + std::string output = captureOutput(vec, 0, 5); + EXPECT_TRUE(output.empty() || output == "There are no necessary numbers"); +} + +TEST(SumTwoNum, SingleElement) { + std::vector vec = {5}; + std::string output = captureOutput(vec, 1, 5); + EXPECT_TRUE(output == "There are no necessary numbers" || output.empty()); +} + +TEST(SumTwoNum, EdgeCase) { + std::vector vec = {3, 5}; + std::string output = captureOutput(vec, 2, 8); + EXPECT_TRUE(output == "3+5=8" || + output == "There are no necessary numbers 3+5=8"); } \ No newline at end of file diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..887fdb0 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,36 @@ #include +#include + #include "topology_sort.hpp" -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +TEST(TopologyFuncTest, OrdinaryWeek) { + std::vector temperatures = {73, 74, 75, 71, 69, 72, 76, 73}; + std::vector expected = {1, 1, 4, 2, 1, 1, 0, 0}; + ASSERT_EQ(TopologySort(temperatures), expected); +} + +TEST(TopologyFuncTest, EmptyInput) { + std::vector temperatures = {}; + std::vector expected = {}; + ASSERT_EQ(TopologySort(temperatures), expected); +} + +TEST(TopologyFuncTest, SingleDay) { + std::vector temperatures = {30}; + std::vector expected = {0}; + ASSERT_EQ(TopologySort(temperatures), expected); +} + +TEST(TopologyFuncTest, IncreasingTemperatures) { + std::vector temperatures = {10, 20, 30, 40}; + std::vector expected = {1, 1, 1, 0}; + ASSERT_EQ(TopologySort(temperatures), expected); } + +TEST(TopologyFuncTest, MixedTemperatures) { + std::vector temperatures = {73, 74, 75, 71, 69, 72, 76, 73}; + std::vector expected = {1, 1, 4, 2, 1, 1, 0, 0}; + ASSERT_EQ(TopologySort(temperatures), expected); +} \ No newline at end of file diff --git a/task_03/src/topology_sort.cpp b/task_03/src/topology_sort.cpp index e53f670..07dd4ae 100644 --- a/task_03/src/topology_sort.cpp +++ b/task_03/src/topology_sort.cpp @@ -1 +1,19 @@ #include "topology_sort.hpp" + +#include + +std::vector TopologySort(const std::vector& temperatures) { + std::vector result(temperatures.size(), 0); + std::stack> s; + + for (int i{0}; i < temperatures.size(); ++i) { + while (!s.empty() && temperatures[i] > s.top().first) { + int prev_index = s.top().second; + result[prev_index] = i - prev_index; + s.pop(); + } + s.push({temperatures[i], i}); + } + + return result; +} \ No newline at end of file diff --git a/task_03/src/topology_sort.hpp b/task_03/src/topology_sort.hpp index 6f70f09..8dfa29a 100644 --- a/task_03/src/topology_sort.hpp +++ b/task_03/src/topology_sort.hpp @@ -1 +1,4 @@ #pragma once +#include + +std::vector TopologySort(const std::vector& temperatures); \ No newline at end of file diff --git a/task_04/src/main.cpp b/task_04/src/main.cpp index 0e4393b..526b7fd 100644 --- a/task_04/src/main.cpp +++ b/task_04/src/main.cpp @@ -1,3 +1,5 @@ #include +// Задача на жадный алгоритмы, которые мы будем проходить в следующем семестре +// Разрешили не делать int main() { return 0; } diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..0e02f47 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,9 @@ #include +// Задача на жадный алгоритмы, которые мы будем проходить в следующем семестре +// Разрешили не делать + TEST(TopologySort, Simple) { ASSERT_EQ(1, 1); // Stack [] } diff --git a/task_05/src/bubble_sort.cpp b/task_05/src/bubble_sort.cpp new file mode 100644 index 0000000..aa6698a --- /dev/null +++ b/task_05/src/bubble_sort.cpp @@ -0,0 +1,14 @@ +#include "bubble_sort.hpp" + +void BubbleSort(std::vector& vec) { + int n = vec.size(); + + while (n > 1) { + for (size_t j = 0; j < n - 1; j++) { + if (vec[j] > vec[j + 1]) { + std::swap(vec[j], vec[j + 1]); + } + } + n--; + } +} \ No newline at end of file diff --git a/task_05/src/bubble_sort.hpp b/task_05/src/bubble_sort.hpp new file mode 100644 index 0000000..7f78f60 --- /dev/null +++ b/task_05/src/bubble_sort.hpp @@ -0,0 +1,18 @@ +/* Сортировка пузырьком +Выполняется некоторое количество проходов по массиву — начиная от начала +массива, перебираются пары соседних элементов массива. Если 1-й элемент пары +больше 2-го, элементы переставляются (выполняется обмен). Пары элементов массива +перебираются (проходы по массиву повторяются) либо (n - 1) раз либо до тех пор, +пока на очередном проходе не обнаружится, что более не требуется выполнять +перестановки (обмены) (массив отсортирован). При каждом проходе алгоритма по +внутреннему циклу очередной наибольший элемент массива ставится на своё место в +конце массива рядом с предыдущим «наибольшим элементом», а наименьший элемент +перемещается на одну позицию к началу массива (как бы «всплывает» до нужной +позиции, как пузырёк в воде — откуда и название алгоритма). +*/ + +// В худшем и среднем случае O( n^2 ). В лучшем случае O( n ) + +#include + +void BubbleSort(std::vector& vec); \ No newline at end of file diff --git a/task_05/src/insertion_sort.cpp b/task_05/src/insertion_sort.cpp new file mode 100644 index 0000000..1c686fe --- /dev/null +++ b/task_05/src/insertion_sort.cpp @@ -0,0 +1,17 @@ +#include "insertion_sort.hpp" + +void InsertionSort(std::vector& vec) { + int n = vec.size(); + + for (size_t i = 0; i < n; i++) { + for (size_t j = i; j > 0; j--) { + if (vec[j] < vec[j - 1]) { + std::swap(vec[j], vec[j - 1]); + continue; + } + if (vec[j] >= vec[j - 1]) { + break; + } + } + } +} \ No newline at end of file diff --git a/task_05/src/insertion_sort.hpp b/task_05/src/insertion_sort.hpp new file mode 100644 index 0000000..f0338fa --- /dev/null +++ b/task_05/src/insertion_sort.hpp @@ -0,0 +1,11 @@ +/* Сортировка вставкой +Aлгоритм сортировки, в котором элементы входной последовательности +просматриваются по одному, и каждый новый поступивший элемент размещается в +подходящее место среди ранее упорядоченных элементов +*/ + +// В худшем и среднем случае O( n^2 ). В лучшем случае O( n ) + +#include + +void InsertionSort(std::vector& vec); \ No newline at end of file diff --git a/task_05/src/merge_sort.cpp b/task_05/src/merge_sort.cpp new file mode 100644 index 0000000..db66b0c --- /dev/null +++ b/task_05/src/merge_sort.cpp @@ -0,0 +1,49 @@ +#include "merge_sort.hpp" + +int Mmax(int a, int b) { return a >= b ? a : b; } +int Mmin(int a, int b) { return a <= b ? a : b; } + +std::vector Sslice(const std::vector& vector, const size_t from, + const size_t to) { + if (from < to) + return std::vector{vector.begin() + from, vector.begin() + to}; + else + return std::vector{}; +} + +std::vector Merge(std::vector& left, std::vector& right) { + std::vector nw; + size_t i_l = 0; + size_t i_r = 0; + size_t size_l = left.size(); + size_t size_r = right.size(); + while (i_l < size_l && i_r < size_r) { + if (left[i_l] < right[i_r]) { + nw.push_back(left[i_l]); + ++i_l; + } else { + nw.push_back(right[i_r]); + ++i_r; + } + } + if (i_l >= size_l) { + for (size_t i = i_r; i < size_r; ++i) nw.push_back(right[i]); + return nw; + } + if (i_r >= size_r) { + for (size_t i = i_l; i < size_l; ++i) nw.push_back(left[i]); + return nw; + } + return nw; +} +void MergeSort(std::vector& vec) { + int n = vec.size(); + if (n <= 1) return; + std::vector left = Sslice(vec, 0, n / 2); + std::vector right = Sslice(vec, n / 2, n); + + MergeSort(left); + MergeSort(right); + + vec = Merge(left, right); +} \ No newline at end of file diff --git a/task_05/src/merge_sort.hpp b/task_05/src/merge_sort.hpp new file mode 100644 index 0000000..c8fd70d --- /dev/null +++ b/task_05/src/merge_sort.hpp @@ -0,0 +1,35 @@ +/* Сортировка +слиянием + +1. Сортируемый массив разбивается на две части примерно одинакового размера; +2. Каждая из получившихся частей сортируется отдельно, например — тем же самым +алгоритмом; +3. Два упорядоченных массива половинного размера соединяются в один. +1.1. — 2.1. Рекурсивное разбиение задачи на меньшие происходит до тех пор, пока +размер массива не достигнет единицы (любой массив длины 1 можно считать +упорядоченным). + +3.1. Соединение двух упорядоченных массивов в один. +Основную идею слияния двух отсортированных массивов можно объяснить на следующем +примере. Пусть мы имеем два уже отсортированных по возрастанию подмассива. +Тогда: 3.2. Слияние двух подмассивов в третий результирующий массив. На каждом +шаге мы берём меньший из двух первых элементов подмассивов и записываем его в +результирующий массив. Счётчики номеров элементов результирующего массива и +подмассива, из которого был взят элемент, увеличиваем на 1. 3.3. «Прицепление» +остатка. Когда один из подмассивов закончился, мы добавляем все оставшиеся +элементы второго подмассива в результирующий массив. +*/ + +// Всегда (и в среднем, и в худшем, и в лучшем случае) O(n*log(n)) + +#include + +int Mmax(int a, int b); +int Mmin(int a, int b); + +std::vector Sslice(const std::vector& vector, const size_t from, + const size_t to); + +std::vector Merge(std::vector& left, std::vector& right); + +void MergeSort(std::vector& vec); diff --git a/task_05/src/q_sort.cpp b/task_05/src/q_sort.cpp new file mode 100644 index 0000000..c502efd --- /dev/null +++ b/task_05/src/q_sort.cpp @@ -0,0 +1,35 @@ +#include "q_sort.hpp" + +#include +#include + +int Partition(std::vector &arr, int low, int high) { + int pivot_index = low + rand() % (high - low + 1); + int pivot = arr[pivot_index]; + + std::swap(arr[pivot_index], arr[high]); + + int i = low; // Указатель на место для следующего меньшего элемента + + for (int j = low; j < high; j++) { + if (arr[j] <= pivot) { + std::swap(arr[i], arr[j]); + i++; + } + } + // Возвращаем опорный элемент на правильную позицию + std::swap(arr[i], arr[high]); + return i; +} + +void QSortWithI(std::vector &arr, int low, int high) { + if (low < high) { + // pi - индекс разделения, arr[pi] теперь на правильном месте + int pi = Partition(arr, low, high); + + QSortWithI(arr, low, pi - 1); + QSortWithI(arr, pi + 1, high); + } +} + +void QSort(std::vector &arr) { QSortWithI(arr, 0, arr.size() - 1); } diff --git a/task_05/src/q_sort.hpp b/task_05/src/q_sort.hpp new file mode 100644 index 0000000..a433073 --- /dev/null +++ b/task_05/src/q_sort.hpp @@ -0,0 +1,11 @@ +/* +Добавил другой вариант быстрой сортировки +*/ + +#include + +int Partition(std::vector& arr, int low, int high); + +void QSortWithI(std::vector& arr, int low, int high); + +void QSort(std::vector& arr); \ No newline at end of file diff --git a/task_05/src/quick_sort.cpp b/task_05/src/quick_sort.cpp new file mode 100644 index 0000000..005ec6c --- /dev/null +++ b/task_05/src/quick_sort.cpp @@ -0,0 +1,30 @@ +#include "quick_sort.hpp" + +void QuickSortWithI(std::vector& vec, int first, int last) { + if (last - first <= 0) return; + int index_big = last + 1; + for (size_t i = first + 1; i <= last; ++i) { + if (vec[i] > vec[first]) { + if (index_big != last + 1) continue; + index_big = i; + } else { + if (index_big == last + 1) + continue; + else { + int tmp = vec[index_big]; + vec[index_big] = vec[i]; + vec[i] = tmp; + index_big++; + } + } + } + int tmp = vec[index_big - 1]; + vec[index_big - 1] = vec[first]; + vec[first] = tmp; + QuickSortWithI(vec, first, index_big - 2); + QuickSortWithI(vec, index_big, last); +} + +void QuickSort(std::vector& vec) { + QuickSortWithI(vec, 0, vec.size() - 1); +} \ No newline at end of file diff --git a/task_05/src/quick_sort.hpp b/task_05/src/quick_sort.hpp new file mode 100644 index 0000000..f90b5ec --- /dev/null +++ b/task_05/src/quick_sort.hpp @@ -0,0 +1,28 @@ +/* Быстрая сортировка, сортировка Хоара (англ. +quicksort), часто называемая qsort Выбрать из массива элемент, называемый +опорным. Это может быть любой из элементов массива. От выбора опорного элемента +не зависит корректность алгоритма, но в отдельных случаях может сильно зависеть +его эффективность. Сравнить все остальные элементы с опорным и переставить их в +массиве так, чтобы разбить массив на три непрерывных отрезка, следующих друг за +другом: «элементы меньшие опорного», «равные» и «большие». Для отрезков +«меньших» и «больших» значений выполнить рекурсивно ту же последовательность +операций, если длина отрезка больше единицы. + +Алгоритм состоит из трёх шагов: +1. Выбрать элемент из массива. Назовём его опорным. +2. Разбиение: перераспределение элементов в массиве таким образом, что элементы, +меньшие опорного, помещаются перед ним, а большие или равные — после. +3. Рекурсивно применить первые два шага к двум подмассивам слева и справа от +опорного элемента. Рекурсия не применяется к массиву, в котором только один +элемент или отсутствуют элементы. +*/ + +// В худшем случае O( n^2 ). В среднем O( n*log(n) ). +// В лучшем случае O( n*log(n) ) (обычное разделение) или O( n ) (разделение на +// 3 части) + +#include + +void QuickSortWithI(std::vector& vec, int first, int last); + +void QuickSort(std::vector& vec); \ No newline at end of file diff --git a/task_05/src/selection_sort.cpp b/task_05/src/selection_sort.cpp new file mode 100644 index 0000000..7667dd8 --- /dev/null +++ b/task_05/src/selection_sort.cpp @@ -0,0 +1,24 @@ +#include "selection_sort.hpp" + +int Maxx(int a, int b) { return a >= b ? a : b; } +int Minn(int a, int b) { return a <= b ? a : b; } + +std::vector Slice(const std::vector& vector, const size_t from, + const size_t to) { + if (from < to) + return std::vector{vector.begin() + from, vector.begin() + to}; + else + return std::vector{}; +} + +void SelectionSort(std::vector& vec) { + int n = vec.size(); + + for (size_t i = 0; i < n; i++) { + int min_i = i; + for (size_t j = i; j < n; j++) { + vec[min_i] > vec[j] ? min_i = j : min_i = min_i; + } + std::swap(vec[i], vec[min_i]); + } +} \ No newline at end of file diff --git a/task_05/src/selection_sort.hpp b/task_05/src/selection_sort.hpp new file mode 100644 index 0000000..0d044ac --- /dev/null +++ b/task_05/src/selection_sort.hpp @@ -0,0 +1,20 @@ +/* Сортировка выбором +Шаги алгоритма: +1. Находим номер минимального значения в текущем списке. +2. Производим обмен этого значения со значением первой неотсортированной позиции +(обмен не нужен, если минимальный элемент уже находится на данной позиции). +3. Теперь сортируем хвост списка, исключив из рассмотрения уже отсортированные +элементы. +*/ + +// Всегда (и в среднем, и в худшем, и в лучшем случае) O( n^2 ) + +#include + +int Maxx(int a, int b); +int Minn(int a, int b); + +std::vector Slice(const std::vector& vector, const size_t from, + const size_t to); + +void SelectionSort(std::vector& vec); \ No newline at end of file diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617..6aca59a 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,128 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "bubble_sort.hpp" +#include "insertion_sort.hpp" +#include "merge_sort.hpp" +#include "q_sort.hpp" +#include "quick_sort.hpp" +#include "selection_sort.hpp" + +TEST(BUBBLE, Simple) { + std::vector vec1{5, 2, 7, 1, 3, 9, 8, 4, 6, 10}; + std::vector true_answer1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + BubbleSort(vec1); + ASSERT_EQ(vec1, true_answer1); +} + +TEST(BUBBLE, NegAndPos) { + std::vector vec2{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector true_answer2{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + BubbleSort(vec2); + ASSERT_EQ(vec2, true_answer2); +} + +TEST(BUBBLE, RepeatingNumbers) { + std::vector vec3{2, 3, -1, 4, 4, 3, 2, 4, 3, 4}; + std::vector true_answer3{-1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + BubbleSort(vec3); + ASSERT_EQ(vec3, true_answer3); +} + +TEST(INSERTION, Simple) { + std::vector vec1{5, 2, 7, 1, 3, 9, 8, 4, 6, 10}; + std::vector true_answer1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + InsertionSort(vec1); + ASSERT_EQ(vec1, true_answer1); +} +TEST(INSERTION, NegAndPos) { + std::vector vec2{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector true_answer2{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + InsertionSort(vec2); + ASSERT_EQ(vec2, true_answer2); +} + +TEST(INSERTION, RepeatingNumbers) { + std::vector vec3{2, 3, -1, 4, 4, 3, 2, 4, 3, 4}; + std::vector true_answer3{-1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + InsertionSort(vec3); + ASSERT_EQ(vec3, true_answer3); +} +TEST(MERGE, Simple) { + std::vector vec1{5, 2, 7, 1, 3, 9, 8, 4, 6, 10}; + std::vector true_answer1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + MergeSort(vec1); + ASSERT_EQ(vec1, true_answer1); +} +TEST(MERGE, NegAndPos) { + std::vector vec2{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector true_answer2{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + MergeSort(vec2); + ASSERT_EQ(vec2, true_answer2); } + +TEST(MERGE, RepeatingNumbers) { + std::vector vec3{2, 3, -1, 4, 4, 3, 2, 4, 3, 4}; + std::vector true_answer3{-1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + MergeSort(vec3); + ASSERT_EQ(vec3, true_answer3); +} +TEST(QUICK, Simple) { + std::vector vec1{5, 2, 7, 1, 3, 9, 8, 4, 6, 10}; + std::vector true_answer1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + QuickSort(vec1); + ASSERT_EQ(vec1, true_answer1); +} +TEST(QUICK, NegAndPos) { + std::vector vec2{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector true_answer2{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + QuickSort(vec2); + ASSERT_EQ(vec2, true_answer2); +} + +TEST(QUICK, RepeatingNumbers) { + std::vector vec3{2, 3, -1, 4, 4, 3, 2, 4, 3, 4}; + std::vector true_answer3{-1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + QuickSort(vec3); + ASSERT_EQ(vec3, true_answer3); +} +TEST(Q, Simple) { + std::vector vec1{5, 2, 7, 1, 3, 9, 8, 4, 6, 10}; + std::vector true_answer1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + QSort(vec1); + ASSERT_EQ(vec1, true_answer1); +} +TEST(Q, NegAndPos) { + std::vector vec2{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector true_answer2{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + QSort(vec2); + ASSERT_EQ(vec2, true_answer2); +} + +TEST(Q, RepeatingNumbers) { + std::vector vec3{2, 3, -1, 4, 4, 3, 2, 4, 3, 4}; + std::vector true_answer3{-1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + QSort(vec3); + ASSERT_EQ(vec3, true_answer3); +} +TEST(SELECTION, Simple) { + std::vector vec1{5, 2, 7, 1, 3, 9, 8, 4, 6, 10}; + std::vector true_answer1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + SelectionSort(vec1); + ASSERT_EQ(vec1, true_answer1); +} +TEST(SELECTION, NegAndPos) { + std::vector vec2{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector true_answer2{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + SelectionSort(vec2); + ASSERT_EQ(vec2, true_answer2); +} + +TEST(SELECTION, RepeatingNumbers) { + std::vector vec3{2, 3, -1, 4, 4, 3, 2, 4, 3, 4}; + std::vector true_answer3{-1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + SelectionSort(vec3); + ASSERT_EQ(vec3, true_answer3); +} \ No newline at end of file diff --git a/task_06/src/k_stat.cpp b/task_06/src/k_stat.cpp new file mode 100644 index 0000000..64729fc --- /dev/null +++ b/task_06/src/k_stat.cpp @@ -0,0 +1,46 @@ +#include "k_stat.hpp" + +#include +#include +#include + +int Partition(std::vector& arr, int left, int right) { + int pivot_index = 0; + if (right - left + 1) pivot_index = left + rand() % (right - left + 1); + + int pivot_value = arr[pivot_index]; + + std::swap(arr[pivot_index], arr[right]); + + int store_index = left; + for (int i = left; i < right; i++) { + if (arr[i] < pivot_value) { + std::swap(arr[i], arr[store_index]); + store_index++; + } + } + + std::swap(arr[store_index], arr[right]); + return store_index; +} + +int QuickSelect(std::vector& arr, int left, int right, int k) { + if (left == right) return arr[left]; + + int pivot_index = Partition(arr, left, right); + + if (k == pivot_index) + return arr[k]; + else if (k < pivot_index) + return QuickSelect(arr, left, pivot_index - 1, k); + else + return QuickSelect(arr, pivot_index + 1, right, k); +} + +int FindKStat(std::vector& arr, int n) { + if (n < 0 || n >= arr.size()) { + std::cerr << "Invalid n: out of bounds!" << '\n'; + return -1; + } + return QuickSelect(arr, 0, arr.size() - 1, n); +} \ No newline at end of file diff --git a/task_06/src/k_stat.hpp b/task_06/src/k_stat.hpp new file mode 100644 index 0000000..baa0f02 --- /dev/null +++ b/task_06/src/k_stat.hpp @@ -0,0 +1,7 @@ +#include + +int Partition(std::vector& arr, int left, int right); + +int QuickSelect(std::vector& arr, int left, int right, int k); + +int FindKStat(std::vector& arr, int n); \ No newline at end of file diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617..d1e69d0 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,30 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "k_stat.hpp" +TEST(KSTAT, Simple) { + std::vector vec1{5, 2, 7, 1, 3, 9, 8, 4, 6, 10}; + std::vector sorted_vec1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int k = 5; + int stat1 = FindKStat(vec1, k); + int true_answer1 = sorted_vec1[k]; + ASSERT_EQ(stat1, true_answer1); } + +TEST(KSTAT, NegAndPos) { + std::vector vec2{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector sorted_vec2{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + int k = 5; + int stat2 = FindKStat(vec2, k); + int true_answer2 = sorted_vec2[k]; + ASSERT_EQ(stat2, true_answer2); +} + +TEST(KSTAT, RepeatingNumbers) { + std::vector vec3{-1, 1, 0, 5, 4, -3, 2, -4, -2, 3, -5}; + std::vector sorted_vec3{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + int k = 5; + int stat3 = FindKStat(vec3, k); + int true_answer3 = sorted_vec3[k]; + ASSERT_EQ(stat3, true_answer3); +} \ No newline at end of file diff --git a/task_07/src/test.cpp b/task_07/src/test.cpp index 5e11617..992d1cf 100644 --- a/task_07/src/test.cpp +++ b/task_07/src/test.cpp @@ -1,6 +1,150 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "tree.h" + +TEST(AVL_TREE, InsertAndInOrder) { + AVLTree tree; + tree.Insert(5); + tree.Insert(2); + tree.Insert(7); + tree.Insert(1); + tree.Insert(3); + + std::vector expected{1, 2, 3, 5, 7}; + ASSERT_EQ(tree.InOrder(), expected); } + +TEST(AVL_TREE, Contains) { + AVLTree tree; + tree.Insert(10); + tree.Insert(20); + tree.Insert(30); + + ASSERT_TRUE(tree.Contains(10)); + ASSERT_TRUE(tree.Contains(20)); + ASSERT_TRUE(tree.Contains(30)); + ASSERT_FALSE(tree.Contains(15)); + ASSERT_FALSE(tree.Contains(0)); +} + +TEST(AVL_TREE, RemoveLeaf) { + AVLTree tree; + tree.Insert(50); + tree.Insert(30); + tree.Insert(70); + tree.Insert(20); + tree.Insert(40); + + tree.Remove(20); + std::vector expected{30, 40, 50, 70}; + ASSERT_EQ(tree.InOrder(), expected); +} + +TEST(AVL_TREE, RemoveNodeWithOneChild) { + AVLTree tree; + tree.Insert(50); + tree.Insert(30); + tree.Insert(70); + tree.Insert(40); + + tree.Remove(30); + std::vector expected{40, 50, 70}; + ASSERT_EQ(tree.InOrder(), expected); +} + +TEST(AVL_TREE, RemoveNodeWithTwoChildren) { + AVLTree tree; + tree.Insert(50); + tree.Insert(30); + tree.Insert(70); + tree.Insert(20); + tree.Insert(40); + tree.Insert(60); + tree.Insert(80); + + tree.Remove(50); + std::vector expected{20, 30, 40, 60, 70, 80}; + ASSERT_EQ(tree.InOrder(), expected); +} + +TEST(AVL_TREE, BalanceAfterInsert) { + AVLTree tree; + tree.Insert(10); + tree.Insert(20); + tree.Insert(30); // Должно вызвать левый поворот + + std::vector expected{10, 20, 30}; + ASSERT_EQ(tree.InOrder(), expected); +} + +TEST(AVL_TREE, BalanceAfterRemove) { + AVLTree tree; + tree.Insert(50); + tree.Insert(30); + tree.Insert(70); + tree.Insert(20); + tree.Insert(40); + tree.Insert(60); + tree.Insert(80); + + tree.Remove(20); // Может вызвать балансировку + tree.Remove(40); // Может вызвать балансировку + + std::vector expected{30, 50, 60, 70, 80}; + ASSERT_EQ(tree.InOrder(), expected); +} + +TEST(AVL_TREE, EmptyTree) { + AVLTree tree; + ASSERT_FALSE(tree.Contains(10)); + ASSERT_TRUE(tree.InOrder().empty()); + + tree.Remove(10); // Не должно упасть + ASSERT_TRUE(tree.InOrder().empty()); +} + +TEST(AVL_TREE, RepeatedElements) { + AVLTree tree; + tree.Insert(5); + tree.Insert(5); + tree.Insert(2); + tree.Insert(2); + tree.Insert(7); + + std::vector expected{2, 2, 5, 5, 7}; + ASSERT_EQ(tree.InOrder(), expected); +} + +TEST(AVL_TREE, ComplexTest) { + AVLTree tree; + tree.Insert(50); + tree.Insert(30); + tree.Insert(70); + tree.Insert(20); + tree.Insert(40); + tree.Insert(60); + tree.Insert(80); + tree.Insert(15); + tree.Insert(25); + tree.Insert(35); + tree.Insert(45); + tree.Insert(55); + tree.Insert(65); + tree.Insert(75); + tree.Insert(85); + + // Проверка содержимого + ASSERT_TRUE(tree.Contains(50)); + ASSERT_TRUE(tree.Contains(25)); + ASSERT_FALSE(tree.Contains(100)); + + // Удаление нескольких элементов + tree.Remove(50); + tree.Remove(20); + tree.Remove(80); + + std::vector expected{15, 25, 30, 35, 40, 45, 55, 60, 65, 70, 75, 85}; + ASSERT_EQ(tree.InOrder(), expected); +} \ No newline at end of file diff --git a/task_07/src/tree.h b/task_07/src/tree.h new file mode 100644 index 0000000..9a0c8d4 --- /dev/null +++ b/task_07/src/tree.h @@ -0,0 +1,145 @@ +#ifndef AVL_TREE_H +#define AVL_TREE_H + +#include +#include +#include + +/* +Особенностью АВЛ-дерева является то, что оно является сбалансированным в +следующем смысле: для любого узла дерева высота его правого поддерева отличается +от высоты левого поддерева не более чем на единицу. +*/ + +template +class AVLTree { + private: + struct Node { + T val; + int h; + std::shared_ptr left; + std::shared_ptr right; + + Node(T val) : val(val), h(1), left(nullptr), right(nullptr) {} + }; + + std::shared_ptr root; + + int Height(std::shared_ptr node) const { return node ? node->h : 0; } + + int BalanceFactor(std::shared_ptr node) const { + return Height(node->right) - Height(node->left); + } + + void UpdateHeight(std::shared_ptr node) { + node->h = std::max(Height(node->left), Height(node->right)) + 1; + } + + std::shared_ptr RotateRight(std::shared_ptr y) { + auto x = y->left; + y->left = x->right; + x->right = y; + UpdateHeight(y); + UpdateHeight(x); + return x; + } + + std::shared_ptr RotateLeft(std::shared_ptr x) { + auto y = x->right; + x->right = y->left; + y->left = x; + UpdateHeight(x); + UpdateHeight(y); + return y; + } + + std::shared_ptr Balance(std::shared_ptr node) { + UpdateHeight(node); + + if (BalanceFactor(node) == 2) { + if (BalanceFactor(node->right) < 0) + node->right = RotateRight(node->right); + return RotateLeft(node); + } + + if (BalanceFactor(node) == -2) { + if (BalanceFactor(node->left) > 0) node->left = RotateLeft(node->left); + return RotateRight(node); + } + + return node; + } + + std::shared_ptr Insert(std::shared_ptr node, T val) { + if (!node) return std::make_shared(val); + + if (val < node->val) + node->left = Insert(node->left, val); + else + node->right = Insert(node->right, val); + + return Balance(node); + } + + std::shared_ptr FindMin(std::shared_ptr node) const { + return node->left ? FindMin(node->left) : node; + } + + std::shared_ptr RemoveMin(std::shared_ptr node) { + if (!node->left) return node->right; + node->left = RemoveMin(node->left); + return Balance(node); + } + + std::shared_ptr Remove(std::shared_ptr node, T val) { + if (!node) return nullptr; + + if (val < node->val) { + node->left = Remove(node->left, val); + } else if (val > node->val) { + node->right = Remove(node->right, val); + } else { + auto left = node->left; + auto right = node->right; + + if (!right) return left; + + auto min = FindMin(right); + min->right = RemoveMin(right); + min->left = left; + + return Balance(min); + } + + return Balance(node); + } + + bool Contains(std::shared_ptr node, T val) const { + if (!node) return false; + if (val == node->val) return true; + return val < node->val ? Contains(node->left, val) + : Contains(node->right, val); + } + + void InOrder(std::shared_ptr node, std::vector& result) const { + if (!node) return; + InOrder(node->left, result); + result.push_back(node->val); + InOrder(node->right, result); + } + + public: + AVLTree() : root(nullptr) {} + + void Insert(T val) { root = Insert(root, val); } + void Remove(T val) { root = Remove(root, val); } + bool Contains(T val) const { return Contains(root, val); } + + std::vector InOrder() const { + std::vector result; + InOrder(root, result); + return result; + } +}; + +#endif // AVL_TREE_H \ No newline at end of file