diff --git a/CMakeLists.txt b/CMakeLists.txt index fb5abf3a..1871b521 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,12 @@ include(cmake/function.cmake) # подхватываем функции, # и для создания исполняемого проекта в отдельные функции add_subdirectory(lib_easy_example) # подключаем дополнительный CMakeLists.txt из подкаталога с именем lib_easy_example +add_subdirectory(lib_DSU) +add_subdirectory(lib_stack) +add_subdirectory(lib_list) +add_subdirectory(lib_stackL) +add_subdirectory(lib_queueL) +add_subdirectory(lib_alg) add_subdirectory(main) # подключаем дополнительный CMakeLists.txt из подкаталога с именем main diff --git a/lib_DSU/CMakeLists.txt b/lib_DSU/CMakeLists.txt new file mode 100644 index 00000000..424d2417 --- /dev/null +++ b/lib_DSU/CMakeLists.txt @@ -0,0 +1 @@ +create_project_lib(DSU) \ No newline at end of file diff --git a/lib_DSU/DSU.cpp b/lib_DSU/DSU.cpp new file mode 100644 index 00000000..db9a54d8 --- /dev/null +++ b/lib_DSU/DSU.cpp @@ -0,0 +1 @@ +#include "DSU.h" \ No newline at end of file diff --git a/lib_DSU/DSU.h b/lib_DSU/DSU.h new file mode 100644 index 00000000..af7c6898 --- /dev/null +++ b/lib_DSU/DSU.h @@ -0,0 +1,119 @@ +#pragma once +#include + +class DSU { +private: + int* _parent; + int* _rank; + int _size; + +public: + explicit DSU(int n); + ~DSU(); + + DSU(const DSU&) = delete; + DSU& operator=(const DSU&) = delete; + + + DSU(DSU&& other) noexcept; + DSU& operator=(DSU&& other) noexcept; + + int find(int x); + void unite(int x, int y); + bool same(int x, int y); + int size() const; + int sets_count() const; +}; + +inline DSU::DSU(int n) : _size(n) { + if (n <= 0) { + throw std::invalid_argument("DSU size must be positive"); + } + + _parent = new int[n]; + _rank = new int[n]; + + for (int i = 0; i < n; ++i) { + _parent[i] = i; + _rank[i] = 0; + } +} + +inline DSU::~DSU() { + delete[] _parent; + delete[] _rank; +} + +inline DSU::DSU(DSU&& other) noexcept + : _parent(other._parent), _rank(other._rank), _size(other._size) { + other._parent = nullptr; + other._rank = nullptr; + other._size = 0; +} + +inline DSU& DSU::operator=(DSU&& other) noexcept { + if (this != &other) { + delete[] _parent; + delete[] _rank; + + _parent = other._parent; + _rank = other._rank; + _size = other._size; + + other._parent = nullptr; + other._rank = nullptr; + other._size = 0; + } + return *this; +} + +inline int DSU::find(int x) { + if (x < 0 || x >= _size) { + throw std::out_of_range("DSU index out of range in find"); + } + + if (_parent[x] != x) { + _parent[x] = find(_parent[x]); + } + return _parent[x]; +} + +inline void DSU::unite(int x, int y) { + int rootX = find(x); + int rootY = find(y); + + if (rootX == rootY) return; + + + if (_rank[rootX] < _rank[rootY]) { + _parent[rootX] = rootY; + } + else if (_rank[rootX] > _rank[rootY]) { + _parent[rootY] = rootX; + } + else { + _parent[rootY] = rootX; + _rank[rootX]++; + } +} + + +inline bool DSU::same(int x, int y) { + return find(x) == find(y); +} + + +inline int DSU::size() const { + return _size; +} + + +inline int DSU::sets_count() const { + int count = 0; + for (int i = 0; i < _size; ++i) { + if (_parent[i] == i) { + count++; + } + } + return count; +} \ No newline at end of file diff --git a/lib_alg/CMakeLists.txt b/lib_alg/CMakeLists.txt new file mode 100644 index 00000000..32c3b3d8 --- /dev/null +++ b/lib_alg/CMakeLists.txt @@ -0,0 +1,3 @@ +create_project_lib(Alg) +add_depend(Alg DSU ..\\lib_DSU) +add_depend(Alg Stack ..\\lib_stack) \ No newline at end of file diff --git a/lib_alg/alg.cpp b/lib_alg/alg.cpp new file mode 100644 index 00000000..edf70adc --- /dev/null +++ b/lib_alg/alg.cpp @@ -0,0 +1,71 @@ +#include "alg.h" + +int countIslands(int** grid, int N) { + if (N <= 0) return 0; + + DSU dsu(N * N); + + for (int i = 0; i < N; ++i) { + for (int j = 0; j < N; ++j) { + if (grid[i][j] == 0) continue; + + int currentIndex = i * N + j; + + if (j + 1 < N && grid[i][j + 1] == 1) { + dsu.unite(currentIndex, i * N + (j + 1)); + } + + if (i + 1 < N && grid[i + 1][j] == 1) { + dsu.unite(currentIndex, (i + 1) * N + j); + } + } + } + + + std::vector isIslandRoot(N * N, false); + int islandCount = 0; + + for (int i = 0; i < N; ++i) { + for (int j = 0; j < N; ++j) { + if (grid[i][j] == 1) { + int root = dsu.find(i * N + j); + if (!isIslandRoot[root]) { + isIslandRoot[root] = true; + islandCount++; + } + } + } + } + + return islandCount; +} + +bool check_brackets(const std::string& str) { + Stack brackets; + + for (char c : str) { + if (c == '(' || c == '[' || c == '{') { + brackets.push(c); + } + else if (c == ')') { + if (brackets.is_empty() || brackets.top() != '(') { + return false; + } + brackets.pop(); + } + else if (c == ']') { + if (brackets.is_empty() || brackets.top() != '[') { + return false; + } + brackets.pop(); + } + else if (c == '}') { + if (brackets.is_empty() || brackets.top() != '{') { + return false; + } + brackets.pop(); + } + } + + return brackets.is_empty(); +} \ No newline at end of file diff --git a/lib_alg/alg.h b/lib_alg/alg.h new file mode 100644 index 00000000..e793b878 --- /dev/null +++ b/lib_alg/alg.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +#include "stack.h" +#include "dsu.h" + +int countIslands(int** grid, int N); +bool check_brackets(const std::string& str); + +//int countIslands(int** grid, int N) { +// if (N <= 0) return 0; +// +// int** dynamicGrid = new int* [N]; +// for (int i = 0; i < N; ++i) { +// dynamicGrid[i] = new int[N]; +// for (int j = 0; j < N; ++j) { +// dynamicGrid[i][j] = grid[i][j]; +// } +// } +// +// int result = countIslands(dynamicGrid, N); +// +// +// for (int i = 0; i < N; ++i) { +// delete[] dynamicGrid[i]; +// } +// delete[] dynamicGrid; +// +// return result; +//} + + +//inline int** createGrid(int N, ) { +// int** grid = new int* [N]; +// for (int i = 0; i < N; ++i) { +// grid[i] = new int[N]; +// for (int j = 0; j < N; ++j) { +// grid[i][j] = initFunc(i, j); +// } +// } +// return grid; +//} +// +//inline void deleteGrid(int** grid, int N) { +// for (int i = 0; i < N; ++i) { +// delete[] grid[i]; +// } +// delete[] grid; +//} + diff --git a/lib_list/CMakeLists.txt b/lib_list/CMakeLists.txt new file mode 100644 index 00000000..148b539a --- /dev/null +++ b/lib_list/CMakeLists.txt @@ -0,0 +1 @@ +create_project_lib(List) \ No newline at end of file diff --git a/lib_list/list.cpp b/lib_list/list.cpp new file mode 100644 index 00000000..811c5120 --- /dev/null +++ b/lib_list/list.cpp @@ -0,0 +1 @@ +#include "list.h" \ No newline at end of file diff --git a/lib_list/list.h b/lib_list/list.h new file mode 100644 index 00000000..bdfafb09 --- /dev/null +++ b/lib_list/list.h @@ -0,0 +1,275 @@ +#pragma once +#include +#include +#include + +template +class List { +private: + struct Node { + T value; + Node* next; + + Node(const T& val, Node* next_node = nullptr) + : value(val), next(next_node) { + } + }; + + Node* head; + Node* tail; + size_t size; + +public: + // / + List() : head(nullptr), tail(nullptr), size(0) {} + + List(const List& other) : head(nullptr), tail(nullptr), size(0) { + Node* current = other.head; + while (current != nullptr) { + push_back(current->value); + current = current->next; + } + } + + List& operator=(const List& other) { + if (this != &other) { + clear(); + Node* current = other.head; + while (current != nullptr) { + push_back(current->value); + current = current->next; + } + } + return *this; + } + + ~List() { + clear(); + } + + // + void push_front(const T& value) { + head = new Node(value, head); + if (tail == nullptr) { + tail = head; + } + size++; + } + + void push_back(const T& value) { + Node* new_node = new Node(value); + if (tail == nullptr) { + head = tail = new_node; + } + else { + tail->next = new_node; + tail = new_node; + } + size++; + } + + void pop_front() { + if (empty()) { + throw std::out_of_range("pop_front from empty list"); + } + + Node* temp = head; + head = head->next; + if (head == nullptr) { + tail = nullptr; + } + delete temp; + size--; + } + + void pop_back() { + if (empty()) { + throw std::out_of_range("pop_back from empty list"); + } + + if (head == tail) { + delete head; + head = tail = nullptr; + } + else { + Node* current = head; + while (current->next != tail) { + current = current->next; + } + delete tail; + tail = current; + tail->next = nullptr; + } + size--; + } + + T& front() { + if (empty()) { + throw std::out_of_range("front from empty list"); + } + return head->value; + } + + const T& front() const { + if (empty()) { + throw std::out_of_range("front from empty list"); + } + return head->value; + } + + T& back() { + if (empty()) { + throw std::out_of_range("back from empty list"); + } + return tail->value; + } + + const T& back() const { + if (empty()) { + throw std::out_of_range("back from empty list"); + } + return tail->value; + } + + bool empty() const { + return size == 0; + } + + size_t get_size() const { + return size; + } + + void clear() { + while (!empty()) { + pop_front(); + } + } + + + class Iterator { + private: + Node* current; + + public: + Node* get_node() const { return current; }; + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + + Iterator(Node* node = nullptr) : current(node) {} + + + Iterator& operator++() { + if (current != nullptr) { + current = current->next; + } + return *this; + } + + Iterator operator++(int) { + Iterator temp = *this; + ++(*this); + return temp; + } + + reference operator*() { + if (current == nullptr) { + throw std::out_of_range("dereferencing end iterator"); + } + return current->value; + } + + pointer operator->() { + if (current == nullptr) { + throw std::out_of_range("accessing member through end iterator"); + } + return &(current->value); + } + + bool operator==(const Iterator& other) const { + return current == other.current; + } + + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + }; + + + class ConstIterator { + private: + const Node* current; + + public: + const Node* get_node() const { return current; } + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = const T*; + using reference = const T&; + + ConstIterator(const Node* node = nullptr) : current(node) {} + + ConstIterator& operator++() { + if (current != nullptr) { + current = current->next; + } + return *this; + } + + ConstIterator operator++(int) { + ConstIterator temp = *this; + ++(*this); + return temp; + } + + reference operator*() const { + if (current == nullptr) { + throw std::out_of_range("dereferencing end iterator"); + } + return current->value; + } + + pointer operator->() const { + if (current == nullptr) { + throw std::out_of_range("accessing member through end iterator"); + } + return &(current->value); + } + + bool operator==(const ConstIterator& other) const { + return current == other.current; + } + + bool operator!=(const ConstIterator& other) const { + return !(*this == other); + } + }; + + + Iterator begin() { + return Iterator(head); + } + + Iterator end() { + return Iterator(nullptr); + } + + ConstIterator begin() const { + return ConstIterator(head); + } + + ConstIterator end() const { + return ConstIterator(nullptr); + } + + ConstIterator cbegin() const { + return ConstIterator(head); + } + + ConstIterator cend() const { + return ConstIterator(nullptr); + } +}; \ No newline at end of file diff --git a/lib_queueL/CMakeLists.txt b/lib_queueL/CMakeLists.txt new file mode 100644 index 00000000..84f0f468 --- /dev/null +++ b/lib_queueL/CMakeLists.txt @@ -0,0 +1,2 @@ +create_project_lib(QueueL) +add_depend(QueueL List ..\\lib_list) \ No newline at end of file diff --git a/lib_queueL/queueL.cpp b/lib_queueL/queueL.cpp new file mode 100644 index 00000000..7950b6ae --- /dev/null +++ b/lib_queueL/queueL.cpp @@ -0,0 +1 @@ +#include "queueL.h" \ No newline at end of file diff --git a/lib_queueL/queueL.h b/lib_queueL/queueL.h new file mode 100644 index 00000000..964e0c6b --- /dev/null +++ b/lib_queueL/queueL.h @@ -0,0 +1,84 @@ +#pragma once +#include "list.h" + +template +class QueueList { +private: + List list; + +public: + QueueList() = default; + + // + QueueList(const QueueList& other) : list(other.list) {} + + // + QueueList& operator=(const QueueList& other) { + if (this != &other) { + list = other.list; + } + return *this; + } + + // + QueueList(QueueList&& other) noexcept : list(std::move(other.list)) {} + + // + QueueList& operator=(QueueList&& other) noexcept { + if (this != &other) { + list = std::move(other.list); + } + return *this; + } + + void push(const T& value) { + list.push_back(value); + } + + void pop() { + if (empty()) { + throw std::out_of_range("pop from empty queue"); + } + list.pop_front(); + } + + T& front() { + if (empty()) { + throw std::out_of_range("front from empty queue"); + } + return list.front(); + } + + const T& front() const { + if (empty()) { + throw std::out_of_range("front from empty queue"); + } + return list.front(); + } + + T& back() { + if (empty()) { + throw std::out_of_range("back from empty queue"); + } + return list.back(); + } + + const T& back() const { + if (empty()) { + throw std::out_of_range("back from empty queue"); + } + return list.back(); + } + + bool empty() const { + return list.empty(); + } + + size_t size() const { + return list.get_size(); + } + + void clear() { + list.clear(); + } +}; \ No newline at end of file diff --git a/lib_stack/CMakeLists.txt b/lib_stack/CMakeLists.txt new file mode 100644 index 00000000..b6bedb01 --- /dev/null +++ b/lib_stack/CMakeLists.txt @@ -0,0 +1 @@ +create_project_lib(Stack) \ No newline at end of file diff --git a/lib_stack/stack.cpp b/lib_stack/stack.cpp new file mode 100644 index 00000000..3d38ae2e --- /dev/null +++ b/lib_stack/stack.cpp @@ -0,0 +1 @@ +#include "stack.h" \ No newline at end of file diff --git a/lib_stack/stack.h b/lib_stack/stack.h new file mode 100644 index 00000000..2effdf40 --- /dev/null +++ b/lib_stack/stack.h @@ -0,0 +1,116 @@ +#ifndef STACK_H +#define STACK_H + +#include + +template +class Stack { + T* _data; + int _size; + int _top; + +public: + Stack(); + explicit Stack(int size); + Stack(const Stack& other); + ~Stack(); + Stack& operator=(const Stack& other); + void push(const T& val); + void pop(); + T top() const; + inline bool is_empty() const noexcept; + inline bool is_full() const noexcept; + void clear(); + int capacity() const noexcept; + int count() const noexcept; +}; + + + +template +Stack::Stack() : _size(10), _top(-1) { + _data = new T[_size]; +} + +template +Stack::Stack(int size) : _size(size > 0 ? size : 10), _top(-1) { + _data = new T[_size]; +} + +template +Stack::Stack(const Stack& other) : _size(other._size), _top(other._top) { + _data = new T[_size]; + for (int i = 0; i <= _top; ++i) { + _data[i] = other._data[i]; + } +} + +template +Stack::~Stack() { + delete[] _data; +} + +template +Stack& Stack::operator=(const Stack& other) { + if (this != &other) { + delete[] _data; + _size = other._size; + _top = other._top; + _data = new T[_size]; + for (int i = 0; i <= _top; ++i) { + _data[i] = other._data[i]; + } + } + return *this; +} + +template +void Stack::push(const T& val) { + if (is_full()) { + throw std::runtime_error("Stack is full"); + } + _data[++_top] = val; +} + +template +void Stack::pop() { + if (is_empty()) { + throw std::runtime_error("Stack is empty"); + } + --_top; +} + +template +T Stack::top() const { + if (is_empty()) { + throw std::runtime_error("Stack is empty"); + } + return _data[_top]; +} + +template +inline bool Stack::is_empty() const noexcept { + return _top == -1; +} + +template +inline bool Stack::is_full() const noexcept { + return _top == _size - 1; +} + +template +void Stack::clear() { + _top = -1; +} + +template +int Stack::capacity() const noexcept { + return _size; +} + +template +int Stack::count() const noexcept { + return _top + 1; +} + +#endif // STACK_H \ No newline at end of file diff --git a/lib_stackL/CMakeLists.txt b/lib_stackL/CMakeLists.txt new file mode 100644 index 00000000..49cd32a0 --- /dev/null +++ b/lib_stackL/CMakeLists.txt @@ -0,0 +1,2 @@ +create_project_lib(StackL) +add_depend(StackL List ..\\lib_list) \ No newline at end of file diff --git a/lib_stackL/stackL.cpp b/lib_stackL/stackL.cpp new file mode 100644 index 00000000..70805b18 --- /dev/null +++ b/lib_stackL/stackL.cpp @@ -0,0 +1 @@ +#include "stackL.h" \ No newline at end of file diff --git a/lib_stackL/stackL.h b/lib_stackL/stackL.h new file mode 100644 index 00000000..c2db1cd8 --- /dev/null +++ b/lib_stackL/stackL.h @@ -0,0 +1,70 @@ +#pragma once +#include "list.h" + +template +class StackList { +private: + List list; + +public: + StackList() = default; + + // + StackList(const StackList& other) : list(other.list) {} + + // + StackList& operator=(const StackList& other) { + if (this != &other) { + list = other.list; + } + return *this; + } + + // + StackList(StackList&& other) noexcept : list(std::move(other.list)) {} + + // + StackList& operator=(StackList&& other) noexcept { + if (this != &other) { + list = std::move(other.list); + } + return *this; + } + + void push(const T& value) { + list.push_front(value); + } + + void pop() { + if (empty()) { + throw std::out_of_range("pop from empty stack"); + } + list.pop_front(); + } + + T& top() { + if (empty()) { + throw std::out_of_range("top from empty stack"); + } + return list.front(); + } + + const T& top() const { + if (empty()) { + throw std::out_of_range("top from empty stack"); + } + return list.front(); + } + + bool empty() const { + return list.empty(); + } + + size_t size() const { + return list.get_size(); + } + + void clear() { + list.clear(); + } +}; \ No newline at end of file diff --git a/tests/test_DSU.cpp b/tests/test_DSU.cpp new file mode 100644 index 00000000..a993f20c --- /dev/null +++ b/tests/test_DSU.cpp @@ -0,0 +1,121 @@ +#include +#include "dsu.h" +#include + +TEST(DSUTest, Initialization) { + DSU dsu(5); + EXPECT_EQ(dsu.size(), 5); + EXPECT_EQ(dsu.sets_count(), 5); + + for (int i = 0; i < 5; ++i) { + EXPECT_EQ(dsu.find(i), i); + } +} + +TEST(DSUTest, BasicUnionFind) { + DSU dsu(5); + + dsu.unite(0, 1); + EXPECT_TRUE(dsu.same(0, 1)); + EXPECT_EQ(dsu.find(0), dsu.find(1)); + EXPECT_EQ(dsu.sets_count(), 4); + + dsu.unite(2, 3); + EXPECT_TRUE(dsu.same(2, 3)); + EXPECT_EQ(dsu.find(2), dsu.find(3)); + EXPECT_EQ(dsu.sets_count(), 3); + + EXPECT_FALSE(dsu.same(0, 2)); + EXPECT_FALSE(dsu.same(1, 3)); +} + +TEST(DSUTest, TransitiveUnion) { + DSU dsu(5); + + dsu.unite(0, 1); + dsu.unite(1, 2); + + EXPECT_TRUE(dsu.same(0, 2)); + EXPECT_EQ(dsu.find(0), dsu.find(1)); + EXPECT_EQ(dsu.find(1), dsu.find(2)); + EXPECT_EQ(dsu.find(0), dsu.find(2)); + EXPECT_EQ(dsu.sets_count(), 3); +} + +TEST(DSUTest, MultipleUnions) { + DSU dsu(6); + + dsu.unite(0, 1); + dsu.unite(1, 2); + dsu.unite(3, 4); + dsu.unite(4, 5); + + EXPECT_EQ(dsu.sets_count(), 2); + EXPECT_TRUE(dsu.same(0, 2)); + EXPECT_TRUE(dsu.same(3, 5)); + EXPECT_FALSE(dsu.same(0, 3)); + + dsu.unite(2, 3); + EXPECT_TRUE(dsu.same(0, 5)); + EXPECT_TRUE(dsu.same(1, 4)); + EXPECT_EQ(dsu.find(0), dsu.find(5)); + EXPECT_EQ(dsu.sets_count(), 1); +} + +TEST(DSUTest, SelfUnion) { + DSU dsu(3); + + dsu.unite(0, 0); + dsu.unite(1, 1); + + EXPECT_EQ(dsu.find(0), 0); + EXPECT_EQ(dsu.find(1), 1); + EXPECT_FALSE(dsu.same(0, 1)); + EXPECT_EQ(dsu.sets_count(), 3); +} + +TEST(DSUTest, PathCompression) { + DSU dsu(5); + + dsu.unite(0, 1); + dsu.unite(1, 2); + dsu.unite(2, 3); + dsu.unite(3, 4); + + int root = dsu.find(4); + + EXPECT_EQ(dsu.find(0), root); + EXPECT_EQ(dsu.find(1), root); + EXPECT_EQ(dsu.find(2), root); + EXPECT_EQ(dsu.find(3), root); + EXPECT_EQ(dsu.find(4), root); +} + +TEST(DSUTest, MoveSemantics) { + DSU dsu1(5); + dsu1.unite(0, 1); + dsu1.unite(2, 3); + + DSU dsu2 = std::move(dsu1); + + EXPECT_EQ(dsu2.size(), 5); + EXPECT_TRUE(dsu2.same(0, 1)); + EXPECT_TRUE(dsu2.same(2, 3)); + EXPECT_FALSE(dsu2.same(0, 2)); +} + +TEST(DSUTest, OutOfRange) { + DSU dsu(3); + + EXPECT_THROW(dsu.find(-1), std::out_of_range); + EXPECT_THROW(dsu.find(3), std::out_of_range); + EXPECT_THROW(dsu.find(100), std::out_of_range); + + EXPECT_THROW(dsu.unite(-1, 0), std::out_of_range); + EXPECT_THROW(dsu.unite(0, 5), std::out_of_range); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/tests/test_alg.cpp b/tests/test_alg.cpp new file mode 100644 index 00000000..a276aaca --- /dev/null +++ b/tests/test_alg.cpp @@ -0,0 +1,174 @@ +#include +#include "alg.h" +#include "dsu.h" + +TEST(BracketsTest, EmptyString) { + EXPECT_TRUE(check_brackets("")); +} + +TEST(BracketsTest, SinglePairs) { + EXPECT_TRUE(check_brackets("()")); + EXPECT_TRUE(check_brackets("[]")); + EXPECT_TRUE(check_brackets("{}")); +} + +TEST(BracketsTest, MultiplePairs) { + EXPECT_TRUE(check_brackets("()[]{}")); + EXPECT_TRUE(check_brackets("([])")); + EXPECT_TRUE(check_brackets("{()}")); + EXPECT_TRUE(check_brackets("[{}]")); +} + +TEST(BracketsTest, NestedBrackets) { + EXPECT_TRUE(check_brackets("({[]})")); + EXPECT_TRUE(check_brackets("((()))")); + EXPECT_TRUE(check_brackets("{{{}}}")); + EXPECT_TRUE(check_brackets("[[[]]]")); + EXPECT_TRUE(check_brackets("({[{}]})")); +} + +TEST(BracketsTest, ComplexCorrectSequences) { + EXPECT_TRUE(check_brackets("()()()()")); + EXPECT_TRUE(check_brackets("(([]{}))")); + EXPECT_TRUE(check_brackets("{()}[{}]")); + EXPECT_TRUE(check_brackets("([{()()}])")); + EXPECT_TRUE(check_brackets("((((()))))")); +} + +TEST(BracketsTest, WithOtherCharacters) { + EXPECT_TRUE(check_brackets("abc(def[ghi]jkl)mno")); + EXPECT_TRUE(check_brackets("a + (b * [c - d])")); + EXPECT_TRUE(check_brackets("if (x > 0) { y = [1, 2, 3]; }")); + EXPECT_TRUE(check_brackets("function(a, b, c) { return a + b; }")); + EXPECT_TRUE(check_brackets("array[[index]] = value;")); +} + +TEST(BracketsTest, SingleUnclosed) { + EXPECT_FALSE(check_brackets("(")); + EXPECT_FALSE(check_brackets("[")); + EXPECT_FALSE(check_brackets("{")); + EXPECT_FALSE(check_brackets(")")); + EXPECT_FALSE(check_brackets("]")); + EXPECT_FALSE(check_brackets("}")); +} + +TEST(BracketsTest, WrongOrder) { + EXPECT_FALSE(check_brackets(")(")); + EXPECT_FALSE(check_brackets("][")); + EXPECT_FALSE(check_brackets("}{")); + EXPECT_FALSE(check_brackets("([)]")); + EXPECT_FALSE(check_brackets("{[}]")); + EXPECT_FALSE(check_brackets("(]")); + EXPECT_FALSE(check_brackets("[)")); + EXPECT_FALSE(check_brackets("{]")); +} + +TEST(BracketsTest, MixedErrors) { + EXPECT_FALSE(check_brackets("())")); + EXPECT_FALSE(check_brackets("(()")); + EXPECT_FALSE(check_brackets("{[}")); + EXPECT_FALSE(check_brackets("{{}")); + EXPECT_FALSE(check_brackets("[[]")); + EXPECT_FALSE(check_brackets("())(")); + EXPECT_FALSE(check_brackets("{[}]")); +} + +TEST(BracketsTest, OnlyOpening) { + EXPECT_FALSE(check_brackets("((((")); + EXPECT_FALSE(check_brackets("[[[[")); + EXPECT_FALSE(check_brackets("{{{{")); + EXPECT_FALSE(check_brackets("(([[{{")); +} + +TEST(BracketsTest, OnlyClosing) { + EXPECT_FALSE(check_brackets("))))")); + EXPECT_FALSE(check_brackets("]]]]")); + EXPECT_FALSE(check_brackets("}}}}")); + EXPECT_FALSE(check_brackets("))]]}}")); +} + +TEST(BracketsTest, RealWorldExamples) { + EXPECT_TRUE(check_brackets("(1 + [2 * {3 - 4}])")); + EXPECT_TRUE(check_brackets("array = [1, 2, {key: value}]")); + EXPECT_FALSE(check_brackets("if (x > 0 { y = 1; }")); + EXPECT_FALSE(check_brackets("function(a, b] { return a + b; }")); + EXPECT_FALSE(check_brackets("items = [1, 2, 3));")); +} + +TEST(IslandCounter, EmptyGrid) { + int** grid = nullptr; + EXPECT_EQ(countIslands(grid, 0), 0); +} + +TEST(IslandCounter, TwoIslands) { + int grid[3][3] = { + {1, 0, 0}, + {0, 0, 0}, + {0, 0, 1} + }; + + int n = 3; + int** pgrid = new int* [n]; + for (int i = 0; i < n; i++) { + pgrid[i] = new int[n]; + for (int j = 0; j < n; j++) { + pgrid[i][j] = grid[i][j]; + } + } + + EXPECT_EQ(countIslands(pgrid, n), 2); + + for (int i = 0; i < n; i++) { + delete pgrid[i]; + } + delete[]pgrid; +} + +TEST(IslandCounter, ChessPattern) { + int grid[3][3] = { + {1, 0, 1}, + {0, 1, 0}, + {1, 0, 1} + }; + + int n = 3; + int** pgrid = new int* [n]; + for (int i = 0; i < n; i++) { + pgrid[i] = new int[n]; + for (int j = 0; j < n; j++) { + pgrid[i][j] = grid[i][j]; + } + } + + EXPECT_EQ(countIslands(pgrid, n), 5); + + for (int i = 0; i < n; i++) { + delete pgrid[i]; + } + delete[]pgrid; +} + +TEST(IslandCounter, ComplexShape) { + int grid[4][4] = { + {1, 1, 0, 0}, + {1, 0, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 1} + }; + + int n = 4; + int** pgrid = new int* [n]; + for (int i = 0; i < n; i++) { + pgrid[i] = new int[n]; + for (int j = 0; j < n; j++) { + pgrid[i][j] = grid[i][j]; + } + } + + EXPECT_EQ(countIslands(pgrid, n), 2); + + for (int i = 0; i < n; i++) { + delete pgrid[i]; + } + delete[]pgrid; +} \ No newline at end of file diff --git a/tests/test_list.cpp b/tests/test_list.cpp new file mode 100644 index 00000000..12a57076 --- /dev/null +++ b/tests/test_list.cpp @@ -0,0 +1,199 @@ +#include +#include "list.h" +#include +#include + +TEST(ListIteratorTest, ReadingWithIterators) { + List list; + + for (int i = 0; i < 4; i++) { + list.push_back(i * 3 + 1); + } + + std::vector result_postfix; + for (auto it = list.begin(); it != list.end(); it++) { + result_postfix.push_back(*it); + } + EXPECT_EQ(result_postfix, std::vector({ 1, 4, 7, 10 })); + + std::vector result_prefix; + for (auto it = list.begin(); it != list.end(); ++it) { + result_prefix.push_back(*it); + } + EXPECT_EQ(result_prefix, std::vector({ 1, 4, 7, 10 })); +} + + +TEST(ListIteratorTest, WritingWithIterators) { + List list; + + for (int i = 1; i <= 4; i++) { + list.push_back(i); + } + + for (auto it = list.begin(); it != list.end(); it++) { + *it = *it * 2; + } + + std::vector result; + for (auto it = list.begin(); it != list.end(); ++it) { + result.push_back(*it); + } + EXPECT_EQ(result, std::vector({ 2, 4, 6, 8 })); + + + for (auto it = list.begin(); it != list.end(); ++it) { + *it = 0; + } + + std::vector result_zero; + for (auto it = list.begin(); it != list.end(); it++) { + result_zero.push_back(*it); + } + EXPECT_EQ(result_zero, std::vector({ 0, 0, 0, 0 })); +} + + +TEST(ListIteratorTest, EmptyListOperations) { + List list; + + + EXPECT_EQ(list.begin(), list.end()); + + + auto it = list.end(); + it++; + ++it; + EXPECT_EQ(it, list.end()); + + + int counter_postfix = 0; + for (auto it = list.begin(); it != list.end(); it++) { + counter_postfix++; + } + EXPECT_EQ(counter_postfix, 0); + + int counter_prefix = 0; + for (auto it = list.begin(); it != list.end(); ++it) { + counter_prefix++; + } + EXPECT_EQ(counter_prefix, 0); +} + +TEST(ListIteratorTest, STLAlgorithmsCompatibility) { + List list; + + for (int i = 0; i < 10; i++) { + list.push_back(i * 3 + 1); + } + + + auto it_find = std::find(list.begin(), list.end(), 10); + EXPECT_NE(it_find, list.end()); + EXPECT_EQ(*it_find, 10); + + + int count_seven = std::count(list.begin(), list.end(), 7); + EXPECT_EQ(count_seven, 1); + + int count_nonexistent = std::count(list.begin(), list.end(), 100); + EXPECT_EQ(count_nonexistent, 0); + + + std::for_each(list.begin(), list.end(), [](int& n) { n += 1; }); + + + std::vector result; + for (auto it = list.begin(); it != list.end(); ++it) { + result.push_back(*it); + } + EXPECT_EQ(result, std::vector({ 2, 5, 8, 11, 14, 17, 20, 23, 26, 29 })); +} + +TEST(ListBasicTest, BasicOperations) { + List list; + + + EXPECT_TRUE(list.empty()); + EXPECT_EQ(list.get_size(), 0); + + + list.push_back(1); + EXPECT_FALSE(list.empty()); + EXPECT_EQ(list.get_size(), 1); + EXPECT_EQ(list.front(), 1); + EXPECT_EQ(list.back(), 1); + + list.push_front(0); + EXPECT_EQ(list.get_size(), 2); + EXPECT_EQ(list.front(), 0); + EXPECT_EQ(list.back(), 1); + + + list.push_back(2); + EXPECT_EQ(list.get_size(), 3); + EXPECT_EQ(list.front(), 0); + EXPECT_EQ(list.back(), 2); +} + +TEST(ListBasicTest, ElementRemoval) { + List list; + + + for (int i = 0; i < 5; i++) { + list.push_back(i); + } + + + list.pop_front(); + EXPECT_EQ(list.front(), 1); + EXPECT_EQ(list.get_size(), 4); + + + list.pop_back(); + EXPECT_EQ(list.back(), 3); + EXPECT_EQ(list.get_size(), 3); + + + list.clear(); + EXPECT_TRUE(list.empty()); + EXPECT_EQ(list.get_size(), 0); +} + + +TEST(ListBasicTest, CopyAndAssignment) { + List original; + for (int i = 0; i < 3; i++) { + original.push_back(i * 10); + } + + + List copy(original); + EXPECT_EQ(copy.get_size(), original.get_size()); + + std::vector original_vec, copy_vec; + for (auto it = original.begin(); it != original.end(); ++it) { + original_vec.push_back(*it); + } + for (auto it = copy.begin(); it != copy.end(); ++it) { + copy_vec.push_back(*it); + } + EXPECT_EQ(original_vec, copy_vec); + + + List assigned; + assigned = original; + EXPECT_EQ(assigned.get_size(), original.get_size()); + + std::vector assigned_vec; + for (auto it = assigned.begin(); it != assigned.end(); ++it) { + assigned_vec.push_back(*it); + } + EXPECT_EQ(original_vec, assigned_vec); +} + + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/tests/test_queueL.cpp b/tests/test_queueL.cpp new file mode 100644 index 00000000..70691ec3 --- /dev/null +++ b/tests/test_queueL.cpp @@ -0,0 +1,170 @@ +#include +#include "queueL.h" + +TEST(QueueTest, EmptyQueue) { + QueueList queue; + EXPECT_TRUE(queue.empty()); + EXPECT_EQ(queue.size(), 0); +} + +TEST(QueueTest, PushIncreasesSize) { + QueueList queue; + queue.push(1); + EXPECT_FALSE(queue.empty()); + EXPECT_EQ(queue.size(), 1); + + queue.push(2); + EXPECT_EQ(queue.size(), 2); +} + +TEST(QueueTest, FrontAndBack) { + QueueList queue; + queue.push(10); + EXPECT_EQ(queue.front(), 10); + EXPECT_EQ(queue.back(), 10); + + queue.push(20); + EXPECT_EQ(queue.front(), 10); + EXPECT_EQ(queue.back(), 20); + + queue.push(30); + EXPECT_EQ(queue.front(), 10); + EXPECT_EQ(queue.back(), 30); +} + +TEST(QueueTest, PopDecreasesSize) { + QueueList queue; + queue.push(1); + queue.push(2); + queue.push(3); + + queue.pop(); + EXPECT_EQ(queue.size(), 2); + EXPECT_EQ(queue.front(), 2); + EXPECT_EQ(queue.back(), 3); + + queue.pop(); + EXPECT_EQ(queue.size(), 1); + EXPECT_EQ(queue.front(), 3); + EXPECT_EQ(queue.back(), 3); + + queue.pop(); + EXPECT_TRUE(queue.empty()); +} + +TEST(QueueTest, FIFOOrder) { + QueueList queue; + + // Push 1, 2, 3 + for (int i = 1; i <= 3; ++i) { + queue.push(i); + } + + // Should dequeue 1, 2, 3 + EXPECT_EQ(queue.front(), 1); + queue.pop(); + + EXPECT_EQ(queue.front(), 2); + queue.pop(); + + EXPECT_EQ(queue.front(), 3); + queue.pop(); + + EXPECT_TRUE(queue.empty()); +} + +TEST(QueueTest, FrontThrowsWhenEmpty) { + QueueList queue; + EXPECT_THROW(queue.front(), std::out_of_range); +} + +TEST(QueueTest, BackThrowsWhenEmpty) { + QueueList queue; + EXPECT_THROW(queue.back(), std::out_of_range); +} + +TEST(QueueTest, PopThrowsWhenEmpty) { + QueueList queue; + EXPECT_THROW(queue.pop(), std::out_of_range); +} + +TEST(QueueTest, ClearEmptiesQueue) { + QueueList queue; + queue.push(1); + queue.push(2); + queue.push(3); + + EXPECT_EQ(queue.size(), 3); + queue.clear(); + EXPECT_TRUE(queue.empty()); + EXPECT_EQ(queue.size(), 0); +} + +TEST(QueueTest, StringQueue) { + QueueList queue; + queue.push("hello"); + queue.push("world"); + + EXPECT_EQ(queue.front(), "hello"); + EXPECT_EQ(queue.back(), "world"); + queue.pop(); + EXPECT_EQ(queue.front(), "world"); +} + +TEST(QueueTest, LargeNumberOfElements) { + QueueList queue; + const int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) { + queue.push(i); + } + + EXPECT_EQ(queue.size(), COUNT); + + for (int i = 0; i < COUNT; ++i) { + EXPECT_EQ(queue.front(), i); + queue.pop(); + } + + EXPECT_TRUE(queue.empty()); +} + +TEST(QueueTest, MixedOperations) { + QueueList queue; + + // 3 + queue.push(10); + queue.push(20); + queue.push(30); + + EXPECT_EQ(queue.front(), 10); + EXPECT_EQ(queue.back(), 30); + + // + queue.pop(); + EXPECT_EQ(queue.front(), 20); + EXPECT_EQ(queue.back(), 30); + + // + queue.push(40); + EXPECT_EQ(queue.front(), 20); + EXPECT_EQ(queue.back(), 40); + + // + queue.pop(); + queue.pop(); + queue.pop(); + EXPECT_TRUE(queue.empty()); +} + +TEST(QueueTest, SingleElementQueue) { + QueueList queue; + queue.push(42); + + EXPECT_EQ(queue.size(), 1); + EXPECT_EQ(queue.front(), 42); + EXPECT_EQ(queue.back(), 42); + + queue.pop(); + EXPECT_TRUE(queue.empty()); +} \ No newline at end of file diff --git a/tests/test_stack.cpp b/tests/test_stack.cpp new file mode 100644 index 00000000..97ba78a9 --- /dev/null +++ b/tests/test_stack.cpp @@ -0,0 +1,128 @@ +#include +#include "Stack.h" + +TEST(StackTest, DefaultConstructor) { + Stack stack; + EXPECT_EQ(stack.count(), 0); + EXPECT_EQ(stack.capacity(), 10); + EXPECT_TRUE(stack.is_empty()); + EXPECT_FALSE(stack.is_full()); +} + +TEST(StackTest, SizeConstructor) { + Stack stack(5); + EXPECT_EQ(stack.count(), 0); + EXPECT_EQ(stack.capacity(), 5); + EXPECT_TRUE(stack.is_empty()); + EXPECT_FALSE(stack.is_full()); +} + +TEST(StackTest, PushOperations) { + Stack stack(3); + + stack.push(10); + EXPECT_EQ(stack.count(), 1); + EXPECT_EQ(stack.top(), 10); + EXPECT_FALSE(stack.is_empty()); + EXPECT_FALSE(stack.is_full()); + + stack.push(20); + stack.push(30); + EXPECT_EQ(stack.count(), 3); + EXPECT_EQ(stack.top(), 30); + EXPECT_TRUE(stack.is_full()); +} + +TEST(StackTest, PopOperations) { + Stack stack(3); + stack.push(10); + stack.push(20); + stack.push(30); + + stack.pop(); + EXPECT_EQ(stack.count(), 2); + EXPECT_EQ(stack.top(), 20); + EXPECT_FALSE(stack.is_full()); + + stack.pop(); + EXPECT_EQ(stack.top(), 10); + + stack.pop(); + EXPECT_TRUE(stack.is_empty()); +} + +TEST(StackTest, ClearOperation) { + Stack stack(5); + stack.push(1); + stack.push(2); + stack.push(3); + + EXPECT_EQ(stack.count(), 3); + stack.clear(); + EXPECT_EQ(stack.count(), 0); + EXPECT_TRUE(stack.is_empty()); + EXPECT_EQ(stack.capacity(), 5); // +} + +TEST(StackTest, CopyConstructor) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + stack1.push(3); + + Stack stack2(stack1); + EXPECT_EQ(stack2.count(), 3); + EXPECT_EQ(stack2.capacity(), 3); + EXPECT_EQ(stack2.top(), 3); + + + stack2.pop(); + EXPECT_EQ(stack2.top(), 2); + EXPECT_EQ(stack1.top(), 3); // +} + + +TEST(StackTest, AssignmentOperator) { + Stack stack1(3); + stack1.push(10); + stack1.push(20); + + Stack stack2; + stack2 = stack1; + + EXPECT_EQ(stack2.count(), 2); + EXPECT_EQ(stack2.capacity(), 3); + EXPECT_EQ(stack2.top(), 20); + + stack2.pop(); + EXPECT_EQ(stack2.top(), 10); + EXPECT_EQ(stack1.top(), 20); // +} + + +TEST(StackTest, EmptyStackPopException) { + Stack stack; + + EXPECT_THROW({ + stack.pop(); + }, std::runtime_error); +} + +TEST(StackTest, EmptyStackTopException) { + Stack stack; + + EXPECT_THROW({ + stack.top(); + }, std::runtime_error); +} + +TEST(StackTest, FullStackPushException) { + Stack stack(2); + stack.push(1); + stack.push(2); + + EXPECT_THROW({ + stack.push(3); + }, std::runtime_error); +} + diff --git a/tests/test_stackL.cpp b/tests/test_stackL.cpp new file mode 100644 index 00000000..a76c81af --- /dev/null +++ b/tests/test_stackL.cpp @@ -0,0 +1,119 @@ +#include +#include "stackL.h" + +TEST(StackTest, EmptyStack) { + StackList stack; + EXPECT_TRUE(stack.empty()); + EXPECT_EQ(stack.size(), 0); +} + +TEST(StackTest, PushIncreasesSize) { + StackList stack; + stack.push(1); + EXPECT_FALSE(stack.empty()); + EXPECT_EQ(stack.size(), 1); + + stack.push(2); + EXPECT_EQ(stack.size(), 2); +} + +TEST(StackTest, TopReturnsLastPushed) { + StackList stack; + stack.push(10); + EXPECT_EQ(stack.top(), 10); + + stack.push(20); + EXPECT_EQ(stack.top(), 20); + + stack.push(30); + EXPECT_EQ(stack.top(), 30); +} + +TEST(StackTest, PopDecreasesSize) { + StackList stack; + stack.push(1); + stack.push(2); + stack.push(3); + + stack.pop(); + EXPECT_EQ(stack.size(), 2); + EXPECT_EQ(stack.top(), 2); + + stack.pop(); + EXPECT_EQ(stack.size(), 1); + EXPECT_EQ(stack.top(), 1); + + stack.pop(); + EXPECT_TRUE(stack.empty()); +} + +TEST(StackTest, LIFOOrder) { + StackList stack; + + // Push 1, 2, 3 + for (int i = 1; i <= 3; ++i) { + stack.push(i); + } + + // Should pop 3, 2, 1 + EXPECT_EQ(stack.top(), 3); + stack.pop(); + + EXPECT_EQ(stack.top(), 2); + stack.pop(); + + EXPECT_EQ(stack.top(), 1); + stack.pop(); + + EXPECT_TRUE(stack.empty()); +} + +TEST(StackTest, TopThrowsWhenEmpty) { + StackList stack; + EXPECT_THROW(stack.top(), std::out_of_range); +} + +TEST(StackTest, PopThrowsWhenEmpty) { + StackList stack; + EXPECT_THROW(stack.pop(), std::out_of_range); +} + +TEST(StackTest, ClearEmptiesStack) { + StackList stack; + stack.push(1); + stack.push(2); + stack.push(3); + + EXPECT_EQ(stack.size(), 3); + stack.clear(); + EXPECT_TRUE(stack.empty()); + EXPECT_EQ(stack.size(), 0); +} + +TEST(StackTest, StringStack) { + StackList stack; + stack.push("hello"); + stack.push("world"); + + EXPECT_EQ(stack.top(), "world"); + stack.pop(); + EXPECT_EQ(stack.top(), "hello"); +} + +TEST(StackTest, LargeNumberOfElements) { + StackList stack; + const int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) { + stack.push(i); + } + + EXPECT_EQ(stack.size(), COUNT); + + for (int i = COUNT - 1; i >= 0; --i) { + EXPECT_EQ(stack.top(), i); + stack.pop(); + } + + EXPECT_TRUE(stack.empty()); +} \ No newline at end of file