diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 267b2ec..783d168 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -15,6 +15,7 @@ jobs:
steps:
- name: Install gtest manually
run: sudo apt-get install libgtest-dev
+ run: sudo apt install libomp-dev
- uses: actions/checkout@v3
diff --git a/doc/topic2/img/SAH.jpg b/doc/topic2/img/SAH.jpg
new file mode 100644
index 0000000..c96083d
Binary files /dev/null and b/doc/topic2/img/SAH.jpg differ
diff --git a/doc/topic2/img/raytracing.jpg b/doc/topic2/img/raytracing.jpg
new file mode 100644
index 0000000..7322064
Binary files /dev/null and b/doc/topic2/img/raytracing.jpg differ
diff --git a/doc/topic2/img/search.png b/doc/topic2/img/search.png
new file mode 100644
index 0000000..b8c27f3
Binary files /dev/null and b/doc/topic2/img/search.png differ
diff --git a/doc/topic2/img/stop.jpg b/doc/topic2/img/stop.jpg
new file mode 100644
index 0000000..349dc0f
Binary files /dev/null and b/doc/topic2/img/stop.jpg differ
diff --git "a/doc/topic2/img/\320\277\320\276\320\273\320\270\320\263\320\276\320\275.jpg" "b/doc/topic2/img/\320\277\320\276\320\273\320\270\320\263\320\276\320\275.jpg"
new file mode 100644
index 0000000..e987350
Binary files /dev/null and "b/doc/topic2/img/\320\277\320\276\320\273\320\270\320\263\320\276\320\275.jpg" differ
diff --git "a/doc/topic2/img/\321\200\320\260\320\267\320\261\320\270\320\265\320\275\320\270\320\265.jpg" "b/doc/topic2/img/\321\200\320\260\320\267\320\261\320\270\320\265\320\275\320\270\320\265.jpg"
new file mode 100644
index 0000000..53dd412
Binary files /dev/null and "b/doc/topic2/img/\321\200\320\260\320\267\320\261\320\270\320\265\320\275\320\270\320\265.jpg" differ
diff --git "a/doc/topic2/img/\321\200\320\260\321\201\321\201\321\202\320\276\321\217\320\275\320\270\320\265.png" "b/doc/topic2/img/\321\200\320\260\321\201\321\201\321\202\320\276\321\217\320\275\320\270\320\265.png"
new file mode 100644
index 0000000..885eafd
Binary files /dev/null and "b/doc/topic2/img/\321\200\320\260\321\201\321\201\321\202\320\276\321\217\320\275\320\270\320\265.png" differ
diff --git a/doc/topic2/question1.md b/doc/topic2/question1.md
new file mode 100644
index 0000000..a675c23
--- /dev/null
+++ b/doc/topic2/question1.md
@@ -0,0 +1,78 @@
+# KDTree
+
+Данный конспект является необязательным, но будет интересным для ознакомления
+## Что такое KDTree и где используется?
+До этого мы рассматривали деревья, работающие в одномерном пространстве. Но бывают случаи, когда необходимо работать в пространстве.
+$KDTree$ - это разновидность дерева, применяемого в многомерном пространстве. $K$ в названии указывает на размерность в которой оно реализуется. К примеру существуют 2D-Дерево, 3D-Дерево и тд.
+
+
+Одна из самых главных задач, которые решает данная структура - это поиск
+ближайшей точки (объекта). Данная функция может быть необходима, например, при разработке игр, в частности
+в так называемом ray tracing. Сложные 3D модели состоят из многочисленных треугольников и алгоритм обработки изображения требует быстро находить ближайший треугольник к заданой точке, для просчета луча света, проходящего через объект.
+
+
+
+
+#### **Cyberpunk 2077 с использованием ray tracing технологии**
+
+
+
+
+
+
+Также KD-Дерево используется в Яндекс.Такси для поиска ближайшей свободной машины к заказчику. Здесь тоже нужна скорость, мы же не хотим заставлять клиентов долго ждать
+
+
+
+
+## Принцип работы
+
+Далее будем говорить о множестве точек на плоскости (порядка миллиона), представляющие собой 2 координаты: x и y. Но стоит помнить, что вместо них могут быть как те же треугольники, так и другие объекты, которые могут находиться не только в плоскости, но и в пространстве, 4-х мерном измерении и тд. Принцип работы координально отличаться не будет, но все же некоторые нюансы стоит учитывать.Однако на них в данном конспекте заострять внимание не будем.
+
+
+Итак, предположим, что у нас есть набор точек на плоскости. Глобально алгоритм предполагает разбиение данной плоскоти на более мелкии её составляющие. Это нужно, чтобы для поиска ближайшего мы не перебирали каждый раз *все* точки плоскости, а только *часть* из их.
+
+Для разделения мы должны как-то обозначать границы нашей плоскости. Один способов это сделать - использовать так называемый bounding box. По сути это условные прямоугольники, в которые помещаются наши точки. Далее нам нужно как-то разделить наше пространство. Естсетвенно, разбиение, где в одном подпространстве будет 1 точка, а в другом 99999 нас не очень устраивает, так как мы хотим добиться скорости. Таких разбиений стоит избегать и строить дерево более равномерно.
+
+#### Как это можно сделать?
+* Один из самых простых способов - использовать случайное распределение. Даст ли это равномерное распределение? Может да, а может и нет :)
+* Можно выбирать наиболее длинную сторону bounding box и делить её пополам.
+* Рассекать по медиане: отсортируем все точки по одной из координат, а медианой назовем элемент (или центр элемента), который находится на средней позиции в отсортированном списке. Секущая плоскость будет проходить через медиану так, что количество элементов слева и справа будет примерно равным.
+
+Данные способы позволяют быстро построить дерево, но с большой вероятностью оно будет разбито неравномерно, что скажется на скорости основных функций дерева. Поэтому чтобы получить наиболее оптимальный результат данные методы не подойдут. Нужно как-то вычислить оптимальное разбиение. Для этого были придуманы функции, которые оценят выгодность конкретного разбиения. Один из примеров таких функций - $SAH$ (Surface Area Heuristic). О ней мы поговорим чуть позже.
+
+
+
+Картинка выше - пример возможного разбиения нашего пространства.
+
+Важно отметить, что для эффективного использования памяти координаты точек необходимо хранить в листьях нашего дерева. Сами узлы должны хранить информацию о своем bounding box.
+
+Итак, у нас есть готовое дерево, теперь рассмотрим алгоритмическую составляющую поиска ближайщего к точке.
+
+Пусть у нас есть координаты точки, к которой мы хотим найди ближайшую. Основная идея заключается в том, чтобы найти сначала ближайший bounding box (BB) к этой точке. Затем, мы перебираем все точки в BB и выбираем точку с минимальным расстояниям. Выбрать BB можно, идя рекурсивно, начиная с корня и проверяя лежит ли наша точка в BB левого поддерева или правого. С таким подходом может быть проблема, если данная точка не лежит в BB всех точек (BB корня дерева). Чтобы учесть это следует проверять принадлежность не самой точки, а части окружности, с центром в данной точке.
+
+Что делать если для нашей точки подходят несколько BB? Такое может случится, если наша точка оказалась на границе раздела. В данном случае мы просто будем проверять все подходящие BB. Вы можете подумать, что это неэффективно, но на самом деле мы проверим небольшое количество BB, в сравнении со всеми точками (даже если получится очень неудачная ситуация и необходимо будет перебрать 100000 точек, это все равно в 10 раз эффективнее перебора 1000000).
+
+
+
+
+## Подробнее про SAH функцию
+Давайте подробнее поговорим про SAH функцию. Как уже было сказано она нужна, чтобы оценить выгодность конкретного разбиения. Её значение вычисляется следующим образом:
+
+
+
+Данная формула взята для случая ray tracing'а, но ее можно использовать и для других целей.
+
+Как же ей пользоваться? Сначала мы выбираем направление (линию Ox или Oy). Затем мы делим наш BB на равные части вдоль выбранного направления. Сколько выбрать таких частей зависит от вашего желания и компромисса скорости построения KDTree и его равномерностью. Достаточно оптимальным можно считать разбинение на 33 части. Затем, каждую из этих частей мы отправляем в нашу SAH функцию. Она расчитывается для каждого из предполагаемых разбиений. Остается только выбрать ту часть, которая имеет наименьшее значение по этой функции. Оно и будет самым выгодным.
+
+Константы $C_i$ и $C_t$ также стоит подбирать из соображений оптимальности построения KDTree и его работоспособностью.
+В том же ray tracing'е, откуда была взята данная формула $C_i$ обычно равняется $1$, а $C_t$ находится в пределах $[1,2]$.
+
+Кроме этого с помощью SAH функции можно определить условие остановки построения дерева
+
+
+
+Прекращаем деление, так как следующее разбиение уже не будет более выгодным
+
+# На этом все
+Это была краткая справка о том, что вообще из себя представляет KDTree и какие алгортмы лежат в его реализации. Подробнее о создании данного типа деревьев можно почитать [здесь](https://habr.com/ru/articles/312882/). А также на [википедии](https://ru.wikipedia.org/wiki/K-d-дерево)
\ No newline at end of file
diff --git a/lib/src/util.cpp b/lib/src/util.cpp
index 81e15bd..2f00b78 100644
--- a/lib/src/util.cpp
+++ b/lib/src/util.cpp
@@ -1 +1,24 @@
#include "util.hpp"
+
+void MergeSort(std::vector& array) {
+ int n = array.size();
+ std::vector buffer(n);
+
+ for (int slice = 1; slice < n; slice *= 2) {
+ for (int left = 0; left < n; left += 2 * slice) {
+ int mid = std::min(left + slice, n);
+ int right = std::min(left + 2 * slice, n);
+
+ int i = left, j = mid;
+ int k = left;
+ while (i < mid && j < right) {
+ buffer[k++] = array[i] <= array[j] ? array[i++] : array[j++];
+ }
+ while (i < mid) buffer[k++] = array[i++];
+ while (j < right) buffer[k++] = array[j++];
+
+ std::copy(buffer.begin() + left, buffer.begin() + right,
+ array.begin() + left);
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/src/util.hpp b/lib/src/util.hpp
index e69de29..fd0b3e2 100644
--- a/lib/src/util.hpp
+++ b/lib/src/util.hpp
@@ -0,0 +1,3 @@
+#include
+
+void MergeSort(std::vector& array);
diff --git a/sandbox/template/src/main b/sandbox/template/src/main
new file mode 100755
index 0000000..c89b0c2
Binary files /dev/null and b/sandbox/template/src/main differ
diff --git a/sandbox/template/src/main.cpp b/sandbox/template/src/main.cpp
index 0e4393b..f46e229 100644
--- a/sandbox/template/src/main.cpp
+++ b/sandbox/template/src/main.cpp
@@ -1,3 +1,41 @@
-#include
+// #include
+// #include
-int main() { return 0; }
+// void MergeSort(std ::vector& array) {
+// int i{0}, j{1};
+// int slice{1};
+// do {
+// while (j <= array.size() - 1) {
+// if (array[i] > array[j]) {
+// iter_swap(array.begin() + i, array.begin() + j);
+
+// ++j;
+// } else
+// ++i;
+// if (j - i > slice) {
+// i = j;
+// j = i + slice;
+// } else if (j == i) {
+// i += 1;
+// j = i + slice;
+// }
+// }
+// slice *= 2;
+// slice > array.size() ? j = array.size() - 1 : j = slice;
+// i = 0;
+// if (j == array.size() - 1) {
+// if (i == 0) {
+// return;
+// }
+// }
+// } while (true);
+// }
+
+int main() {
+ // std ::vector unsort{3, 2, 4, 5, 1, 9, 7};
+ // MergeSort(unsort);
+ // for (int i = 0; i < unsort.size(); ++i) {
+ // std ::cout << unsort[i] << " ";
+ // }
+ // std ::cout << std ::endl;
+}
diff --git a/sandbox/template/src/test.cpp b/sandbox/template/src/test.cpp
index 31df8b8..7b3eb4a 100644
--- a/sandbox/template/src/test.cpp
+++ b/sandbox/template/src/test.cpp
@@ -1,8 +1,8 @@
-#include
+// #include
-#include
+// #include
-#include "utils.hpp"
+// #include "utils.hpp"
-TEST(Template, Simple) { ASSERT_EQ(true, true); }
+// TEST(Template, Simple) { ASSERT_EQ(true, true); }
diff --git a/sandbox/template/src/utils.cpp b/sandbox/template/src/utils.cpp
index 0ee624c..03b9030 100644
--- a/sandbox/template/src/utils.cpp
+++ b/sandbox/template/src/utils.cpp
@@ -1 +1 @@
-#include "utils.hpp"
+// #include "utils.hpp"
diff --git a/sandbox/template/src/utils.hpp b/sandbox/template/src/utils.hpp
index 6f70f09..7dcceab 100644
--- a/sandbox/template/src/utils.hpp
+++ b/sandbox/template/src/utils.hpp
@@ -1 +1 @@
-#pragma once
+// #pragma once
diff --git a/task_01/src/find.cpp b/task_01/src/find.cpp
new file mode 100644
index 0000000..b5d0413
--- /dev/null
+++ b/task_01/src/find.cpp
@@ -0,0 +1,20 @@
+#include "find.hpp"
+
+std ::vector FindNums(int k, std ::vector sequence) {
+ if (sequence.size() == 0) throw NoSumNum{};
+
+ std ::vector answer;
+ unsigned long left_index{0};
+ unsigned long right_index{sequence.size() - 1};
+ while (left_index != right_index) {
+ if ((sequence[left_index] + sequence[right_index]) == k) {
+ answer.push_back(sequence[left_index]);
+ answer.push_back(sequence[right_index]);
+ return answer;
+ } else if (sequence[left_index] + sequence[right_index] > k)
+ --right_index;
+ else
+ ++left_index;
+ }
+ throw NoSumNum{};
+}
\ No newline at end of file
diff --git a/task_01/src/find.hpp b/task_01/src/find.hpp
new file mode 100644
index 0000000..8812e23
--- /dev/null
+++ b/task_01/src/find.hpp
@@ -0,0 +1,8 @@
+#include
+#include
+
+struct NoSumNum {
+ std ::string s{"no possible way to solve task"};
+};
+
+std ::vector FindNums(int k, std ::vector sequence);
\ No newline at end of file
diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp
index 0e4393b..9ec81e0 100644
--- a/task_01/src/main.cpp
+++ b/task_01/src/main.cpp
@@ -1,3 +1,3 @@
#include
-int main() { return 0; }
+int main() { return 0; }
\ No newline at end of file
diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp
index 87cef73..42dc3c1 100644
--- a/task_01/src/test.cpp
+++ b/task_01/src/test.cpp
@@ -1,5 +1,33 @@
#include
-TEST(Test, Simple) {
- ASSERT_EQ(1, 1); // Stack []
+#include "find.hpp"
+
+TEST(FindNums, Simple) {
+ std ::vector seq{1, 2, 3, 4, 5};
+ std ::vector ans{FindNums(5, seq)};
+ ASSERT_EQ(5, ans[0] + ans[1]);
+}
+
+TEST(FindNums, Negative) {
+ std ::vector seq{-100, -10, -9, -8, -1};
+ std ::vector ans{FindNums(-9, seq)};
+ ASSERT_EQ(-9, ans[0] + ans[1]);
+}
+
+TEST(FindNums, WithZeros) {
+ std ::vector seq{
+ -15, 0, 0, 2, 8,
+ };
+ std ::vector ans{FindNums(10, seq)};
+ ASSERT_EQ(10, ans[0] + ans[1]);
+}
+
+TEST(FindNums, NoValue) {
+ std ::vector seq{0, 0, 2, 8, -15};
+ EXPECT_THROW(FindNums(60, seq), NoSumNum);
+}
+
+TEST(FindNums, Empty) {
+ std ::vector seq(0);
+ EXPECT_THROW(FindNums(60, seq), NoSumNum);
}
\ No newline at end of file
diff --git a/task_02/src/stack.cpp b/task_02/src/stack.cpp
deleted file mode 100644
index 8ca8990..0000000
--- a/task_02/src/stack.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "stack.hpp"
-
-#include
-
-void Stack::Push(int value) { data_.push(value); }
-
-int Stack::Pop() {
- auto result = data_.top();
- data_.pop();
- return result;
-}
-
-void MinStack::Push(int value) { data_.push_back(value); }
-
-int MinStack::Pop() {
- auto result = data_.back();
- data_.pop_back();
- return result;
-}
-
-int MinStack::GetMin() { return *std::min_element(data_.begin(), data_.end()); }
\ No newline at end of file
diff --git a/task_02/src/stack.hpp b/task_02/src/stack.hpp
index 138ec40..fcf5a1b 100644
--- a/task_02/src/stack.hpp
+++ b/task_02/src/stack.hpp
@@ -1,23 +1,70 @@
-#pragma once
-
-#include
+#include
+#include
#include
+template
+concept Comparable = requires(T a, T b) {
+ { a < b } -> std::convertible_to;
+};
+
+template
class Stack {
public:
- void Push(int value);
- int Pop();
+ void Push(T k);
+ T Pop();
private:
- std::stack data_;
+ std ::vector _data;
};
+template
+void Stack::Push(T k) {
+ _data.push_back(k);
+}
+
+template
+T Stack::Pop() {
+ if (_data.size() == 0) throw std::out_of_range("No data in stack");
+ T pop_val{_data.back()};
+ _data.pop_back();
+ return pop_val;
+}
+
+template
class MinStack {
public:
- void Push(int value);
- int Pop();
- int GetMin();
+ void Push(T k);
+ T Pop();
+ T GetMin();
private:
- std::vector data_;
+ std ::vector _data;
+ std ::vector _min_data;
};
+
+template
+void MinStack::Push(T k) {
+ if (_min_data.size() == 0)
+ _min_data.push_back(k);
+ else if (_min_data.back() > k)
+ _min_data.push_back(k);
+ else
+ _min_data.push_back(_min_data.back());
+ _data.push_back(k);
+}
+
+template
+T MinStack::Pop() {
+ if ((_data.size() == 0) || (_min_data.size() == 0))
+ throw std::out_of_range("No data in stack");
+ T pop_val{_data.back()};
+ _data.pop_back();
+ _min_data.pop_back();
+ return pop_val;
+}
+
+template
+T MinStack::GetMin() {
+ if (_min_data.size() == 0) throw std::out_of_range("No data in stack");
+ return _min_data.back();
+}
diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp
index 54e7ce9..f99f283 100644
--- a/task_02/src/test.cpp
+++ b/task_02/src/test.cpp
@@ -1,42 +1,66 @@
#include
-#include
-
#include "stack.hpp"
TEST(StackTest, Simple) {
- Stack stack;
- stack.Push(1); // Stack [1]
- ASSERT_EQ(stack.Pop(), 1); // Stack []
- stack.Push(1); // Stack [1]
- stack.Push(2); // Stack [1, 2]
- ASSERT_EQ(stack.Pop(), 2); // Stack [1]
- ASSERT_EQ(stack.Pop(), 1); // 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 []
+ Stack stack;
+ stack.Push(1);
+ ASSERT_EQ(stack.Pop(), 1);
+ stack.Push(1);
+ stack.Push(2);
+ ASSERT_EQ(stack.Pop(), 2);
+ ASSERT_EQ(stack.Pop(), 1);
+ stack.Push(1);
+ stack.Push(2);
+ ASSERT_EQ(stack.Pop(), 2);
+ stack.Push(3);
+ ASSERT_EQ(stack.Pop(), 3);
+ ASSERT_EQ(stack.Pop(), 1);
}
TEST(MinStackTest, Simple) {
- MinStack stack;
- stack.Push(1); // Stack [1]
+ MinStack stack;
+ stack.Push(1);
ASSERT_EQ(stack.GetMin(), 1);
- ASSERT_EQ(stack.Pop(), 1); // Stack []
- stack.Push(1); // Stack [1]
- stack.Push(2); // Stack [1, 2]
+ ASSERT_EQ(stack.Pop(), 1);
+ stack.Push(1);
+ stack.Push(2);
ASSERT_EQ(stack.GetMin(), 1);
- ASSERT_EQ(stack.Pop(), 2); // Stack [1]
- ASSERT_EQ(stack.Pop(), 1); // Stack []
- stack.Push(1); // Stack [1]
- stack.Push(2); // Stack [1, 2]
+ ASSERT_EQ(stack.Pop(), 2);
+ ASSERT_EQ(stack.Pop(), 1);
+ stack.Push(1);
+ stack.Push(2);
ASSERT_EQ(stack.GetMin(), 1);
- ASSERT_EQ(stack.Pop(), 2); // Stack [1]
- stack.Push(3); // Stack [1, 3]
+ ASSERT_EQ(stack.Pop(), 2);
+ stack.Push(3);
ASSERT_EQ(stack.GetMin(), 1);
- ASSERT_EQ(stack.Pop(), 3); // Stack [1]
- ASSERT_EQ(stack.Pop(), 1); // Stack []
+ ASSERT_EQ(stack.Pop(), 3);
+ ASSERT_EQ(stack.Pop(), 1);
+}
+
+TEST(Stack, Custom) {
+ Stack stack;
+ stack.Push(10);
+ ASSERT_EQ(10, stack.Pop());
+
+ EXPECT_THROW(stack.Pop(), std::out_of_range);
+}
+
+TEST(MinStack, Custom) {
+ MinStack stack;
+ stack.Push(10);
+ stack.Push(2);
+ stack.Push(17);
+ ASSERT_EQ(2, stack.GetMin());
+
+ stack.Pop();
+ stack.Pop();
+ stack.Pop();
+ EXPECT_THROW(stack.Pop(), std::out_of_range);
+
+ stack.Push(10);
+ stack.Push(10);
+ stack.Push(10);
+ ASSERT_EQ(10, stack.GetMin());
}
\ No newline at end of file
diff --git a/task_03/src/main.cpp b/task_03/src/main.cpp
index 0e4393b..a4fe526 100644
--- a/task_03/src/main.cpp
+++ b/task_03/src/main.cpp
@@ -1,3 +1,13 @@
#include
-int main() { return 0; }
+#include "warming_func.hpp"
+
+// void print(std::vector& v) {
+// for (auto c : v) std ::cout << c << " ";
+// }
+
+int main() {
+ // std ::vector s{5, 7, 9, 3, 4, 0, 2, -1, 3};
+ // s = Warming(s);
+ // print(s);
+}
diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp
index ef5a86a..9b68bb4 100644
--- a/task_03/src/test.cpp
+++ b/task_03/src/test.cpp
@@ -1,8 +1,46 @@
#include
-#include "topology_sort.hpp"
+#include "warming_func.hpp"
-TEST(TopologySort, Simple) {
- ASSERT_EQ(1, 1); // Stack []
+TEST(Warm, Simple) {
+ std ::vector temperature = {73, 74, 75, 71, 69, 72, 76, 73};
+ std ::vector ans = {1, 1, 4, 2, 1, 1, 0, 0};
+ ASSERT_EQ(Warming(temperature), ans);
+}
+
+TEST(Warm, Stable) {
+ std ::vector temperature = {30, 20, 10};
+ std ::vector ans = {0, 0, 0};
+ ASSERT_EQ(Warming(temperature), ans);
+}
+
+TEST(Warm, OneDay) {
+ std ::vector temperature = {50};
+ std ::vector ans = {0};
+ ASSERT_EQ(Warming(temperature), ans);
+}
+
+TEST(Warm, Empty) {
+ std ::vector temperature = {};
+ std ::vector ans = {};
+ ASSERT_EQ(Warming(temperature), ans);
+}
+
+TEST(Warm, SameTemperature) {
+ std ::vector temperature = {10, 10, 10, 10};
+ std ::vector ans = {0, 0, 0, 0};
+ ASSERT_EQ(Warming(temperature), ans);
+}
+
+TEST(Warm, Negative) {
+ std ::vector temperature = {-10, -5, -20};
+ std ::vector ans = {1, 0, 0};
+ ASSERT_EQ(Warming(temperature), ans);
+}
+
+TEST(Warm, BigDiff) {
+ std ::vector temperature = {0, -10, 100, 5, 1000};
+ std ::vector ans = {2, 1, 2, 1, 0};
+ ASSERT_EQ(Warming(temperature), ans);
}
diff --git a/task_03/src/topology_sort.cpp b/task_03/src/topology_sort.cpp
deleted file mode 100644
index e53f670..0000000
--- a/task_03/src/topology_sort.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include "topology_sort.hpp"
diff --git a/task_03/src/topology_sort.hpp b/task_03/src/topology_sort.hpp
deleted file mode 100644
index 6f70f09..0000000
--- a/task_03/src/topology_sort.hpp
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/task_03/src/warming_func.cpp b/task_03/src/warming_func.cpp
new file mode 100644
index 0000000..b1294ee
--- /dev/null
+++ b/task_03/src/warming_func.cpp
@@ -0,0 +1,18 @@
+#include
+
+#include "warming_func.hpp"
+
+std ::vector Warming(std ::vector temperature) {
+ std::stack index;
+ std ::vector ans(temperature.size());
+
+ for (int i = 0; i < temperature.size(); ++i) {
+ while (!index.empty() && (temperature[i] > temperature[index.top()])) {
+ int j = index.top();
+ index.pop();
+ ans[j] = i - j;
+ }
+ index.push(i);
+ }
+ return ans;
+}
\ No newline at end of file
diff --git a/task_03/src/warming_func.hpp b/task_03/src/warming_func.hpp
new file mode 100644
index 0000000..a8020ee
--- /dev/null
+++ b/task_03/src/warming_func.hpp
@@ -0,0 +1,3 @@
+#include
+
+std ::vector Warming(std ::vector temperature);
diff --git a/task_04/src/EconomicCalculation.cpp b/task_04/src/EconomicCalculation.cpp
new file mode 100644
index 0000000..4298014
--- /dev/null
+++ b/task_04/src/EconomicCalculation.cpp
@@ -0,0 +1,23 @@
+#include "EconomicCalculation.hpp"
+
+#include
+
+std::vector OptimizeFishPurchases(std::vector& prices, int K, int N) {
+ std::vector purchases(N, 0);
+ int CurrentDay = 0;
+
+ while (CurrentDay < N) {
+ int Border = std::min(CurrentDay + K, N);
+ int BestDay = CurrentDay;
+
+ for (int day = CurrentDay; day < Border; ++day) {
+ if (prices[day] < prices[BestDay]) {
+ BestDay = day;
+ }
+ }
+ int FishNeeded = Border - BestDay;
+ purchases[BestDay] += FishNeeded;
+ CurrentDay = BestDay + FishNeeded;
+ }
+ return purchases;
+}
\ No newline at end of file
diff --git a/task_04/src/EconomicCalculation.hpp b/task_04/src/EconomicCalculation.hpp
new file mode 100644
index 0000000..fcf53f7
--- /dev/null
+++ b/task_04/src/EconomicCalculation.hpp
@@ -0,0 +1,4 @@
+#include
+
+std::vector OptimizeFishPurchases(std::vector& prices, int N,
+ int K);
\ No newline at end of file
diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp
index 5e11617..1002a34 100644
--- a/task_04/src/test.cpp
+++ b/task_04/src/test.cpp
@@ -1,6 +1,58 @@
#include
-TEST(TopologySort, Simple) {
- ASSERT_EQ(1, 1); // Stack []
+#include "EconomicCalculation.hpp"
+
+TEST(FindFish, Simple) {
+ std::vector prices = {3, 5, 2, 4, 1, 3};
+ int K = 3;
+ int N = prices.size();
+ auto result = OptimizeFishPurchases(prices, K, N);
+ std::vector expected = {0, 0, 1, 0, 2, 0};
+ ASSERT_EQ(expected, result);
+}
+
+TEST(FindFish, SamePrice) {
+ std::vector prices = {2, 2, 2, 2, 2};
+ int K = 2;
+ int N = prices.size();
+ auto result = OptimizeFishPurchases(prices, K, N);
+ std::vector expected = {2, 0, 2, 0, 1};
+ ASSERT_EQ(expected, result);
+}
+
+TEST(FindFish, ImmediateConsumption) {
+ std::vector prices = {5, 4, 3, 2, 1};
+ int K = 1;
+ int N = prices.size();
+ auto result = OptimizeFishPurchases(prices, K, N);
+ std::vector expected = {1, 1, 1, 1, 1};
+ ASSERT_EQ(expected, result);
}
+
+TEST(FindFish, OneBuy) {
+ std::vector prices = {5, 3, 4, 2, 6};
+ int K = 10;
+ int N = prices.size();
+ auto result = OptimizeFishPurchases(prices, K, N);
+ std::vector expected = {0, 0, 0, 2, 0};
+ ASSERT_EQ(expected, result);
+}
+
+TEST(FindFish, OneDay) {
+ std::vector prices = {3};
+ int K = 5;
+ int N = prices.size();
+ auto result = OptimizeFishPurchases(prices, K, N);
+ std::vector expected = {1};
+ ASSERT_EQ(expected, result);
+}
+
+TEST(FindFish, OptimizedBuy) {
+ std::vector prices = {5, 4, 3, 2, 1};
+ int K = 3;
+ int N = prices.size();
+ auto result = OptimizeFishPurchases(prices, K, N);
+ std::vector expected = {0, 0, 1, 0, 1};
+ ASSERT_EQ(expected, result);
+}
\ No newline at end of file
diff --git a/task_05/src/main.cpp b/task_05/src/main.cpp
index 0e4393b..67c383e 100644
--- a/task_05/src/main.cpp
+++ b/task_05/src/main.cpp
@@ -1,3 +1,3 @@
-#include
+#include "sorting.hpp"
-int main() { return 0; }
+int main() {}
diff --git a/task_05/src/merge.cpp b/task_05/src/merge.cpp
new file mode 100644
index 0000000..7e5b467
--- /dev/null
+++ b/task_05/src/merge.cpp
@@ -0,0 +1,26 @@
+#include
+
+#include "sorting.hpp"
+
+void MergeSort(std::vector& array) {
+ int n = array.size();
+ std::vector buffer(n);
+
+ for (int slice = 1; slice < n; slice *= 2) {
+ for (int left = 0; left < n; left += 2 * slice) {
+ int mid = std::min(left + slice, n);
+ int right = std::min(left + 2 * slice, n);
+
+ int i = left, j = mid;
+ int k = left;
+ while (i < mid && j < right) {
+ buffer[k++] = array[i] <= array[j] ? array[i++] : array[j++];
+ }
+ while (i < mid) buffer[k++] = array[i++];
+ while (j < right) buffer[k++] = array[j++];
+
+ std::copy(buffer.begin() + left, buffer.begin() + right,
+ array.begin() + left);
+ }
+ }
+}
\ No newline at end of file
diff --git a/task_05/src/sorting.hpp b/task_05/src/sorting.hpp
new file mode 100644
index 0000000..f2e9c73
--- /dev/null
+++ b/task_05/src/sorting.hpp
@@ -0,0 +1,3 @@
+#include
+
+void MergeSort(std ::vector& array);
\ No newline at end of file
diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp
index 5e11617..64b6813 100644
--- a/task_05/src/test.cpp
+++ b/task_05/src/test.cpp
@@ -1,6 +1,52 @@
-
#include
-TEST(TopologySort, Simple) {
- ASSERT_EQ(1, 1); // Stack []
+#include "sorting.hpp"
+
+TEST(MergeSort, Simple) {
+ std ::vector unsort{3, 2, 4, 5, 1, 9, 7};
+ std ::vector sorted{1, 2, 3, 4, 5, 7, 9};
+ MergeSort(unsort);
+ ASSERT_EQ(unsort, sorted);
+}
+
+TEST(MergeSort, Simple2) {
+ std ::vector unsort{5, 7, 2, 3, 1, 6, 4};
+ std ::vector sorted{1, 2, 3, 4, 5, 6, 7};
+ MergeSort(unsort);
+ ASSERT_EQ(unsort, sorted);
}
+
+TEST(MergeSort, Negative) {
+ std ::vector unsort{-5, -7, -2, -3, -1, -6, -4};
+ std ::vector sorted{-7, -6, -5, -4, -3, -2, -1};
+ MergeSort(unsort);
+ ASSERT_EQ(unsort, sorted);
+}
+
+TEST(MergeSort, SameElements) {
+ std ::vector unsort{3, 3, 3, 3};
+ std ::vector sorted{3, 3, 3, 3};
+ MergeSort(unsort);
+ ASSERT_EQ(unsort, sorted);
+}
+
+TEST(MergeSort, NoElements) {
+ std ::vector unsort{};
+ std ::vector sorted{};
+ MergeSort(unsort);
+ ASSERT_EQ(unsort, sorted);
+}
+
+TEST(MergeSort, DiffElements) {
+ std ::vector unsort{1, -3, 5, 0, 0, -10, 6, 2, 21, -8, 90, -6};
+ std ::vector sorted{-10, -8, -6, -3, 0, 0, 1, 2, 5, 6, 21, 90};
+ MergeSort(unsort);
+ ASSERT_EQ(unsort, sorted);
+}
+
+TEST(MergeSort, OneElement) {
+ std ::vector unsort{10};
+ std ::vector sorted{10};
+ MergeSort(unsort);
+ ASSERT_EQ(unsort, sorted);
+}
\ No newline at end of file
diff --git a/task_06/src/NStatistic.cpp b/task_06/src/NStatistic.cpp
new file mode 100644
index 0000000..0c96d68
--- /dev/null
+++ b/task_06/src/NStatistic.cpp
@@ -0,0 +1,12 @@
+#include "NStatistic.hpp"
+
+#include "../../lib/src/util.hpp"
+#include
+
+int NStatistic(std ::vector data, int n) {
+ if (data.size() == 0) throw std::invalid_argument("");
+ if (n > data.size()) throw std::invalid_argument("");
+
+ MergeSort(data);
+ return data[n];
+}
\ No newline at end of file
diff --git a/task_06/src/NStatistic.hpp b/task_06/src/NStatistic.hpp
new file mode 100644
index 0000000..336d39f
--- /dev/null
+++ b/task_06/src/NStatistic.hpp
@@ -0,0 +1,3 @@
+#include
+
+int NStatistic(std ::vector data, int n);
\ No newline at end of file
diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp
index 5e11617..4a3087f 100644
--- a/task_06/src/test.cpp
+++ b/task_06/src/test.cpp
@@ -1,6 +1,44 @@
#include
-TEST(TopologySort, Simple) {
- ASSERT_EQ(1, 1); // Stack []
+#include "NStatistic.hpp"
+
+TEST(NStatistic, Simple) {
+ std ::vector data = {3, 1, 4, 1, 5};
+ int n = 2;
+ int ans = 3;
+ ASSERT_EQ(NStatistic(data, n), ans);
+}
+
+TEST(NStatistic, OneElem) {
+ std ::vector data = {100};
+ int n = 0;
+ int ans = 100;
+ ASSERT_EQ(NStatistic(data, n), ans);
+}
+
+TEST(NStatistic, SameElem) {
+ std ::vector data = {7, 7, 7, 7};
+ int n = 2;
+ int ans = 7;
+ ASSERT_EQ(NStatistic(data, n), ans);
+}
+
+TEST(NStatistic, NegativeElem) {
+ std ::vector data = {-5, 0, -1, 3, -2};
+ int n = 2;
+ int ans = -1;
+ ASSERT_EQ(NStatistic(data, n), ans);
+}
+
+TEST(NStatistic, BigN) {
+ std ::vector data = {1, 2, 3, 65, 4};
+ int n = 100;
+ EXPECT_THROW(NStatistic(data, n), std::invalid_argument);
+}
+
+TEST(NStatistic, Empty) {
+ std ::vector data = {};
+ int n = 0;
+ EXPECT_THROW(NStatistic(data, n), std::invalid_argument);
}
diff --git a/task_07/CMakeLists.txt b/task_07/CMakeLists.txt
index 91b6a60..68f94d9 100644
--- a/task_07/CMakeLists.txt
+++ b/task_07/CMakeLists.txt
@@ -24,11 +24,14 @@ add_executable(${PROJECT_NAME} ${source_list})
enable_testing()
find_package(GTest REQUIRED)
+
+
include_directories(${GTEST_INCLUDE_DIRS})
find_library(Utils ../)
target_link_libraries(${PROJECT_NAME} PUBLIC Utils)
+
# 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(
diff --git a/task_07/src/KDtree.cpp b/task_07/src/KDtree.cpp
new file mode 100644
index 0000000..fd284f4
--- /dev/null
+++ b/task_07/src/KDtree.cpp
@@ -0,0 +1,96 @@
+#include "KDtree.hpp"
+
+#include
+
+#include
+#include
+#include
+
+void KDTree::PreparePoints(std::vector& points) {
+ std::sort(std::execution::par, points.begin(), points.end(),
+ [](const Point& a, const Point& b) {
+ return std::tie(a.x, a.y) < std::tie(b.x, b.y);
+ });
+
+ auto equal = [](const Point& a, const Point& b) {
+ return a.x == b.x && a.y == b.y;
+ };
+ points.erase(std::unique(points.begin(), points.end(), equal), points.end());
+}
+
+void KDTree::Split(std::unique_ptr& node, Axis Ax, int depth) {
+ std::pair SAH = KDTree::SAH(
+ node->bounding_box.first, node->bounding_box.second, Ax, node->indices);
+
+ double SAH_parant = Ci * (node->indices.second - node->indices.first);
+
+ if (SAH.first >= SAH_parant) {
+ node->leaf = true;
+ return;
+ }
+
+ node->left_child = std::make_unique();
+ node->right_child = std::make_unique();
+
+ if (Ax == Axis::Ox) {
+ node->left_child->bounding_box.first = node->bounding_box.first;
+ node->left_child->bounding_box.second =
+ Point(SAH.second, node->bounding_box.second.y);
+ node->right_child->bounding_box.first =
+ Point(SAH.second, node->bounding_box.first.y);
+ node->right_child->bounding_box.second = node->bounding_box.second;
+ } else {
+ node->right_child->bounding_box.first =
+ Point(node->bounding_box.first.x, SAH.second);
+ node->right_child->bounding_box.second = node->bounding_box.second;
+
+ node->left_child->bounding_box.first = node->bounding_box.first;
+ node->left_child->bounding_box.second =
+ Point(node->bounding_box.second.x, SAH.second);
+ }
+
+ node->left_child->indices.first = node->indices.first;
+
+ int left_count = std::count_if(
+ std::execution::par, cloud.begin() + node->indices.first,
+ cloud.begin() + node->indices.second + 1,
+ [Ax, split_pos = SAH.second](const Point& p) {
+ return (Ax == Axis::Ox) ? p.x < split_pos : p.y < split_pos;
+ });
+
+ node->left_child->indices.second = node->indices.first + left_count - 1;
+ node->right_child->indices.first = node->indices.first + left_count;
+ node->right_child->indices.second = node->indices.second;
+
+ Ax = (Ax == Axis::Ox) ? Axis::Oy : Axis::Ox;
+
+ if (depth < max_parallel_depth) {
+#pragma omp task shared(node)
+ Split(node->left_child, Ax, depth + 1);
+
+#pragma omp task shared(node)
+ Split(node->right_child, Ax, depth + 1);
+
+#pragma omp taskwait
+ } else {
+ Split(node->left_child, Ax, depth + 1);
+ Split(node->right_child, Ax, depth + 1);
+ }
+}
+
+KDTree::KDTree(std ::vector points) {
+ if (points.empty()) throw std::invalid_argument{"No Points detected"};
+
+ cloud = std::move(points);
+ PreparePoints(cloud);
+
+ root = std::make_unique();
+ root->indices = std::make_pair(0, cloud.size() - 1);
+ root->bounding_box = std::make_pair(cloud[0], cloud[cloud.size() - 1]);
+
+#pragma omp parallel
+ {
+#pragma omp single nowait
+ Split(root, Axis::Ox, 0);
+ }
+}
diff --git a/task_07/src/KDtree.hpp b/task_07/src/KDtree.hpp
new file mode 100644
index 0000000..4297920
--- /dev/null
+++ b/task_07/src/KDtree.hpp
@@ -0,0 +1,64 @@
+#ifndef KDtreeHpp
+#define KDtreeHpp
+
+#include
+#include
+
+#include "constants.hpp"
+
+struct Point {
+ double x;
+ double y;
+ Point(double x, double y) : x{x}, y{y} {}
+ Point() : x{NONE}, y{NONE} {}
+
+ bool operator==(const Point& other) const {
+ constexpr double epsilon = 1e-9;
+ return (std::abs(x - other.x) < epsilon) &&
+ (std::abs(y - other.y) < epsilon);
+ }
+};
+
+class KDTree {
+ public:
+ KDTree(std::vector points);
+ ~KDTree() = default;
+ Point NearestPoint(Point target);
+
+ private:
+ std ::vector cloud;
+
+ struct Node {
+ bool leaf = false;
+ std::unique_ptr left_child = nullptr;
+ std::unique_ptr right_child = nullptr;
+ std::pair bounding_box =
+ std::make_pair(Point(0, 0), Point(0, 0));
+ std ::pair indices; // промежуток точек
+ // принадлежащих данной bounding_box [от, до]
+ };
+ std::unique_ptr root;
+ enum class Axis {
+ Ox = 0,
+ Oy = 1,
+ };
+
+ void Split(std::unique_ptr& node, Axis Ax = Axis::Ox, int depth = 0);
+ std ::pair SAH(Point left_min_point, Point right_max_point,
+ Axis curr_Axis, std::pair& range);
+ std::pair FindMinimum(Point target,
+ std::unique_ptr& node);
+ void PreparePoints(std::vector& points);
+ double Distance(Point first, Point second);
+ double DistanceToBox(Point& point, std::pair& box);
+ bool IntoBox(Point target, std::pair box);
+
+ template
+ auto GetAxis(const T& request, Axis ax) {
+ if (ax == Axis::Ox)
+ return request.x;
+ else
+ return request.y;
+ }
+};
+#endif
\ No newline at end of file
diff --git a/task_07/src/SAH.cpp b/task_07/src/SAH.cpp
new file mode 100644
index 0000000..d661765
--- /dev/null
+++ b/task_07/src/SAH.cpp
@@ -0,0 +1,55 @@
+#include
+
+#include
+
+#include "KDtree.hpp"
+#include "constants.hpp"
+
+std::pair KDTree::SAH(Point left_min_point,
+ Point right_max_point, Axis curr_axis,
+ std::pair& range) {
+ std::pair SAH_result{NONE, NONE};
+ double width =
+ GetAxis(right_max_point, curr_axis) - GetAxis(left_min_point, curr_axis);
+ double width_x = right_max_point.x - left_min_point.x;
+ double width_y = right_max_point.y - left_min_point.y;
+ double width_w = curr_axis == Axis::Ox ? width_y : width_x;
+ double SApar = width_x * width_y;
+
+ if (SApar <= 0) return SAH_result;
+
+ const int bins = PARITION;
+ std::vector binCounts(bins, 0);
+
+ double bin_width = width / bins;
+ if (bin_width <= 0) return SAH_result;
+
+ for (int index = range.first; index <= range.second; ++index) {
+ int bin_index = static_cast((GetAxis(cloud[index], curr_axis) -
+ GetAxis(left_min_point, curr_axis)) /
+ bin_width);
+ bin_index = std::clamp(bin_index, 0, bins - 1);
+ ++binCounts[bin_index];
+ }
+
+ std::vector prefix_sum(bins + 1, 0);
+ for (int i = 1; i <= bins; ++i) {
+ prefix_sum[i] = prefix_sum[i - 1] + binCounts[i - 1];
+ }
+
+ for (int i = 1; i < bins; ++i) {
+ double x0 = GetAxis(left_min_point, curr_axis) + width * i / bins;
+ double SAl = (x0 - GetAxis(left_min_point, curr_axis)) * width_w;
+ double SAr = (GetAxis(right_max_point, curr_axis) - x0) * width_w;
+
+ int Nl = prefix_sum[i];
+ int Nr = (range.second - range.first + 1) - Nl;
+
+ double SAH = Ct + Ci * (SAl * Nl + SAr * Nr) / SApar;
+ if ((SAH < SAH_result.first) || (SAH_result.first < 0)) {
+ SAH_result = std::make_pair(SAH, x0);
+ }
+ }
+
+ return SAH_result;
+}
\ No newline at end of file
diff --git a/task_07/src/constants.hpp b/task_07/src/constants.hpp
new file mode 100644
index 0000000..ca6ee32
--- /dev/null
+++ b/task_07/src/constants.hpp
@@ -0,0 +1,11 @@
+#ifndef CONSTS
+#define CONSTS
+#include
+// SAH
+constexpr double Ct{1}; // стоимость прослеживания луча внутри узла
+constexpr double Ci{1}; // стоимость пересечения (плоскостью) лучом
+constexpr double PARITION{33}; // разбиение по оси
+
+constexpr double NONE{std::numeric_limits::max()};
+constexpr int max_parallel_depth{4};
+#endif
\ No newline at end of file
diff --git a/task_07/src/main.cpp b/task_07/src/main.cpp
index 0e4393b..87affd0 100644
--- a/task_07/src/main.cpp
+++ b/task_07/src/main.cpp
@@ -1,3 +1,16 @@
#include
-int main() { return 0; }
+#include "KDtree.hpp"
+#include "vector"
+
+int main() {
+ std::vector cloud = {
+ Point(1.0, 2.0), Point(3.0, 4.0), Point(5.0, 6.0),
+ Point(7.0, 8.0), Point(9.0, 10.0),
+ };
+
+ KDTree tree(cloud);
+ std ::cout << "compiled\n";
+ Point k = tree.NearestPoint(Point(4.8, 5.9));
+ std ::cout << k.x << " " << k.y << '\n';
+}
diff --git a/task_07/src/min_search.cpp b/task_07/src/min_search.cpp
new file mode 100644
index 0000000..eccfa07
--- /dev/null
+++ b/task_07/src/min_search.cpp
@@ -0,0 +1,59 @@
+#include
+
+#include "KDtree.hpp"
+
+double KDTree::Distance(Point first, Point second) {
+ return ((first.x - second.x) * (first.x - second.x) +
+ (first.y - second.y) * (first.y - second.y));
+}
+
+bool KDTree::IntoBox(Point target, std::pair box) {
+ if ((target.x >= box.first.x) && (target.x <= box.second.x)) {
+ if ((target.y >= box.first.y) && (target.y <= box.second.y)) return true;
+ }
+ return false;
+}
+
+double KDTree::DistanceToBox(Point& point, std::pair& box) {
+ double dx = std::max({box.first.x - point.x, 0.0, point.x - box.second.x});
+ double dy = std::max({box.first.y - point.y, 0.0, point.y - box.second.y});
+ return dx * dx + dy * dy;
+}
+
+std::pair KDTree::FindMinimum(Point target,
+ std::unique_ptr& node) {
+ if (node->leaf) {
+ double min_dist = NONE;
+ Point NearestPoint;
+ for (int i = node->indices.first; i <= node->indices.second; ++i) {
+ double current_dist = Distance(cloud[i], target);
+ if (current_dist < min_dist) {
+ min_dist = current_dist;
+ NearestPoint = cloud[i];
+ }
+ }
+ return {min_dist, NearestPoint};
+ }
+
+ bool target_in_left = IntoBox(target, node->left_child->bounding_box);
+ auto& first_child = target_in_left ? node->left_child : node->right_child;
+ auto& second_child = target_in_left ? node->right_child : node->left_child;
+
+ auto [min_dist, nearest] = FindMinimum(target, first_child);
+
+ double dist_to_second_box = DistanceToBox(target, second_child->bounding_box);
+ if (dist_to_second_box < min_dist) {
+ auto [second_dist, second_nearest] = FindMinimum(target, second_child);
+ if (second_dist < min_dist) {
+ min_dist = second_dist;
+ nearest = second_nearest;
+ }
+ }
+
+ return {min_dist, nearest};
+}
+
+Point KDTree::NearestPoint(Point target) {
+ auto point = FindMinimum(target, root);
+ return point.second;
+}
\ No newline at end of file
diff --git a/task_07/src/test.cpp b/task_07/src/test.cpp
index 5e11617..89d3cae 100644
--- a/task_07/src/test.cpp
+++ b/task_07/src/test.cpp
@@ -1,6 +1,124 @@
#include
-TEST(TopologySort, Simple) {
- ASSERT_EQ(1, 1); // Stack []
+#include
+#include
+#include
+
+#include "KDtree.hpp"
+
+std::vector GenerateRandomPoints(size_t count, double min = 0.0,
+ double max = 1000.0) {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_real_distribution dist(min, max);
+
+ std::vector points;
+ points.reserve(count);
+ for (size_t i = 0; i < count; ++i) {
+ points.emplace_back(dist(gen), dist(gen));
+ }
+ return points;
+}
+
+TEST(KD3, Simple) {
+ std::vector cloud = {
+ Point(1.0, 2.0), Point(3.0, 4.0), Point(5.0, 6.0),
+ Point(7.0, 8.0), Point(9.0, 10.0),
+ };
+
+ KDTree tree(cloud);
+
+ Point k = tree.NearestPoint(Point(4.8, 5.9));
+ ASSERT_EQ(k, Point(5.0, 6.0));
+}
+
+TEST(KD3, SameDistanse) {
+ std::vector cloud = {
+ Point(0.0, 0.0), Point(1.0, 0.0), Point(0.0, 1.0),
+ Point(-1.0, 0.0), Point(0.0, -1.0),
+ };
+
+ KDTree tree(cloud);
+
+ Point k = tree.NearestPoint(Point(0.0, 0.0));
+ ASSERT_EQ(k, Point(0.0, 0.0));
+}
+
+TEST(KD3, OneLine) {
+ std::vector cloud = {
+ Point(1.0, 1.0), Point(1.0, 2.0), Point(1.0, 3.0),
+ Point(1.0, 4.0), Point(1.0, 5.0),
+ };
+
+ KDTree tree(cloud);
+
+ Point k = tree.NearestPoint(Point(1.2, 3.1));
+ ASSERT_EQ(k, Point(1.0, 3.0));
+}
+
+TEST(KD3, Dublicates) {
+ std::vector cloud = {
+ Point(2.0, 2.0), Point(2.0, 2.0), Point(3.0, 3.0),
+ Point(2.0, 2.0), Point(4.0, 4.0),
+ };
+
+ KDTree tree(cloud);
+
+ Point k = tree.NearestPoint(Point(2.1, 2.1));
+ ASSERT_EQ(k, Point(2.0, 2.0));
+}
+
+TEST(KD3, Error) {
+ std::vector cloud(0);
+ EXPECT_THROW(KDTree tree(cloud), std::invalid_argument);
+}
+
+TEST(KD3, TimeTest_1000) {
+ auto cloud = GenerateRandomPoints(1000);
+
+ auto start = std::chrono::high_resolution_clock::now();
+ KDTree tree(cloud);
+ auto end = std::chrono::high_resolution_clock::now();
+
+ auto duration =
+ std::chrono::duration_cast(end - start);
+ EXPECT_TRUE(duration.count() < 500);
+}
+
+TEST(KD3, TimeTest_10000) {
+ auto cloud = GenerateRandomPoints(10000);
+
+ auto start = std::chrono::high_resolution_clock::now();
+ KDTree tree(cloud);
+ auto end = std::chrono::high_resolution_clock::now();
+
+ auto duration =
+ std::chrono::duration_cast(end - start);
+ EXPECT_TRUE(duration.count() < 500);
}
+
+TEST(KD3, TimeTest_1M) {
+ auto cloud = GenerateRandomPoints(1000000);
+
+ auto start = std::chrono::high_resolution_clock::now();
+ KDTree tree(cloud);
+ auto end = std::chrono::high_resolution_clock::now();
+
+ auto duration =
+ std::chrono::duration_cast(end - start);
+ EXPECT_TRUE(duration.count() < 5000);
+}
+
+TEST(KD3, TimeTest_10M) {
+ auto cloud = GenerateRandomPoints(10'000'000);
+
+ KDTree tree(cloud);
+ auto start = std::chrono::high_resolution_clock::now();
+
+ tree.NearestPoint(Point(3.75, 2.1));
+ auto end = std::chrono::high_resolution_clock::now();
+ auto duration =
+ std::chrono::duration_cast(end - start);
+ EXPECT_TRUE(duration.count() < 20000);
+}
\ No newline at end of file
diff --git a/task_08/src/HashTable.cpp b/task_08/src/HashTable.cpp
new file mode 100644
index 0000000..b58109b
--- /dev/null
+++ b/task_08/src/HashTable.cpp
@@ -0,0 +1,70 @@
+#include "HashTable.hpp"
+
+#include
+#include
+
+size_t HashTable::MyHash(const std::string& value) {
+ return std::hash{}(value) * 0xdeadbeef;
+}
+
+HashTable::HashTable() {
+ std::vector PreparedData(13, ZeroElem);
+ data = std::move(PreparedData);
+}
+
+void HashTable::Resize() {
+ std::vector NewData(data.size() * 2, ZeroElem);
+ std::vector OldData = std::move(data);
+ data = std::move(NewData);
+ for (auto& elem : OldData) {
+ if (elem.CurrentLabel == Label::Full) {
+ add(elem.Key, elem.Value);
+ }
+ }
+}
+
+void HashTable::add(const std::string& key, int value) {
+ int index = MyHash(key) % data.size();
+ int BeginingIndex = index;
+ while ((data[index].CurrentLabel != Label::Empty) &&
+ (data[index].CurrentLabel != Label::Deleted)) {
+ if (data[index].CurrentLabel == Label::Full && data[index].Key == key) {
+ data[index].Value = value;
+ return;
+ }
+ ++index;
+ if (index >= data.size()) index = 0;
+ if (index == BeginingIndex) break;
+ }
+ data[index].Value = value;
+ data[index].Key = key;
+ data[index].CurrentLabel = Label::Full;
+ ++EngagedSpace;
+ if (EngagedSpace > (data.size() / 2)) Resize();
+}
+
+void HashTable::remove(const std::string& key) {
+ int index = MyHash(key) % data.size();
+ int BeginingIndex = index;
+ while (data[index].Key != key) {
+ ++index;
+ if (index >= data.size()) index = 0;
+ if (index == BeginingIndex) throw std::runtime_error("ValueError");
+ }
+ data[index].CurrentLabel = Label::Deleted;
+ --EngagedSpace;
+}
+
+int HashTable::get(const std::string& key) {
+ int index = MyHash(key) % data.size();
+ while ((data[index].Key != key) &&
+ (data[index].CurrentLabel != Label::Empty)) {
+ ++index;
+ if (index >= data.size()) index = 0;
+ }
+ if (data[index].CurrentLabel == Label::Empty) {
+ throw std::runtime_error("ValueError");
+ } else {
+ return data[index].Value;
+ }
+}
\ No newline at end of file
diff --git a/task_08/src/HashTable.hpp b/task_08/src/HashTable.hpp
new file mode 100644
index 0000000..2934db2
--- /dev/null
+++ b/task_08/src/HashTable.hpp
@@ -0,0 +1,28 @@
+#include
+#include
+
+class HashTable {
+ public:
+ HashTable();
+
+ void add(const std::string& key, int value);
+ void remove(const std::string& key);
+ int get(const std::string& key);
+
+ private:
+ enum struct Label {
+ Empty = 0,
+ Full = 1,
+ Deleted = 2,
+ };
+ struct Elem {
+ Label CurrentLabel;
+ int Value;
+ std::string Key;
+ };
+ int EngagedSpace = 0;
+ std ::vector data;
+ size_t MyHash(const std::string& value);
+ void Resize();
+ Elem ZeroElem = {Label::Empty, 0};
+};
\ No newline at end of file
diff --git a/task_08/src/main.cpp b/task_08/src/main.cpp
index 0e4393b..3d180c4 100644
--- a/task_08/src/main.cpp
+++ b/task_08/src/main.cpp
@@ -1,3 +1,3 @@
-#include
+#include "HashTable.hpp"
-int main() { return 0; }
+int main() {}
\ No newline at end of file
diff --git a/task_08/src/test.cpp b/task_08/src/test.cpp
index 5e11617..2e62a39 100644
--- a/task_08/src/test.cpp
+++ b/task_08/src/test.cpp
@@ -1,6 +1,86 @@
-
#include
-TEST(TopologySort, Simple) {
- ASSERT_EQ(1, 1); // Stack []
+#include "HashTable.hpp"
+
+TEST(HashTable, Simple) {
+ HashTable table;
+ table.add("first", 1);
+ table.add("second", 2);
+ ASSERT_EQ(table.get("first"), 1);
+}
+
+TEST(HashTable, DeleteTest) {
+ HashTable table;
+ table.add("first", 1);
+ table.add("second", 2);
+ table.add("second_full", 3);
+ table.remove("second");
+ ASSERT_EQ(table.get("second_full"), 3);
}
+
+TEST(HashTable, FalseDelete) {
+ HashTable table;
+ table.add("first", 1);
+ table.add("second", 2);
+ EXPECT_THROW(table.remove("no_second"), std::runtime_error);
+}
+
+TEST(HashTable, FalseGet) {
+ HashTable table;
+ table.add("first", 1);
+ table.add("second", 2);
+ EXPECT_THROW(table.get("no_second"), std::runtime_error);
+}
+
+TEST(HashTable, ResizeTest1) {
+ HashTable table;
+ table.add("1", -8);
+ table.add("2", 2);
+ table.add("3", 1);
+ table.add("4", 2);
+ table.add("5", 1);
+ table.add("5", 2);
+ table.add("6", 1);
+ table.add("7", 2);
+ table.add("8", 1);
+ table.add("9", 2);
+ table.add("10", 1);
+ table.add("11", 2);
+ table.add("12", 1);
+ table.add("13", 2);
+ table.add("14", 1);
+ table.add("15", 2);
+ table.add("16", 1);
+ table.add("17", 2);
+ ASSERT_EQ(table.get("1"), -8);
+}
+
+TEST(HashTable, ResizeTest2) {
+ HashTable table;
+ table.add("1", -8);
+ table.add("2", 2);
+ table.add("3", 1);
+ table.add("4", 2);
+ table.add("5", 1);
+ table.add("5", 2);
+ table.add("6", 1);
+ table.add("7", 2);
+ table.add("8", 1);
+ table.add("9", 2);
+ table.add("10", 1);
+ table.add("11", 2);
+ table.add("12", 1);
+ table.add("13", 2);
+ table.add("14", 1);
+ table.add("15", 2);
+ table.add("16", 1);
+ table.add("17", 19);
+ ASSERT_EQ(table.get("17"), 19);
+}
+
+TEST(HashTable, AddSameKey) {
+ HashTable table;
+ table.add("first", 1);
+ table.add("first", 2);
+ ASSERT_EQ(table.get("first"), 2);
+}
\ No newline at end of file
diff --git a/task_09/src/TableTask.cpp b/task_09/src/TableTask.cpp
new file mode 100644
index 0000000..a38818e
--- /dev/null
+++ b/task_09/src/TableTask.cpp
@@ -0,0 +1,45 @@
+#include "TableTask.hpp"
+
+std::vector TaskSolve(int n, int m, int k,
+ std::vector>& table,
+ std::vector>& queries) {
+ std::vector answer;
+ std::vector> IsGood(n - 1, std::vector(m));
+
+ for (int j = 0; j < m; ++j) {
+ for (int i = 0; i < n - 1; ++i) {
+ IsGood[i][j] = (table[i][j] <= table[i + 1][j]);
+ }
+ }
+
+ std::vector> prefix(m, std::vector(n));
+ for (int j = 0; j < m; ++j) {
+ prefix[j][0] = 0;
+ for (int i = 1; i < n; ++i) {
+ prefix[j][i] = prefix[j][i - 1] + (IsGood[i - 1][j] ? 1 : 0);
+ }
+ }
+
+ for (auto& query : queries) {
+ int l = query.first - 1;
+ int r = query.second - 1;
+
+ if (l == r) {
+ answer.push_back("Yes");
+ continue;
+ }
+
+ bool found = false;
+ for (int j = 0; j < m; ++j) {
+ int cnt = prefix[j][r] - prefix[j][l];
+ if (cnt == r - l) {
+ found = true;
+ break;
+ }
+ }
+
+ answer.push_back(found ? "Yes" : "No");
+ }
+
+ return answer;
+}
\ No newline at end of file
diff --git a/task_09/src/TableTask.hpp b/task_09/src/TableTask.hpp
new file mode 100644
index 0000000..932fad5
--- /dev/null
+++ b/task_09/src/TableTask.hpp
@@ -0,0 +1,6 @@
+#include
+#include
+
+std::vector TaskSolve(int n, int m, int k,
+ std::vector>& table,
+ std::vector>& queries);
\ No newline at end of file
diff --git a/task_09/src/test.cpp b/task_09/src/test.cpp
index a42caa4..f9479cd 100644
--- a/task_09/src/test.cpp
+++ b/task_09/src/test.cpp
@@ -1,23 +1,54 @@
#include
-#include
+#include "TableTask.hpp"
+
+TEST(CanReachNonDecreasingSegment, SampleTest) {
+ std::vector> table = {
+ {1, 2, 3, 5}, {3, 1, 3, 2}, {4, 5, 2, 3}, {5, 5, 3, 2}, {4, 4, 3, 4}};
+
+ std::vector> queries = {{1, 1}, {2, 5}, {4, 5},
+ {3, 5}, {1, 3}, {1, 5}};
+
+ auto result = TaskSolve(5, 4, 6, table, queries);
+ std::vector expected = {"Yes", "No", "Yes", "Yes", "Yes", "No"};
+
+ ASSERT_EQ(result, expected);
+}
TEST(CanReachNonDecreasingSegment, 1) {
- // ASSERT_EQ(SolveFunction(5, 4, 6,
- // std::vector>{{1, 2, 3, 5},
- // {3, 1, 3, 2},
- // {4, 5, 2, 3},
- // {5, 5, 3, 2},
- // {4, 4, 3, 4}},
- // std::vector>{
- // {1, 1}, {2, 5}, {4, 5}, {3, 5}, {1, 3}, {1,
- // 5}}),
- // (std::vector{"Yes", "No", "Yes", "Yes", "Yes",
- // "No"}));
+ std::vector> table = {
+ {1, 2, 3, 5}, {3, 1, 3, 2}, {4, 5, 2, 3}, {5, 5, 3, 2}, {4, 4, 3, 4}};
+ std::vector> queries{{1, 1}, {2, 5}, {4, 5},
+ {3, 5}, {1, 3}, {1, 5}};
+ ASSERT_EQ(TaskSolve(5, 4, 6, table, queries),
+ (std::vector{"Yes", "No", "Yes", "Yes", "Yes", "No"}));
}
TEST(CanReachNonDecreasingSegment, 2) {
- // ASSERT_EQ(SolveFunction(1, 1, 1, std::vector>{{1, 1}},
- // std::vector>{{1, 1}}),
- // (std::vector{"Yes"}));
+ std::vector> table = {{1, 1}};
+ std::vector> queries = {{1, 1}};
+ ASSERT_EQ(TaskSolve(1, 1, 1, table, queries),
+ (std::vector{"Yes"}));
}
+
+TEST(CanReachNonDecreasingSegment, SingleElement) {
+ std::vector> table = {{1}};
+ std::vector> queries{{1, 1}};
+ ASSERT_EQ(TaskSolve(1, 1, 1, table, queries),
+ (std::vector{"Yes"}));
+}
+
+TEST(CanReachNonDecreasingSegment, AllColumnsSorted) {
+ std::vector> table = {{1, 1, 1}, {2, 2, 2}, {3, 3, 3}};
+ std::vector> queries{{1, 3}, {2, 3}, {1, 2}};
+ ASSERT_EQ(TaskSolve(3, 3, 3, table, queries),
+ (std::vector{"Yes", "Yes", "Yes"}));
+}
+
+TEST(CanReachNonDecreasingSegment, OneColumnSorted) {
+ std::vector> table = {
+ {5, 1}, {4, 2}, {3, 3}, {2, 4}, {1, 5}};
+ std::vector> queries{{1, 5}, {2, 4}, {3, 5}};
+ ASSERT_EQ(TaskSolve(5, 2, 3, table, queries),
+ (std::vector{"Yes", "Yes", "Yes"}));
+}
\ No newline at end of file