diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 267b2ec0..0c6e9a57 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -26,10 +26,6 @@ jobs: working-directory: ${{github.workspace}}/build run: make - - name: Test task 01 - working-directory: ${{github.workspace}}/build - run: ./task_01/task_01_tests - - name: Test task 02 working-directory: ${{github.workspace}}/build run: ./task_02/task_02_tests diff --git a/task_01/CMakeLists.txt b/task_01/CMakeLists.txt deleted file mode 100644 index 0e239848..00000000 --- a/task_01/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME}) -project(${PROJECT_NAME} C CXX) - -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -file(GLOB_RECURSE source_list "src/*.cpp" "src/*.hpp") -file(GLOB_RECURSE lib_source_list "../lib/src/*.cpp" "../lib/src/*.hpp") -file(GLOB_RECURSE main_source_list "src/main.cpp") -file(GLOB_RECURSE test_source_list "src/*.cpp") -file(GLOB_RECURSE test_list "src/*test.cpp") - -list(REMOVE_ITEM test_source_list ${main_source_list}) -list(REMOVE_ITEM source_list ${test_list}) - -include_directories(${PROJECT_NAME} PUBLIC src) -include_directories(${PROJECT_NAME} PUBLIC ../lib/src) - -add_executable(${PROJECT_NAME} ${source_list}) -target_link_libraries(${PROJECT_NAME} PUBLIC Utils) - -# Locate GTest -enable_testing() -find_package(GTest REQUIRED) -include_directories(${GTEST_INCLUDE_DIRS}) - -# Link runTests with what we want to test and the GTest and pthread library -add_executable(${PROJECT_NAME}_tests ${test_source_list}) -target_link_libraries( - ${PROJECT_NAME}_tests - GTest::gtest_main - Utils -) - -include(GoogleTest) -gtest_discover_tests(${PROJECT_NAME}_tests) diff --git a/task_01/README.md b/task_01/README.md deleted file mode 100644 index 8ceb5d4e..00000000 --- a/task_01/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Задача 1 - -Дано целое число и отсортированый массив целых чисел, нужно найти 2 числа из массива которые в сумме дадут заданное число diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp deleted file mode 100644 index 0e4393ba..00000000 --- a/task_01/src/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { return 0; } diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp deleted file mode 100644 index ef5a86ae..00000000 --- a/task_01/src/test.cpp +++ /dev/null @@ -1,8 +0,0 @@ - -#include - -#include "topology_sort.hpp" - -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] -} diff --git a/task_01/src/topology_sort.cpp b/task_01/src/topology_sort.cpp deleted file mode 100644 index e53f670c..00000000 --- a/task_01/src/topology_sort.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "topology_sort.hpp" diff --git a/task_01/src/topology_sort.hpp b/task_01/src/topology_sort.hpp deleted file mode 100644 index 6f70f09b..00000000 --- a/task_01/src/topology_sort.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/task_02/src/stack.cpp b/task_02/src/stack.cpp index 8ca89902..07b091de 100644 --- a/task_02/src/stack.cpp +++ b/task_02/src/stack.cpp @@ -1,21 +1,51 @@ #include "stack.hpp" -#include +#include +#include -void Stack::Push(int value) { data_.push(value); } +void Stack::Push(int value) { + auto p = std::make_shared(value); + if (top == nullptr) { + top = p; + } else { + p->next = top; + top = p; + } +} int Stack::Pop() { - auto result = data_.top(); - data_.pop(); - return result; + if (top == nullptr) { + throw std::logic_error("out_of_range"); + } + int val = top->value; + top = top->next; + return val; } -void MinStack::Push(int value) { data_.push_back(value); } +void MinStack::Push(int value) { + if (stack_.top == nullptr) { + stack_.Push(value); + min_stack_.Push(value); + return; + } + + if (stack_.top->value > value) { + min_stack_.Push(value); + } else { + stack_.Push(value); + min_stack_.Push(min_stack_.top->value); + } +} int MinStack::Pop() { - auto result = data_.back(); - data_.pop_back(); - return result; + if (stack_.top == nullptr) { + throw std::logic_error("out_of_range"); + } + + int val = stack_.top->value; + stack_.top = stack_.top->next; + min_stack_.top = min_stack_.top->next; + return val; } -int MinStack::GetMin() { return *std::min_element(data_.begin(), data_.end()); } \ No newline at end of file +int MinStack::GetMin() { return min_stack_.top->value; } diff --git a/task_02/src/stack.hpp b/task_02/src/stack.hpp index 138ec40f..9c42ef71 100644 --- a/task_02/src/stack.hpp +++ b/task_02/src/stack.hpp @@ -1,15 +1,19 @@ #pragma once +#include +#include -#include -#include +struct Node { + int value; + std::shared_ptr next{nullptr}; + Node(int value) : value(value) {} +}; class Stack { public: + Stack() { top = nullptr; } void Push(int value); int Pop(); - - private: - std::stack data_; + std::shared_ptr top; }; class MinStack { @@ -19,5 +23,6 @@ class MinStack { int GetMin(); private: - std::vector data_; + Stack stack_; + Stack min_stack_; }; diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp index 54e7ce90..53330dab 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -1,7 +1,7 @@ - #include #include +#include #include "stack.hpp" @@ -39,4 +39,52 @@ TEST(MinStackTest, Simple) { ASSERT_EQ(stack.GetMin(), 1); ASSERT_EQ(stack.Pop(), 3); // Stack [1] ASSERT_EQ(stack.Pop(), 1); // Stack [] -} \ No newline at end of file +} + +TEST(MinStackTest, Complex) { + MinStack stack; + stack.Push(2); + ASSERT_EQ(stack.GetMin(), 2); + stack.Push(1); + ASSERT_EQ(stack.GetMin(), 1); + stack.Push(3); + ASSERT_EQ(stack.GetMin(), 1); + stack.Pop(); + ASSERT_EQ(stack.GetMin(), 1); + stack.Pop(); + ASSERT_EQ(stack.GetMin(), 2); +} + +TEST(StackTest, Empty) { + Stack stack; + ASSERT_THROW(stack.Pop(), std::logic_error); // Проверяем, что Pop() вызывает + // исключение, если стек пустой + stack.Push(1); + ASSERT_NO_THROW(stack.Pop()); // Проверяем, что Pop() не вызывает исключение, + // если в стеке есть элементы +} + +TEST(StackTest, Behavior) { + Stack stack; + stack.Push(1); // Stack [1] + stack.Push(2); // Stack [1, 2] + ASSERT_EQ(stack.Pop(), 2); // Stack [1] + stack.Push(3); // Stack [1, 3] + ASSERT_EQ(stack.Pop(), 3); // Stack [1] + ASSERT_EQ(stack.Pop(), 1); // Stack [] +} + +// Тесты для MinStack +TEST(MinStackTest, Behavior) { + MinStack stack; + stack.Push(2); // Stack [2] + ASSERT_EQ(stack.GetMin(), 2); // Минимальный элемент равен 2 + stack.Push(1); // Stack [2, 1] + ASSERT_EQ(stack.GetMin(), 1); // Минимальный элемент обновляется до 1 + stack.Push(3); // Stack [2, 1, 3] + ASSERT_EQ(stack.GetMin(), 1); // Минимальный элемент остается 1 + ASSERT_EQ(stack.Pop(), 3); // Stack [2, 1] + ASSERT_EQ(stack.GetMin(), 1); // Минимальный элемент остается 1 + ASSERT_EQ(stack.Pop(), 2); // Stack [2] + ASSERT_EQ(stack.GetMin(), 2); // Минимальный элемент обновляется до 2 +} diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86ae..b0b41a18 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,51 @@ - #include #include "topology_sort.hpp" +//Простые тесты TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] + ASSERT_EQ(RiseTemperature(std::vector{1, 2, 3, 4, 5}), + (std::vector{1, 1, 1, 1, 0})); + ASSERT_EQ(RiseTemperature(std::vector{5, 4, 3, 2, 1}), + (std::vector{0, 0, 0, 0, 0})); + ASSERT_EQ( + RiseTemperature(std::vector{-3, 0, 1, 23, 4, 5, 12, 1, 2, 1, 3}), + (std::vector{1, 1, 1, 0, 1, 1, 0, 1, 2, 1, 0})); + ASSERT_EQ( + RiseTemperature(std::vector{12, 14, 2, 12, 11, 10, 0, 5, 3, 20, 4}), + (std::vector{1, 8, 1, 6, 5, 4, 1, 2, 1, 0, 0})); + ASSERT_EQ( + RiseTemperature(std::vector{11, -2, 3, 1, 5, 2, 6, 3, 7, 84, 4}), + (std::vector{9, 1, 2, 1, 2, 1, 2, 1, 1, 0, 0})); + ASSERT_EQ(RiseTemperature(std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9}), + (std::vector{1, 1, 1, 1, 1, 1, 1, 1, 0})); +} + +// Тестирование поведения при убывающих температурах +TEST(TopologySort, DecreasingTemperature) { + ASSERT_EQ(RiseTemperature(std::vector{10, 9, 8, 7, 6}), + (std::vector{0, 0, 0, 0, 0})); +} + +// Тестирование поведения при возрастающих температурах +TEST(TopologySort, IncreasingTemperature) { + ASSERT_EQ(RiseTemperature(std::vector{-5, -4, -3, -2, -1}), + (std::vector{1, 1, 1, 1, 0})); +} + +// Тестирование поведения с случайными температурами +TEST(TopologySort, RandomTemperature) { + ASSERT_EQ(RiseTemperature(std::vector{3, -1, 4, 1, 5}), + (std::vector{2, 1, 2, 1, 0})); +} + +// Тестирование поведения с пустым вектором +TEST(TopologySort, EmptyVector) { + EXPECT_THROW(RiseTemperature(std::vector{}), WrongVector); +} + +// Тестирование поведения с максимальными и минимальными значениями +TEST(TopologySort, ExtremeValues) { + ASSERT_EQ(RiseTemperature(std::vector{-2, 0, 5}), + (std::vector{1, 1, 0})); } diff --git a/task_03/src/topology_sort.cpp b/task_03/src/topology_sort.cpp index e53f670c..d6855edc 100644 --- a/task_03/src/topology_sort.cpp +++ b/task_03/src/topology_sort.cpp @@ -1 +1,38 @@ #include "topology_sort.hpp" + +#include +#include +#include + +class Day { + public: + int number_of_day; + int temperature; + Day(int number_of_day, int temperature) + : number_of_day(number_of_day), temperature(temperature) {} +}; + +std::vector RiseTemperature(std::vector vec) { + int size = int(vec.size()); + if (size == 0) { + throw WrongVector("Wrong vector is too small"); + } + std::stack stack_days; + std::vector answer_vec(size, 0); + stack_days.emplace(0, vec[0]); + int i = 1; + while (i < size) { + while (!stack_days.empty()) { + if (vec[i] > stack_days.top().temperature) { + answer_vec[stack_days.top().number_of_day] = + i - stack_days.top().number_of_day; + stack_days.pop(); + } else if (vec[i] < stack_days.top().temperature) { + break; + } + } + stack_days.emplace(i, vec[i]); + ++i; + } + return answer_vec; +} diff --git a/task_03/src/topology_sort.hpp b/task_03/src/topology_sort.hpp index 6f70f09b..59aaad9e 100644 --- a/task_03/src/topology_sort.hpp +++ b/task_03/src/topology_sort.hpp @@ -1 +1,9 @@ #pragma once +#include +#include + +class WrongVector : public std::runtime_error { + using std::runtime_error::runtime_error; +}; + +std::vector RiseTemperature(std::vector vec); diff --git a/task_04/src/heap.cpp b/task_04/src/heap.cpp new file mode 100644 index 00000000..4b617806 --- /dev/null +++ b/task_04/src/heap.cpp @@ -0,0 +1,58 @@ +#include "heap.hpp" + +#include +#include + +void Heap::SiftDown(int cur_node) { + while (2 * cur_node + 1 < vec_.size()) { + int left = 2 * cur_node + 1; + int right = 2 * cur_node + 2; + int next_node = left; + if ((right < vec_.size()) && vec_[right] < vec_[left]) next_node = right; + if (vec_[cur_node] <= vec_[next_node]) break; + std::swap(vec_[cur_node], vec_[next_node]); + cur_node = next_node; + } +} + +void Heap::SiftUp(int i) { + while (vec_[i] < (vec_[(i - 1) / 2])) { + std::swap(vec_[i], vec_[(i - 1) / 2]); + i = (i - 1) / 2; + } +} + +int Heap::FindMin() { return vec_[0]; } + +int Heap::ExtractMin() { + int min = vec_[0]; + vec_[0] = vec_[vec_.size() - 1]; + vec_.pop_back(); + SiftDown(0); + return min; +} + +std::vector Heap::CopyHeap() { return vec_; } + +void Heap::Insert(int value) { + vec_.push_back(value); + SiftUp(vec_.size() - 1); +} + +void Heap::BuildHeap(std::vector vec) { + for (int i = 0; i < vec.size(); ++i) { + Insert(vec[i]); + } +} + +int FindMinimum(std::vector vec) { + Heap heap; + heap.BuildHeap(vec); + return heap.FindMin(); +} + +std::vector HeapReady(std::vector vec) { + Heap heap; + heap.BuildHeap(vec); + return heap.CopyHeap(); +} diff --git a/task_04/src/heap.hpp b/task_04/src/heap.hpp new file mode 100644 index 00000000..afaae69e --- /dev/null +++ b/task_04/src/heap.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +class Heap { + public: + void SiftDown(int i); + void SiftUp(int i); + void Insert(int value); + int FindMin(); + void BuildHeap(std::vector vec); + int ExtractMin(); + std::vector CopyHeap(); + + private: + std::vector vec_; +}; + +int FindMinimum(std::vector vec); + +std::vector HeapReady(std::vector heap); \ No newline at end of file diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617e..27dbf2d2 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,76 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "heap.hpp" + +// Простое тестирование +TEST(heap, Simple) { + ASSERT_EQ(FindMinimum(std::vector{1, 3, 5, 6, 2, 4}), 1); + ASSERT_EQ(FindMinimum(std::vector{11, 37, 55, 34, -6, 0, 4}), -6); + ASSERT_EQ(HeapReady(std::vector{4, 1, 3, 2, 5}), + (std::vector{1, 2, 3, 4, 5})); + ASSERT_EQ(HeapReady(std::vector{3, 1, 5, 6, 2, 4}), + (std::vector{1, 2, 4, 6, 3, 5})); + Heap heap; + heap.BuildHeap(std::vector{1, 3, 5, 7, 9, 12, 324, 5, 47, 457, 9467, -4, + 758, -579, -4, 0}); + ASSERT_EQ(heap.FindMin(), -579); + heap.Insert(23); + heap.Insert(-1000); + ASSERT_EQ(heap.ExtractMin(), -1000); + ASSERT_EQ(heap.FindMin(), -579); +} + +// Тестирование поведения кучи при вставке элементов +TEST(HeapTest, Insert) { + Heap heap; + heap.Insert(5); + ASSERT_EQ(heap.FindMin(), 5); + heap.Insert(3); + ASSERT_EQ(heap.FindMin(), 3); + heap.Insert(8); + ASSERT_EQ(heap.FindMin(), 3); +} + +// Тестирование поведения кучи при удалении элементов +TEST(HeapTest, ExtractMin) { + Heap heap; + heap.Insert(5); + heap.Insert(3); + heap.Insert(8); + ASSERT_EQ(heap.ExtractMin(), 3); + ASSERT_EQ(heap.FindMin(), 5); + ASSERT_EQ(heap.ExtractMin(), 5); + ASSERT_EQ(heap.FindMin(), 8); +} + +// Тестирование поведения кучи с отрицательными числами +TEST(HeapTest, NegativeNumbers) { + Heap heap; + heap.Insert(-5); + heap.Insert(-3); + heap.Insert(-8); + ASSERT_EQ(heap.FindMin(), -8); + ASSERT_EQ(heap.ExtractMin(), -8); + ASSERT_EQ(heap.FindMin(), -5); +} + +// Тестирование поведения кучи с большим количеством элементов +TEST(HeapTest, LargeHeap) { + Heap heap; + for (int i = 0; i < 1000; ++i) { + heap.Insert(i); + } + ASSERT_EQ(heap.FindMin(), 0); + for (int i = 0; i < 1000; ++i) { + ASSERT_EQ(heap.ExtractMin(), i); + } +} + +// Тестирование поведения кучи при построении из вектора +TEST(HeapTest, BuildHeap) { + Heap heap; + heap.BuildHeap(std::vector{5, 3, 8, 1, 2, 9}); + ASSERT_EQ(heap.FindMin(), 1); + ASSERT_EQ(heap.ExtractMin(), 1); + ASSERT_EQ(heap.FindMin(), 2); } diff --git a/task_05/src/sort.cpp b/task_05/src/sort.cpp new file mode 100644 index 00000000..636bf0fc --- /dev/null +++ b/task_05/src/sort.cpp @@ -0,0 +1,26 @@ +#include "sort.hpp" + +#include +#include + +int Partition(std::vector &arr, int low, int high) { + int pivot = arr[high]; + int i = low - 1; + for (int j = low; j <= high; ++j) { + if (arr[j] < pivot) { + ++i; + std::swap(arr[i], arr[j]); + } + } + std::swap(arr[i + 1], arr[high]); + return (i + 1); +} + +std::vector QuickSort(std::vector &arr, int low, int high) { + if (low < high) { + int m = Partition(arr, low, high); + QuickSort(arr, low, m - 1); + QuickSort(arr, m + 1, high); + } + return arr; +} \ No newline at end of file diff --git a/task_05/src/sort.hpp b/task_05/src/sort.hpp new file mode 100644 index 00000000..7ed3881a --- /dev/null +++ b/task_05/src/sort.hpp @@ -0,0 +1,7 @@ +#pragma once +#include +#include + +int Partition(std::vector &arr, int low, int high); + +std::vector QuickSort(std::vector &arr, int low, int high); \ No newline at end of file diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617e..6d0feb14 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,81 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "sort.hpp" + +TEST(QuickSort, Simple) { + std::vector vec1{9, 8, 7, 6, 5, 4, 2, 3, 1, 0}; + ASSERT_EQ(QuickSort(vec1, 0, 9), + (std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); + std::vector vec2{10, 90, 30, 80, 60, 50}; + ASSERT_EQ(QuickSort(vec2, 0, 5), (std::vector{10, 30, 50, 60, 80, 90})); + std::vector vec3{12, 43, 15, 26, -1233, 346, 1325, + -56, -12, 78, 0, 3345, -34}; + ASSERT_EQ(QuickSort(vec3, 0, 12), + (std::vector{-1233, -56, -34, -12, 0, 12, 15, 26, 43, 78, 346, + 1325, 3345})); + vec3.push_back(-10); + vec3.push_back(1000); + vec3.push_back(5); + ASSERT_EQ(QuickSort(vec3, 0, 15), + (std::vector{-1233, -56, -34, -12, -10, 0, 5, 12, 15, 26, 43, + 78, 346, 1000, 1325, 3345})); +} + +// Тестирование сортировки пустого вектора +TEST(QuickSort, EmptyVector) { + std::vector vec; + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), (std::vector{})); +} + +// Тестирование сортировки вектора с одним элементом +TEST(QuickSort, SingleElement) { + std::vector vec{1}; + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), (std::vector{1})); +} + +// Тестирование сортировки вектора с повторяющимися элементами +TEST(QuickSort, RepeatedElements) { + std::vector vec{5, 5, 5, 5}; + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), (std::vector{5, 5, 5, 5})); +} + +// Тестирование сортировки вектора с отрицательными и положительными числами +TEST(QuickSort, MixedNumbers) { + std::vector vec{-1, 3, -2, 5, 4, -3}; + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), + (std::vector{-3, -2, -1, 3, 4, 5})); +} + +// Тестирование сортировки вектора с уже отсортированными элементами +TEST(QuickSort, AlreadySorted) { + std::vector vec{1, 2, 3, 4, 5}; + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), + (std::vector{1, 2, 3, 4, 5})); +} + +// Тестирование сортировки вектора с элементами в обратном порядке +TEST(QuickSort, ReverseOrder) { + std::vector vec{5, 4, 3, 2, 1}; + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), + (std::vector{1, 2, 3, 4, 5})); +} + +// Тестирование сортировки вектора с нулями и отрицательными числами +TEST(QuickSort, ZerosAndNegatives) { + std::vector vec{0, -1, 0, -2, 0, -3}; + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), + (std::vector{-3, -2, -1, 0, 0, 0})); +} + +// Тестирование сортировки вектора с большим количеством элементов +TEST(QuickSort, LargeArray) { + std::vector vec(1000); + std::iota(vec.begin(), vec.end(), + -500); // Заполнение вектора числами от -500 до 499 + std::random_shuffle(vec.begin(), vec.end()); // Перемешивание элементов + std::vector sorted_vec(vec); + std::sort(sorted_vec.begin(), sorted_vec.end()); + ASSERT_EQ(QuickSort(vec, 0, vec.size() - 1), sorted_vec); } diff --git a/task_06/src/k_stat.cpp b/task_06/src/k_stat.cpp new file mode 100644 index 00000000..9ea003b9 --- /dev/null +++ b/task_06/src/k_stat.cpp @@ -0,0 +1,46 @@ +#include "k_stat.hpp" + +#include +#include +#include + +int Partition(std::vector &vec, int l, int r) { + int piv = vec[rand() % vec.size()]; + int i = l; + int j = r; + while (i <= j) { + while (vec[i] < piv) { + i++; + } + while (vec[j] > piv) { + j--; + } + if (i >= j) { + break; + } + std::swap(vec[i++], vec[j--]); + } + return j; +} + +int FindOrderStatistic(std::vector &vec, int k) { + if (k >= vec.size() || k < 0) { + throw std::logic_error("Wrong k order statistic"); + } + int left = 0; + int right = int(vec.size() - 1); + while (left < vec.size()) { + int mid = Partition(vec, left, right); + + if (mid == k) { + return vec[mid]; + } + + else if (k < mid) { + right = mid; + } else { + left = mid + 1; + } + } + throw std::logic_error("Wrong k order statistic"); +} diff --git a/task_06/src/k_stat.hpp b/task_06/src/k_stat.hpp new file mode 100644 index 00000000..4a90dcc7 --- /dev/null +++ b/task_06/src/k_stat.hpp @@ -0,0 +1,7 @@ +#pragma once +#include +#include + +int Partition(std::vector &vec, int l, int r); + +int FindOrderStatistic(std::vector &vec, int k); \ No newline at end of file diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617e..e4d6c26c 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,80 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include + +#include "k_stat.hpp" + +// Простое тестирование +TEST(k_stat, Simple) { + std::vector vec1{14, -1, 5, 21, 6, -3, 7, 93, 9, 0, 84}; + ASSERT_EQ(FindOrderStatistic(vec1, 8), 21); + ASSERT_EQ(FindOrderStatistic(vec1, 3), 5); + ASSERT_EQ(FindOrderStatistic(vec1, 10), 93); + EXPECT_THROW(FindOrderStatistic(vec1, 13), std::logic_error); + std::vector vec2{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ASSERT_EQ(FindOrderStatistic(vec2, 4), 5); + vec2.pop_back(); + vec2.pop_back(); + vec2.push_back(-12); + vec2.push_back(100); + vec2.push_back(134); + ASSERT_EQ(FindOrderStatistic(vec2, 9), 100); +} + +// Тестирование поиска k-й порядковой статистики в случайном массиве +TEST(k_stat, RandomArray) { + std::vector vec{10, 85, -24, 45, 28, 5, 12, -90, 67}; + ASSERT_EQ(FindOrderStatistic(vec, 0), -90); + ASSERT_EQ(FindOrderStatistic(vec, 2), 5); + ASSERT_EQ(FindOrderStatistic(vec, 5), 28); + ASSERT_EQ(FindOrderStatistic(vec, 8), 85); +} + +// Тестирование поиска k-й порядковой статистики в отсортированном массиве +TEST(k_stat, SortedArray) { + std::vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9}; + ASSERT_EQ(FindOrderStatistic(vec, 0), 1); + ASSERT_EQ(FindOrderStatistic(vec, 3), 4); + ASSERT_EQ(FindOrderStatistic(vec, 8), 9); +} + +// Тестирование поиска k-й порядковой статистики в массиве с повторяющимися +// элементами +TEST(k_stat, RepeatedElements) { + std::vector vec{4, 2, 4, 2, 4, 2}; + ASSERT_EQ(FindOrderStatistic(vec, 2), 2); + ASSERT_EQ(FindOrderStatistic(vec, 5), 4); +} + +// Тестирование поиска k-й порядковой статистики в массиве с отрицательными +// числами +TEST(k_stat, NegativeNumbers) { + std::vector vec{-5, -1, -3, -4, -2}; + ASSERT_EQ(FindOrderStatistic(vec, 0), -5); + ASSERT_EQ(FindOrderStatistic(vec, 4), -1); +} + +// Тестирование поиска k-й порядковой статистики в массиве с одинаковыми +// элементами +TEST(k_stat, UniformElements) { + std::vector vec{5, 5, 5, 5, 5}; + ASSERT_EQ(FindOrderStatistic(vec, 0), 5); + ASSERT_EQ(FindOrderStatistic(vec, 4), 5); +} + +// Тестирование на выброс исключения при некорректном k +TEST(k_stat, OutOfBounds) { + std::vector vec{3, 1, 4}; + EXPECT_THROW(FindOrderStatistic(vec, 4), std::logic_error); + EXPECT_THROW(FindOrderStatistic(vec, -1), std::logic_error); +} + +// Тестирование поиска k-й порядковой статистики в большом массиве +TEST(k_stat, LargeArray) { + std::vector vec(1000); + std::iota(vec.begin(), vec.end(), + 1); // Заполнение массива числами от 1 до 1000 + std::random_shuffle(vec.begin(), vec.end()); // Перемешивание элементов + ASSERT_EQ(FindOrderStatistic(vec, 499), 484); } diff --git a/task_07/src/AVL_Tree.cpp b/task_07/src/AVL_Tree.cpp new file mode 100644 index 00000000..69a9a87f --- /dev/null +++ b/task_07/src/AVL_Tree.cpp @@ -0,0 +1,105 @@ +#include "AVL_Tree.hpp" + +unsigned char AVL_Tree::Height(Node *p) { return p ? p->height : 0; } + +int AVL_Tree::DifferenceH(Node *p) { + return Height(p->right) - Height(p->left); +} + +void AVL_Tree::FixHeight(Node *p) { + unsigned char height_l = Height(p->left); + unsigned char height_r = Height(p->right); + p->height = (height_l > height_r ? height_l : height_r) + 1; +} + +Node *AVL_Tree::Insert(Node *root, int k) { + if (root == nullptr) { + return new Node(k); + } else if (root->key < k) { + root->right = Insert(root->right, k); + } else { + root->left = Insert(root->left, k); + } + return Balance(root); +} + +Node *AVL_Tree::RotateRight(Node *p) { + Node *q = p->left; + p->left = q->right; + q->right = p; + FixHeight(p); + FixHeight(q); + return q; +} + +Node *AVL_Tree::RotateLeft(Node *q) { + Node *p = q->right; + q->right = p->left; + p->left = q; + FixHeight(q); + FixHeight(p); + return p; +} +Node *AVL_Tree::Balance(Node *p) { + FixHeight(p); + if (DifferenceH(p) == 2) { + if (DifferenceH(p->right) < 0) { + p->right = RotateRight(p->right); + } + return RotateLeft(p); + } + + if (DifferenceH(p) == -2) { + if (DifferenceH(p->left) > 0) { + p->left = RotateLeft(p->left); + } + return RotateRight(p); + } + return p; +} + +Node *AVL_Tree::FindMin(Node *right_subtree) { + return right_subtree->left ? FindMin(right_subtree->left) : right_subtree; +} + +Node *AVL_Tree::RemoveMin(Node *p) { + if (p->left == nullptr) return p->right; + p->left = RemoveMin(p->left); + return p; +} + +Node *AVL_Tree::Remove(Node *p, int k) { + if (!p) return nullptr; + if (k < p->key) { + p->left = Remove(p->left, k); + } else if (k > p->key) { + p->right = Remove(p->right, k); + } else { + Node *p_left = p->left; + Node *p_right = p->right; + delete p; + if (!p_right) return p_left; + Node *min = FindMin(p_right); + min->right = RemoveMin(p_right); + min->left = p_left; + return Balance(min); + } + return Balance(p); +} + +bool AVL_Tree::Contains(Node *node, int value) { + if (!node) return false; + if (value < node->key) { + return Contains(node->left, value); + } + if (value > node->key) { + return Contains(node->right, value); + } + return true; +} + +void AVL_Tree::Insert(int value) { root = Insert(root, value); } + +void AVL_Tree::Remove(int value) { root = Remove(root, value); } + +bool AVL_Tree::Contains(int value) { return Contains(root, value); } \ No newline at end of file diff --git a/task_07/src/AVL_Tree.hpp b/task_07/src/AVL_Tree.hpp new file mode 100644 index 00000000..1c0a8f5c --- /dev/null +++ b/task_07/src/AVL_Tree.hpp @@ -0,0 +1,34 @@ +#pragma once +#include + +struct Node { + int key; + unsigned char height; + Node *left = nullptr; + Node *right = nullptr; + Node(int k) { + key = k; + height = 1; + } +}; + +class AVL_Tree { + public: + void Insert(int value); + void Remove(int value); + bool Contains(int value); + + private: + Node *root = nullptr; + bool Contains(Node *node, int value); + Node *Remove(Node *root, int k); + Node *Insert(Node *root, int k); + Node *RotateRight(Node *p); + Node *RotateLeft(Node *q); + Node *Balance(Node *p); + Node *FindMin(Node *right_subtree); + Node *RemoveMin(Node *p); + unsigned char Height(Node *p); + int DifferenceH(Node *p); + void FixHeight(Node *p); +}; diff --git a/task_07/src/test.cpp b/task_07/src/test.cpp index 5e11617e..9fc8c4c7 100644 --- a/task_07/src/test.cpp +++ b/task_07/src/test.cpp @@ -1,6 +1,85 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "AVL_Tree.hpp" + +TEST(AVLTreeTest, InsertAndContains) { + AVL_Tree tree; + + tree.Insert(10); + tree.Insert(5); + tree.Insert(15); + + ASSERT_EQ(tree.Contains(10), true); + tree.Remove(10); + ASSERT_EQ(tree.Contains(5), true); + ASSERT_EQ(tree.Contains(15), true); + ASSERT_EQ(tree.Contains(20), false); + ASSERT_EQ(tree.Contains(10), false); +} + +TEST(AVLTreeTest, DuplicateInsert) { + AVL_Tree tree; + tree.Insert(5); + tree.Insert(5); + tree.Insert(5); + ASSERT_EQ(tree.Contains(5), true); +} + +TEST(AVLTreeTest, RemoveNonExisting) { + AVL_Tree tree; + tree.Insert(5); + tree.Remove(10); + ASSERT_EQ(tree.Contains(5), true); + ASSERT_EQ(tree.Contains(10), false); +} + +TEST(AVLTreeTest, LeftRotation) { + AVL_Tree tree; + tree.Insert(30); + tree.Insert(20); + tree.Insert(10); + ASSERT_EQ(tree.Contains(10), true); + ASSERT_EQ(tree.Contains(20), true); + ASSERT_EQ(tree.Contains(30), true); +} + +TEST(AVLTreeTest, RightRotation) { + AVL_Tree tree; + tree.Insert(10); + tree.Insert(20); + tree.Insert(30); + ASSERT_EQ(tree.Contains(10), true); + ASSERT_EQ(tree.Contains(20), true); + ASSERT_EQ(tree.Contains(30), true); +} + +TEST(AVLTreeTest, RandomData) { + AVL_Tree tree; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dist(1, 1000); + + std::vector data(100); + for (int i = 0; i < 100; ++i) { + data[i] = dist(gen); + } + + std::shuffle(data.begin(), data.end(), gen); + + for (int value : data) { + tree.Insert(value); + } + + for (int value : data) { + ASSERT_EQ(tree.Contains(value), true); + } + + std::shuffle(data.begin(), data.end(), gen); + for (int i = 0; i < 50; ++i) { + tree.Remove(data[i]); + } + + for (int i = 50; i < 100; ++i) { + ASSERT_EQ(tree.Contains(data[i]), true); + } } diff --git a/task_08/src/hash_table.cpp b/task_08/src/hash_table.cpp new file mode 100644 index 00000000..5b331ba5 --- /dev/null +++ b/task_08/src/hash_table.cpp @@ -0,0 +1,105 @@ +#include "hash_table.hpp" + +#include + +#include +#include + +size_t HashTable::Size() { return size_; } + +size_t HashTable::FirstHashFunc(int key) { + return floor(buffers_size_ * + ((key * hashCoefficient) - floor(key * hashCoefficient))); +} + +size_t HashTable::SecondHashFunc(int key) { + return (key * buffers_size_ - 1) % buffers_size_; +} + +void HashTable::Clear() { + used_cell_ = 0; + size_ = 0; + for (auto &cell : cell_conditions_) { + cell = Condition::Empty; + } +} + +void HashTable::ReSize() { + buffers_size_ *= 2; + t_container_.resize(buffers_size_); + cell_conditions_.resize(buffers_size_); +} + +void HashTable::ReHash() { + std::vector used_elem; + for (int i = 0; i < buffers_size_; ++i) { + if (cell_conditions_[i] == Condition::Fill) { + used_elem.push_back(t_container_[i]); + } + } + + ReSize(); + Clear(); + + for (auto &elem : used_elem) { + Insert(elem); + } +} + +bool HashTable::Contains(int value) { + size_t hash = FirstHashFunc(value) % buffers_size_; + int cnt_attemts = 0; + while (cell_conditions_[hash] != Condition::Empty) { + if (t_container_[hash] == value && + cell_conditions_[hash] == Condition::Fill) { + return true; + } + cnt_attemts++; + hash = (FirstHashFunc(value) + cnt_attemts * SecondHashFunc(value)) % + buffers_size_; + } + return false; +} + +void HashTable::Insert(int value) { + size_t hash = FirstHashFunc(value) % buffers_size_; + int cnt_attempts = 0; + while (cell_conditions_[hash] == Condition::Fill) { + if (t_container_[hash] == value) { + return; + } + cnt_attempts++; + hash = (FirstHashFunc(value) + cnt_attempts * SecondHashFunc(value)) % + buffers_size_; + } + + t_container_[hash] = value; + cell_conditions_[hash] = Condition::Fill; + used_cell_++; + size_++; + + double used_cells_coefficient = double(used_cell_) / buffers_size_; + if (used_cells_coefficient >= rehashCoefficient) { + ReHash(); + } +} + +void HashTable::Remove(int value) { + size_t hash = FirstHashFunc(value) % buffers_size_; + int cnt_attemts = 0; + while (cell_conditions_[hash] != Condition::Empty) { + if (t_container_[hash] == value && + cell_conditions_[hash] == Condition::Fill) { + cell_conditions_[hash] = Condition::Deleted; + size_--; + break; + } + if (t_container_[hash] == value && + cell_conditions_[hash] == Condition::Deleted) { + break; + } + cnt_attemts++; + hash = (FirstHashFunc(value) + SecondHashFunc(value) * cnt_attemts) % + buffers_size_; + } +} \ No newline at end of file diff --git a/task_08/src/hash_table.hpp b/task_08/src/hash_table.hpp new file mode 100644 index 00000000..3dd2c70e --- /dev/null +++ b/task_08/src/hash_table.hpp @@ -0,0 +1,42 @@ +#pragma once +#include +#include + +class HashTable { + public: + HashTable() { + used_cell_ = 0; + size_ = 0; + buffers_size_ = DefaultBufferSize; + t_container_ = std::vector(buffers_size_); + cell_conditions_ = std::vector(buffers_size_, Condition::Empty); + } + + bool Contains(int value); + + void Insert(int value); + + void Remove(int value); + + void Clear(); + + size_t Size(); + + private: + enum class Condition { Fill, Deleted, Empty }; + constexpr static const double rehashCoefficient = 0.7; + constexpr static const double hashCoefficient = 0.618033989; + constexpr static const double DefaultBufferSize = 8; + size_t buffers_size_; + size_t size_; + unsigned used_cell_; + std::vector t_container_; + std::vector cell_conditions_; + + size_t FirstHashFunc(int key); + size_t SecondHashFunc(int key); + + void ReSize(); + + void ReHash(); +}; \ No newline at end of file diff --git a/task_08/src/test.cpp b/task_08/src/test.cpp index 5e11617e..e4065198 100644 --- a/task_08/src/test.cpp +++ b/task_08/src/test.cpp @@ -1,6 +1,66 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include + +TEST(HashTableTest, ContainsElement) { + HashTable table; + table.Insert(5); + ASSERT_TRUE(table.Contains(5)); +} + +TEST(HashTableTest, InsertElement) { + HashTable table; + table.Insert(10); + ASSERT_TRUE(table.Contains(10)); +} + +TEST(HashTableTest, RemoveElement) { + HashTable table; + table.Insert(15); + table.Remove(15); + ASSERT_FALSE(table.Contains(15)); +} + +TEST(HashTableTest, ClearTable) { + HashTable table; + table.Insert(20); + table.Clear(); + ASSERT_EQ(table.Size(), 0); +} + +TEST(HashTableTest, SizeAfterInsertion) { + HashTable table; + table.Insert(25); + table.Insert(30); + ASSERT_EQ(table.Size(), 2); +} + +TEST(HashTableTest, ClearTableWithManyElements) { + HashTable table; + for (int i = 0; i < 1000; ++i) { + table.Insert(i); + } + table.Clear(); + ASSERT_EQ(table.Size(), 0); +} + +TEST(HashTableTest, CollisionHandling) { + HashTable table; + // Элементы с одинаковым хэшем + table.Insert(5); + table.Insert(15); + ASSERT_TRUE(table.Contains(5)); + ASSERT_TRUE(table.Contains(15)); +} + +TEST(HashTableTest, SizeAfterRemoval) { + HashTable table; + for (int i = 0; i < 50; ++i) { + table.Insert(i); + } + for (int i = 0; i < 25; ++i) { + table.Remove(i); + } + ASSERT_EQ(table.Size(), 25); } diff --git a/task_09/src/minimum_moneys.cpp b/task_09/src/minimum_moneys.cpp new file mode 100644 index 00000000..a0dadcbe --- /dev/null +++ b/task_09/src/minimum_moneys.cpp @@ -0,0 +1,20 @@ +#include "minimum_moneys.hpp" + +int MinMoney(std::vector vec, int money) { + std::vector table(money + 1, int(1e10)); + table[0] = 0; + int mon = table[money]; + + for (int i = 1; i <= money; ++i) { + for (int j : vec) { + if (j <= i) { + table[i] = std::min(table[i], 1 + table[i - j]); + } + } + } + + if (abs(table[money]) == abs(mon)) { + return 0; + } + return table[money]; +} \ No newline at end of file diff --git a/task_09/src/minimum_moneys.hpp b/task_09/src/minimum_moneys.hpp new file mode 100644 index 00000000..481a2f01 --- /dev/null +++ b/task_09/src/minimum_moneys.hpp @@ -0,0 +1,5 @@ +#pragma once +#include +#include + +int MinMoney(std::vector vec, int money); \ No newline at end of file diff --git a/task_09/src/test.cpp b/task_09/src/test.cpp index 869094dd..552c2dee 100644 --- a/task_09/src/test.cpp +++ b/task_09/src/test.cpp @@ -1,4 +1,33 @@ - #include -TEST(TopologySort, Simple) { ASSERT_EQ(1, 1); } +#include + +#include "minimum_moneys.hpp" + +TEST(MinMoney, GreedyAlgorithmNotWorkHere) { + ASSERT_EQ(MinMoney(std::vector{1, 3, 4}, 6), (2)); +} + +TEST(MinMoney, Simple) { + ASSERT_EQ(MinMoney(std::vector{1, 2, 5, 10}, 14), (3)); + ASSERT_EQ(MinMoney(std::vector{1, 2, 5, 10}, 19), (4)); + ASSERT_EQ(MinMoney(std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9}, 152), (17)); + ASSERT_EQ(MinMoney(std::vector{1, 3, 4}, 34), (9)); + ASSERT_EQ(MinMoney(std::vector{1, 2, 6, 7}, 12), (2)); +} + +TEST(MinMoney, Impossible) { + ASSERT_EQ(MinMoney(std::vector{4, 5, 6, 7, 8, 9}, 3), (0)); + ASSERT_EQ(MinMoney(std::vector{14, 25}, 12), (0)); +} + +TEST(MinMoneyTest, SingleDenomination) { + ASSERT_EQ(MinMoney(std::vector{5}, 20), 4); +} + +TEST(MinMoney, Hard) { + ASSERT_EQ( + MinMoney(std::vector{1, 2, 5, 10, 12, 14, 15, 16, 20, 23, 36, 65}, + 128), + (4)); +} \ No newline at end of file