From e68f8d5a3ac0e068a675ea5ed1276baffbae6b28 Mon Sep 17 00:00:00 2001 From: luocai Date: Wed, 27 Dec 2023 10:29:16 +0800 Subject: [PATCH] Add unit test. --- CMakeLists.txt | 7 +- DataStructure/Array.h | 50 ++ DataStructure/ArrayList.h | 65 ++ DataStructure/BinarySearchTree.h | 240 +++++++ DataStructure/BinaryTree.h | 412 +++++++++++ DataStructure/CMakeLists.txt | 62 ++ DataStructure/CircularDoublyLinkedList.h | 141 ++++ DataStructure/CircularLinkedList.h | 109 +++ DataStructure/DoublyLinkedList.h | 207 ++++++ DataStructure/DynamicArray.h | 96 +++ DataStructure/DynamicArrayList.h | 81 +++ DataStructure/Exception.cpp | 67 ++ DataStructure/Exception.h | 107 +++ DataStructure/GeneralTree.h | 212 ++++++ DataStructure/Graph.h | 349 +++++++++ DataStructure/KylinSmartPointer.h | 36 + DataStructure/KylinString.cpp | 294 ++++++++ DataStructure/KylinString.h | 100 +++ DataStructure/LinkedList.h | 194 +++++ DataStructure/LinkedQueue.h | 48 ++ DataStructure/LinkedStack.h | 37 + DataStructure/LinuxList.h | 672 ++++++++++++++++++ DataStructure/List.h | 42 ++ DataStructure/ListGraph.h | 186 +++++ DataStructure/MatrixGraph.h | 145 ++++ DataStructure/Object.cpp | 16 + DataStructure/Object.h | 20 + DataStructure/Pointer.h | 38 + DataStructure/Queue.h | 20 + DataStructure/QueueToStack.h | 60 ++ DataStructure/RandomIterator.h | 25 + DataStructure/Readme.md | 30 + DataStructure/SharedPointer.h | 51 ++ DataStructure/Sort.h | 151 ++++ DataStructure/Stack.h | 18 + DataStructure/StackToQueue.h | 52 ++ DataStructure/StaticArray.h | 24 + DataStructure/StaticArrayList.h | 26 + DataStructure/StaticLinkedList.h | 67 ++ DataStructure/StaticQueue.h | 48 ++ DataStructure/StaticStack.h | 40 ++ DataStructure/Tree.h | 36 + LICENSE | 165 +++++ UnitTest/CMakeLists.txt | 25 + .../DataStructure/BinarySearchTreeTest.cpp | 69 ++ UnitTest/DataStructure/BinaryTreeTest.cpp | 273 +++++++ .../CircularDoublyLinkedListTest.cpp | 108 +++ .../DataStructure/CircularLinkedListTest.cpp | 103 +++ .../DataStructure/DoublyLinkedListTest.cpp | 101 +++ .../DataStructure/DynamicArrayListTest.cpp | 75 ++ UnitTest/DataStructure/DynamicArrayTest.cpp | 28 + UnitTest/DataStructure/GeneralTreeTest.cpp | 84 +++ UnitTest/DataStructure/LinkedListTest.cpp | 101 +++ UnitTest/DataStructure/LinkedQueueTest.cpp | 56 ++ UnitTest/DataStructure/LinkedStackTest.cpp | 39 + UnitTest/DataStructure/ListGraphTest.cpp | 229 ++++++ UnitTest/DataStructure/MatrixGraphTest.cpp | 73 ++ UnitTest/DataStructure/QueueToStackTest.cpp | 33 + UnitTest/DataStructure/SmartPointerTest.cpp | 64 ++ UnitTest/DataStructure/SortTest.cpp | 68 ++ UnitTest/DataStructure/StackToQueueTest.cpp | 29 + .../DataStructure/StaticArrayListTest.cpp | 66 ++ UnitTest/DataStructure/StaticArrayTest.cpp | 38 + .../DataStructure/StaticLinkedListTest.cpp | 80 +++ UnitTest/DataStructure/StaticQueueTest.cpp | 36 + UnitTest/DataStructure/StaticStackTest.cpp | 38 + UnitTest/DataStructure/StringTest.cpp | 74 ++ UnitTest/Universal/BoostLogTest.cpp | 7 + Universal/BoostLog.cpp | 6 +- Universal/BoostLog.h | 10 +- 70 files changed, 6752 insertions(+), 7 deletions(-) create mode 100644 DataStructure/Array.h create mode 100644 DataStructure/ArrayList.h create mode 100644 DataStructure/BinarySearchTree.h create mode 100644 DataStructure/BinaryTree.h create mode 100644 DataStructure/CMakeLists.txt create mode 100644 DataStructure/CircularDoublyLinkedList.h create mode 100644 DataStructure/CircularLinkedList.h create mode 100644 DataStructure/DoublyLinkedList.h create mode 100644 DataStructure/DynamicArray.h create mode 100644 DataStructure/DynamicArrayList.h create mode 100644 DataStructure/Exception.cpp create mode 100644 DataStructure/Exception.h create mode 100644 DataStructure/GeneralTree.h create mode 100644 DataStructure/Graph.h create mode 100644 DataStructure/KylinSmartPointer.h create mode 100644 DataStructure/KylinString.cpp create mode 100644 DataStructure/KylinString.h create mode 100644 DataStructure/LinkedList.h create mode 100644 DataStructure/LinkedQueue.h create mode 100644 DataStructure/LinkedStack.h create mode 100644 DataStructure/LinuxList.h create mode 100644 DataStructure/List.h create mode 100644 DataStructure/ListGraph.h create mode 100644 DataStructure/MatrixGraph.h create mode 100644 DataStructure/Object.cpp create mode 100644 DataStructure/Object.h create mode 100644 DataStructure/Pointer.h create mode 100644 DataStructure/Queue.h create mode 100644 DataStructure/QueueToStack.h create mode 100644 DataStructure/RandomIterator.h create mode 100644 DataStructure/Readme.md create mode 100644 DataStructure/SharedPointer.h create mode 100644 DataStructure/Sort.h create mode 100644 DataStructure/Stack.h create mode 100644 DataStructure/StackToQueue.h create mode 100644 DataStructure/StaticArray.h create mode 100644 DataStructure/StaticArrayList.h create mode 100644 DataStructure/StaticLinkedList.h create mode 100644 DataStructure/StaticQueue.h create mode 100644 DataStructure/StaticStack.h create mode 100644 DataStructure/Tree.h create mode 100644 LICENSE create mode 100644 UnitTest/DataStructure/BinarySearchTreeTest.cpp create mode 100644 UnitTest/DataStructure/BinaryTreeTest.cpp create mode 100644 UnitTest/DataStructure/CircularDoublyLinkedListTest.cpp create mode 100644 UnitTest/DataStructure/CircularLinkedListTest.cpp create mode 100644 UnitTest/DataStructure/DoublyLinkedListTest.cpp create mode 100644 UnitTest/DataStructure/DynamicArrayListTest.cpp create mode 100644 UnitTest/DataStructure/DynamicArrayTest.cpp create mode 100644 UnitTest/DataStructure/GeneralTreeTest.cpp create mode 100644 UnitTest/DataStructure/LinkedListTest.cpp create mode 100644 UnitTest/DataStructure/LinkedQueueTest.cpp create mode 100644 UnitTest/DataStructure/LinkedStackTest.cpp create mode 100644 UnitTest/DataStructure/ListGraphTest.cpp create mode 100644 UnitTest/DataStructure/MatrixGraphTest.cpp create mode 100644 UnitTest/DataStructure/QueueToStackTest.cpp create mode 100644 UnitTest/DataStructure/SmartPointerTest.cpp create mode 100644 UnitTest/DataStructure/SortTest.cpp create mode 100644 UnitTest/DataStructure/StackToQueueTest.cpp create mode 100644 UnitTest/DataStructure/StaticArrayListTest.cpp create mode 100644 UnitTest/DataStructure/StaticArrayTest.cpp create mode 100644 UnitTest/DataStructure/StaticLinkedListTest.cpp create mode 100644 UnitTest/DataStructure/StaticQueueTest.cpp create mode 100644 UnitTest/DataStructure/StaticStackTest.cpp create mode 100644 UnitTest/DataStructure/StringTest.cpp create mode 100644 UnitTest/Universal/BoostLogTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b8e970..349f378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,11 @@ project(Kylin) option(UNIT_TEST "do unit test" OFF) +find_package(Boost REQUIRED COMPONENTS log serialization) + set(OpenSSL_LIBRARY ssl crypto) +add_subdirectory(DataStructure) if(TARGET Boost::serialization) add_subdirectory(Encrypt) @@ -19,9 +22,7 @@ if(TARGET Qt${QT_VERSION_MAJOR}::Core) add_subdirectory(QtComponets) endif() -if(TARGET Boost::log) - add_subdirectory(Universal) -endif() +add_subdirectory(Universal) if(UNIT_TEST) add_subdirectory(UnitTest) diff --git a/DataStructure/Array.h b/DataStructure/Array.h new file mode 100644 index 0000000..9ce83b3 --- /dev/null +++ b/DataStructure/Array.h @@ -0,0 +1,50 @@ +#ifndef ARRAY_H +#define ARRAY_H + +#include "Exception.h" +#include "Object.h" +#include "RandomIterator.h" + +namespace Kylin { + +template +class Array : public Object { +public: + using Iterator = RandomIterator; + const T &at(size_t index) const { + if (index >= size()) { + THROW_EXCEPTION(IndexOutOfBoundsException, "Index out of bounds..."); + } + return m_array[index]; + } + + size_t indexOf(const T &value) const { + auto size_ = size(); + for (size_t i = 0; i < size_; i++) { + if (m_array[i] == value) return i; + } + return static_cast(-1); + } + + virtual size_t size() const noexcept = 0; + size_t length() const noexcept { return size(); } + + T &operator[](size_t index) { + if (index >= size()) { + THROW_EXCEPTION(IndexOutOfBoundsException, "Index out of bounds..."); + } + return m_array[index]; + } + + const T &operator[](size_t index) const { return const_cast(this)->operator[](index); } + + T *array() noexcept { return m_array; } + + Iterator begin() { return Iterator(m_array); } + Iterator end() { return Iterator(m_array + size()); } + +protected: + T *m_array = nullptr; +}; +} // namespace Kylin +#endif // ARRAY_H diff --git a/DataStructure/ArrayList.h b/DataStructure/ArrayList.h new file mode 100644 index 0000000..7e9161a --- /dev/null +++ b/DataStructure/ArrayList.h @@ -0,0 +1,65 @@ +#ifndef SEQLIST_H +#define SEQLIST_H + +#include "Exception.h" +#include "List.h" +#include "RandomIterator.h" + +namespace Kylin { + +template +class ArrayList : public List { +public: + static const size_t npos = static_cast(-1); + using Iterator = RandomIterator; + + void append(const T &value) override { return insert(m_size, value); } + + void insert(size_t index, const T &value) override { + if (m_size >= capacity()) THROW_EXCEPTION(InvalidParameterException, "There is no capacity."); + if (index > m_size) index = m_size; + for (int i = m_size - 1; i >= static_cast(index); i--) { + m_array[i + 1] = m_array[i]; + } + m_array[index] = value; + m_size++; + } + + T &last() override { + if (m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the container."); + return m_array[m_size - 1]; + } + + void removeAt(size_t index) override { + if (index >= m_size) THROW_EXCEPTION(IndexOutOfBoundsException, "The index is out of range."); + for (auto i = index + 1; i < m_size; i++) { + m_array[i - 1] = m_array[i]; + } + m_size--; + } + virtual void clear() noexcept { m_size = 0; } + virtual size_t size() const noexcept { return m_size; } + + size_t indexOf(const T &value, size_t from = 0) const override { + for (size_t i = from; i < m_size; i++) { + if (m_array[i] == value) return i; + } + return npos; + } + + virtual size_t capacity() const noexcept = 0; + + T &operator[](size_t index) { + if (index >= m_size) THROW_EXCEPTION(IndexOutOfBoundsException, "Index is out of bounds..."); + return m_array[index]; + } + + Iterator begin() { return Iterator(m_array); } + Iterator end() { return Iterator(m_array + m_size); } + +protected: + T *m_array = nullptr; + size_t m_size = 0; +}; +} // namespace Kylin +#endif // SEQLIST_H diff --git a/DataStructure/BinarySearchTree.h b/DataStructure/BinarySearchTree.h new file mode 100644 index 0000000..1ac5ff6 --- /dev/null +++ b/DataStructure/BinarySearchTree.h @@ -0,0 +1,240 @@ +#ifndef BINARYSEARCHTREE_H +#define BINARYSEARCHTREE_H + +#include "BinaryTree.h" + +namespace Kylin { + +/** + * @brief The BinarySearchTree class. 右子树永远比左子树要小 + * 1.若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值; + * 2.任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值; + * 3.任意节点的左、右子树也分别为二叉查找树。 + * 4.没有键值相等的节点(no duplicate nodes) + */ +template +class BinarySearchTree : public BinaryTree { +public: + using NodeT = BinaryTreeNode; + + class ConstIterator : public Object { + public: + ConstIterator() = default; + ConstIterator(NodeT *pos) : pos(pos) { + } + ConstIterator &operator++() { + if (pos == nullptr) return *this; + if (pos->right) { + pos = pos->right; + while (pos->left) pos = pos->left; + } else { + while ((pos->parent != nullptr) && (dynamic_cast(pos->parent)->right == pos)) + pos = dynamic_cast(pos->parent); + pos = dynamic_cast(pos->parent); + } + return *this; + } + + const T &operator*() { + return pos->value; + } + + bool operator!=(const ConstIterator &iter) { + return pos != iter.pos; + } + + const NodeT *pos = nullptr; + }; + + ConstIterator begin() const { + auto node = this->root(); + while (node->left != nullptr) node = node->left; + return ConstIterator(node); + } + + ConstIterator end() const { + return ConstIterator(); + } + + BinaryTreeNode *find(const T &value) const override { + return find(dynamic_cast *>(this->m_root), value); + } + + T maximum() { + auto node = maximumOfNode(dynamic_cast *>(this->m_root)); + if (node != nullptr) + return node->value; + else + return T(); + } + + T minimum() { + auto node = minimumOfNode(dynamic_cast *>(this->m_root)); + if (node != nullptr) + return node->value; + else + return T(); + } + + /** + * @brief Find the maxinum node which these node are smaller than arg node. + * @param node + * @return + */ + BinaryTreeNode *predecessor(BinaryTreeNode *node) { + if (node == nullptr) return node; + if (node->left != nullptr) return maximumOfNode(node->left); + auto parent = dynamic_cast *>(node->parent); + while ((parent != nullptr) && (parent->left == node)) { + node = parent; + parent = dynamic_cast *>(node->parent); + } + return parent; + } + + /** + * @brief successor Find the mininum node which these node are bigger than arg node. + * @param node + * @return + */ + BinaryTreeNode *successor(BinaryTreeNode *node) { + if (node == nullptr) return node; + if (node->right != nullptr) return minimumOfNode(node->right); + auto parent = dynamic_cast *>(node->parent); + if (node->right == nullptr && parent->left == node) return parent; + while ((parent != nullptr) && (parent->right == node)) { + node = parent; + parent = dynamic_cast *>(node->parent); + } + return parent; + } + + bool insert(const T &value) { + auto node = new NodeT(value); + if (node == nullptr) return false; + return insert(node); + } + + void remove(const T &value) { + BinaryTreeNode *node = find(value); + if (node == nullptr) return; + auto del = remove(node, dynamic_cast *>(this->m_root)); + if (del != nullptr) delete del; + } + +protected: + /** + * @brief find + * @param node the root of sub-tree + * @param value + * @return + */ + BinaryTreeNode *find(BinaryTreeNode *node, const T &value) const { + if ((node == nullptr) || (node->value == value)) return node; + if (value < node->value) + return find(node->left, value); + else if (value > node->value) + return find(node->right, value); + return nullptr; + } + + BinaryTreeNode *find1(BinaryTreeNode *node, const T &value) const { + while ((node != nullptr) && (node->value != value)) { + if (value > node->value) + node = node->right; + else if (value < node->value) + node = node->left; + } + return node; + } + + BinaryTreeNode *maximumOfNode(BinaryTreeNode *node) { + if (node == nullptr) return node; + while (node->right != nullptr) node = node->right; + return node; + } + + /** + * @brief minimumOfNode Find the maxinum node of the sub-tree which root is arg node. + * @param node + * @return + */ + BinaryTreeNode *minimumOfNode(BinaryTreeNode *node) { + if (node == nullptr) return node; + while (node->left != nullptr) node = node->left; + return node; + } + + /** + * @brief insert Insert node to the sub-tree which root is arg node. + */ + bool insert(NodeT *node) { + if (node == nullptr) return false; + auto n = reinterpret_cast(&(this->m_root)); + NodeT *parent = nullptr; + while (*n != nullptr) { + parent = *n; + n = (node->value <= (*n)->value) ? &((*n)->left) : &((*n)->right); + } + node->parent = parent; + *n = node; + return true; + } + + /** + * @brief remove + * @param node The tree which we want remove + * @param tree + * @return + */ + BinaryTreeNode *remove(BinaryTreeNode *node, BinaryTreeNode *tree) { + auto parent = dynamic_cast *>(node->parent); + if ((node->left == nullptr) || (node->right == nullptr)) { + } + + if ((node->left == nullptr) && (node->right == nullptr)) { // node没有左右子树 + if (parent->left == node) + parent->left = nullptr; + else + parent->right = nullptr; + } else if ((node->left != nullptr) && (node->right == nullptr)) { + if (parent->left == node) + parent->left = node->left; + else + parent->right = node->left; + } else if ((node->left == nullptr) && (node->right != nullptr)) { + if (parent->left == node) + parent->left = node->right; + else + parent->right = node->right; + } else { + auto n = successor(node); + n->left = node->left; + if (parent->left == node) + parent->left = node->right; + else + parent->right = node->right; + } + return node; + /* + BinaryTreeNode *del = nullptr; + BinaryTreeNode *n = nullptr; + if((node->left==nullptr)||(node->right==nullptr)) del = node; + else del = successor(node); + + if(del->left!=nullptr) n = del->left; + else n =del->right; + + if(n != nullptr) n->parent = del->parent; + + if(del->parent==nullptr) tree = n; + else if (del == del->parent->left) del->parent->left=n; + else del->parent->right=n; + if(del!=node) tree->value=del->value; + return del; +*/ + } +}; +} // namespace Kylin + +#endif // BINARYSEARCHTREE_H diff --git a/DataStructure/BinaryTree.h b/DataStructure/BinaryTree.h new file mode 100644 index 0000000..2e52e11 --- /dev/null +++ b/DataStructure/BinaryTree.h @@ -0,0 +1,412 @@ +#ifndef BINARYTREE_H +#define BINARYTREE_H + +#include "DynamicArray.h" +#include "LinkedQueue.h" +#include "SharedPointer.h" +#include "Tree.h" + +namespace Kylin { + +template +class BinaryTreeNode : public TreeNode { +public: + BinaryTreeNode(const T &value, BinaryTreeNode *parent = nullptr) : TreeNode(value, parent) {} + + BinaryTreeNode *left = nullptr; + BinaryTreeNode *right = nullptr; +}; + +template +class BinaryTree : public Tree { +public: + enum Pos { //子树节点位置 + Any, + Left, + Right + }; + + enum Traversal { //遍历顺序 + Preorder, //先序遍历 + Inorder, //中序遍历 + Postorder, //后续遍历 + Levelorder //层次遍历 + }; + + class Iterator { + public: + Iterator(BinaryTreeNode *pos) : m_pos(pos) {} + bool operator!=(const Iterator &other) { return (m_pos != other.m_pos); } + T &operator*() { return m_pos->value; } + Iterator &operator++() { + if (m_pos->left != nullptr) m_queue.enqueue(m_pos->left); + if (m_pos->right != nullptr) m_queue.enqueue(m_pos->right); + m_pos = m_queue.empty() ? nullptr : m_queue.dequeue(); + return *this; + } + + private: + BinaryTreeNode *m_pos = nullptr; + LinkedQueue *> m_queue; + }; + + BinaryTree() = default; + + BinaryTree(const BinaryTree &other) { this->m_root = clone(dynamic_cast *>(other.m_root)); } + + BinaryTree(BinaryTree &&other) { + this->m_root = other.m_root; + other.m_root = nullptr; + } + + ~BinaryTree() { clear(); } + + virtual BinaryTreeNode *root() const { return dynamic_cast *>(this->m_root); } + + int degree() const { return degree(dynamic_cast *>(this->m_root)); } + + int height() const { return height(dynamic_cast *>(this->m_root)); } + + int count() const { return count(dynamic_cast *>(this->m_root)); } + + void clear() { + free(dynamic_cast *>(this->m_root)); + this->m_root = nullptr; + } + + BinaryTree operator+(const BinaryTree &other) { + BinaryTree result; + result.m_root = + add(dynamic_cast *>(this->m_root), dynamic_cast *>(other.m_root)); + return result; + } + + BinaryTree &operator=(const BinaryTree &other) { + if (&other != this) { + clear(); + this->m_root = clone(other.m_root); + } + return *this; + } + + bool operator==(const BinaryTree &other) const { + return equal(dynamic_cast *>(this->m_root), + dynamic_cast *>(other.m_root)); + } + + bool operator!=(const BinaryTree &other) const { return !(*this == other); } + + DynamicArray traversal(Traversal order) { + LinkedQueue *> queue; + traversal(order, queue); + auto size = queue.size(); + DynamicArray result(size); + for (size_t i = 0; i < size; i++) { + result[i] = queue.dequeue()->value; + } + return result; + } + + bool insert(TreeNode *node) override { return insert(node, Any); } + + virtual bool insert(TreeNode *node, Pos pos) { + if (node == nullptr) return false; + if (this->m_root == nullptr) { + this->m_root = node; + node->parent = nullptr; + return true; + } + auto status = find(node->parent); + if (!status) return false; //没有找到父节点 + return insert(dynamic_cast *>(node), dynamic_cast *>(node->parent), pos); + } + + bool insert(const T &value, TreeNode *parent, Pos pos) { + bool ret = false; + auto n = new BinaryTreeNode(value); + if (n == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "There is no enough memory to insert an element."); + n->parent = parent; + ret = insert(n, pos); + if (!ret) { + delete n; + } + + return ret; + } + + virtual BinaryTreeNode *find(const T &value) const { + return find(dynamic_cast *>(this->m_root), value); + } + + bool find(TreeNode *node) const { + return find(dynamic_cast *>(this->m_root), dynamic_cast *>(node)); + } + + BinaryTree remove(const T &value) { + auto node = find(dynamic_cast *>(this->m_root), value); + if (node == nullptr) return BinaryTree(); + auto parent = dynamic_cast *>(node->parent); + if (parent->left == node) { + parent->left = nullptr; + } else if (parent->right == node) { + parent->right = nullptr; + } + node->parent = nullptr; + BinaryTree result; + result.m_root = node; + return result; + } + + BinaryTree remove(TreeNode *node) { + auto status = find(dynamic_cast *>(this->m_root), dynamic_cast *>(node)); + if (!status) return BinaryTree(); + auto parent = dynamic_cast *>(node->parent); + if (parent->left == node) { + parent->left = nullptr; + } else if (parent->right == node) { + parent->right = nullptr; + } + node->parent = nullptr; + BinaryTree result; + result.m_root = node; + return result; + } + + /** + * @brief 二叉树线索化,不可逆。 + */ + BinaryTreeNode *threaded(Traversal order) { + BinaryTreeNode *ret = nullptr; + LinkedQueue *> queue; + traversal(order, queue); + ret = connect(queue); + this->m_root = nullptr; + return ret; + } + + Iterator begin() { return Iterator(dynamic_cast *>(this->m_root)); } + Iterator end() { return Iterator(nullptr); } + +protected: + BinaryTreeNode *find(BinaryTreeNode *node, const T &value) const { + BinaryTreeNode *ret = nullptr; + if (node != nullptr) { + if (node->value == value) { + ret = node; + } else { + if (ret == nullptr) { + ret = find(node->left, value); + } + if (ret == nullptr) { + ret = find(node->right, value); + } + } + } + return ret; + } + + /** + * @brief 在以node为根结点的树中查找obj结点 + */ + bool find(BinaryTreeNode *node, BinaryTreeNode *obj) const { + if ((node == nullptr) || (obj == nullptr)) return false; + if (node == obj) return true; + bool ret = find(node->left, obj); + if (!ret) ret = find(node->right, obj); + return ret; + } + + /** + * @brief 将node插入到parent的pos节点 + */ + bool insert(BinaryTreeNode *node, BinaryTreeNode *parent, Pos pos) { + bool ret = false; + if (pos == Any) { + if (parent->left == nullptr) { + parent->left = node; + ret = true; + } else if (parent->right == nullptr) { + parent->right = node; + ret = true; + } + } else if (pos == Left) { + if (parent->left == nullptr) { + parent->left = node; + ret = true; + } + } else if (pos == Right) { + if (parent->right == nullptr) { + parent->right = node; + ret = true; + } + } + return ret; + } + + void free(BinaryTreeNode *node) { + if (node == nullptr) return; + if (node->left != nullptr) { + free(node->left); + } + if (node->right != nullptr) { + free(node->right); + } + delete node; + } + + int count(BinaryTreeNode *node) const { + if (node == nullptr) return 0; + int ret = 1; + ret += count(node->left); + ret += count(node->right); + return ret; + } + + size_t height(BinaryTreeNode *node) const { + if (node == nullptr) return 0; + size_t ret = 0; + ret = height(node->left); + auto rightHeight = height(node->right); + if (rightHeight > ret) ret = rightHeight; + return ret + 1; + } + + int degree(BinaryTreeNode *node) const { + if (node == nullptr) return 0; + int ret = 0; + + ret = (!!node->left) + (!!node->right); + BinaryTreeNode *nodes[] = {node->left, node->right}; + for (int i = 0; (i < 2) && (ret < 2); i++) { + int d = degree(nodes[i]); + if (d > ret) { + d = ret; + } + } + + return ret; + } + + BinaryTreeNode *clone(BinaryTreeNode *node) const { + if (node == nullptr) return nullptr; + auto ret = new BinaryTreeNode(node->value); + ret->left = clone(node->left); + if (ret->left != nullptr) { + ret->left->parent = ret; + } + ret->right = clone(node->right); + if (ret->right != nullptr) { + ret->right->parent = ret; + } + + return ret; + } + + bool equal(const BinaryTreeNode *lh, const BinaryTreeNode *rh) const { + + bool ret = false; + if (lh == rh) { + ret = true; + } else if (lh != nullptr && rh != nullptr) { + ret = (lh->value == rh->value) && equal(lh->left, rh->left) && equal(lh->right, rh->right); + } + return ret; + } + + BinaryTreeNode *add(BinaryTreeNode *lh, BinaryTreeNode *rh) const { + BinaryTreeNode *ret = nullptr; + if ((lh != nullptr) && (rh == nullptr)) { + ret = clone(lh); + } else if ((lh == nullptr) && (rh != nullptr)) { + ret = clone(rh); + } else if ((lh != nullptr) && (rh != nullptr)) { + ret = new BinaryTreeNode(lh->value + rh->value); + ret->left = add(lh->left, rh->left); + ret->right = add(lh->right, rh->right); + if (ret->left != nullptr) ret->left->parent = ret; + if (ret->right != nullptr) ret->right->parent = ret; + } + return ret; + } + + void traversal(Traversal order, LinkedQueue *> &queue) { + switch (order) { + case Preorder: + preOrderTraversal(dynamic_cast *>(this->m_root), queue); + break; + case Inorder: + inOrderTraversal(dynamic_cast *>(this->m_root), queue); + break; + case Postorder: + postOrderTraversal(dynamic_cast *>(this->m_root), queue); + break; + case Levelorder: + levelOrderTraversal(dynamic_cast *>(this->m_root), queue); + break; + default: + break; + } + } + + /** + * @brief 先序遍历 + */ + void preOrderTraversal(BinaryTreeNode *node, LinkedQueue *> &queue) { + if (node == nullptr) return; + queue.enqueue(node); + preOrderTraversal(node->left, queue); + preOrderTraversal(node->right, queue); + } + + /** + * @brief 中序遍历 + */ + void inOrderTraversal(BinaryTreeNode *node, LinkedQueue *> &queue) { + if (node == nullptr) return; + inOrderTraversal(node->left, queue); + queue.enqueue(node); + inOrderTraversal(node->right, queue); + } + + void postOrderTraversal(BinaryTreeNode *node, LinkedQueue *> &queue) { + if (node == nullptr) return; + postOrderTraversal(node->left, queue); + postOrderTraversal(node->right, queue); + queue.enqueue(node); + } + + /** + * @brief 层次遍历 + */ + void levelOrderTraversal(BinaryTreeNode *node, LinkedQueue *> &queue) { + if (node == nullptr) return; + LinkedQueue *> temp; + temp.enqueue(node); + while (temp.length() > 0) { + auto n = temp.dequeue(); + if (n->left != nullptr) temp.enqueue(n->left); + if (n->right != nullptr) temp.enqueue(n->right); + queue.enqueue(n); + } + } + + /** + * @brief 将queue的BinaryTreeNode连接成双向链表 + */ + BinaryTreeNode *connect(LinkedQueue *> &queue) { + if (queue.empty()) return nullptr; + auto slider = queue.dequeue(); + auto ret = slider; + slider->left = nullptr; + while (!queue.empty()) { + slider->right = queue.head(); + queue.head()->left = slider; + slider = queue.dequeue(); + } + slider->right = nullptr; + return ret; + } +}; + +} // namespace Kylin +#endif // BINARYTREE_H diff --git a/DataStructure/CMakeLists.txt b/DataStructure/CMakeLists.txt new file mode 100644 index 0000000..67907a1 --- /dev/null +++ b/DataStructure/CMakeLists.txt @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 3.27) + +project(DataStructure) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(Projects_ROOT E:/Projects) +set(Libraries_ROOT ${Projects_ROOT}/Libraries) + +set(BOOST_ROOT ${Libraries_ROOT}/boost_1_83_0_msvc2022_64bit) +set(Boost_INCLUDE_DIR ${BOOST_ROOT}/include/boost-1_83) +option(Boost_USE_STATIC_LIBS OFF) +add_compile_definitions( + BOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WIN10 +) + +add_library(DataStructure + Array.h + ArrayList.h + BinaryTree.h + BinarySearchTree.h + CircularDoublyLinkedList.h + CircularLinkedList.h + DoublyLinkedList.h + DynamicArray.h + DynamicArrayList.h + Exception.h + Exception.cpp + Graph.h + GeneralTree.h + KylinString.h + KylinString.cpp + Object.h + Object.cpp + List.h + LinkedList.h + LinkedQueue.h + LinkedStack.h + LinuxList.h + ListGraph.h + MatrixGraph.h + Pointer.h + Queue.h + QueueToStack.h + RandomIterator.h + KylinSmartPointer.h + SharedPointer.h + Sort.h + Stack.h + StaticStack.h + StaticQueue.h + StackToQueue.h + StaticArray.h + StaticArrayList.h + StaticLinkedList.h + Tree.h + ) + +target_include_directories(DataStructure + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/DataStructure/CircularDoublyLinkedList.h b/DataStructure/CircularDoublyLinkedList.h new file mode 100644 index 0000000..d2b6b4f --- /dev/null +++ b/DataStructure/CircularDoublyLinkedList.h @@ -0,0 +1,141 @@ +#ifndef DUALCIRCULARLIST_H +#define DUALCIRCULARLIST_H + +#include "DoublyLinkedList.h" + +namespace Kylin { +template +class CircularDoublyLinkedList : public DoublyLinkedList { + using Node = typename DoublyLinkedList::Node; + using Iterator = typename DoublyLinkedList::Iterator; + +public: + static constexpr size_t npos = static_cast(-1); + CircularDoublyLinkedList() { + this->m_header.next = reinterpret_cast(&(this->m_header)); + this->m_header.prev = reinterpret_cast(&(this->m_header)); + this->m_last = reinterpret_cast(&this->m_header); + } + + CircularDoublyLinkedList(std::initializer_list init) { + this->m_header.next = reinterpret_cast(&(this->m_header)); + this->m_header.prev = reinterpret_cast(&(this->m_header)); + this->m_last = reinterpret_cast(&this->m_header); + for (auto &value : init) append(value); + } + + CircularDoublyLinkedList(const CircularDoublyLinkedList &other) { + this->m_header.next = reinterpret_cast(&(this->m_header)); + this->m_header.prev = reinterpret_cast(&(this->m_header)); + this->m_last = reinterpret_cast(&this->m_header); + + auto sourceNode = other.m_header.next; + auto targetNode = reinterpret_cast(&this->m_header); + + for (size_t i = 0; i < other.m_size; i++) { + auto newNode = this->create(); + if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + newNode->value = sourceNode->value; + newNode->prev = targetNode; + newNode->next = targetNode->next; + + targetNode->next = newNode; + targetNode = newNode; + sourceNode = sourceNode->next; + this->m_size++; + this->m_last = targetNode; + } + } + + CircularDoublyLinkedList(CircularDoublyLinkedList &&other) { + this->m_size = other.m_size; + this->m_header = other.m_header; + this->m_last = other.m_last; + + other.m_size = 0; + other.m_header.next = nullptr; + other.m_last = reinterpret_cast(&other.m_header); + } + + void insert(size_t index, const T &value) override { + index = index % (this->m_size + 1); + if (index == this->m_size) return append(value); + auto node = this->create(); + if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No momery to insert new element..."); + + node->value = value; + + auto prev = position(index); + auto next = prev->next; + + node->next = next; + node->prev = prev; + + prev->next = node; + next->prev = node; + + this->m_size++; + } + + inline void append(const T &value) { + auto node = this->create(); + if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + node->value = value; + + node->prev = this->m_last; + node->next = this->m_last->next; + + this->m_last->next->prev = node; + this->m_last->next = node; + + this->m_last = node; + this->m_size++; + } + + void removeAt(size_t index) override { + index = mod(index); + auto prev = position(index); + auto toDel = prev->next; + auto next = toDel->next; + + prev->next = next; + next->prev = prev; + + this->destroy(toDel); + + this->m_size--; + } + + T &last() override { + if (this->m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the container."); + return this->m_header.prev->value; + } + + void clear() override { + while (this->m_size > 0) { + removeAt(0); + } + } + Iterator end() override { return Iterator(reinterpret_cast(&this->m_header)); } + + Iterator end() const override { return Iterator(reinterpret_cast(&this->m_header)); } + + ~CircularDoublyLinkedList() { clear(); } + + T &operator[](size_t index) override { + index = mod(index); + return position(index)->next->value; + } + +protected: + size_t mod(size_t index) const { return (this->m_size == 0) ? 0 : (index % this->m_size); } + Node *position(size_t index) const override { + auto node = reinterpret_cast(&(this->m_header)); + for (size_t i = 0; i < index; i++) { + node = node->next; + } + return node; + } +}; +} // namespace Kylin +#endif // DUALCIRCULARLIST_H diff --git a/DataStructure/CircularLinkedList.h b/DataStructure/CircularLinkedList.h new file mode 100644 index 0000000..01d7d08 --- /dev/null +++ b/DataStructure/CircularLinkedList.h @@ -0,0 +1,109 @@ +#ifndef CIRCULARLIST_H +#define CIRCULARLIST_H + +#include "LinkedList.h" + +namespace Kylin { +template +class CircularLinkedList : public LinkedList { + using Node = typename LinkedList::Node; + using Iterator = typename LinkedList::Iterator; + +public: + CircularLinkedList() = default; + CircularLinkedList(std::initializer_list init) { + this->m_header.next = reinterpret_cast(&this->m_header); + this->m_last = reinterpret_cast(&this->m_header); + + for (auto &value : init) { + this->append(value); + } + } + + CircularLinkedList(const CircularLinkedList &other) { + this->m_header.next = reinterpret_cast(&this->m_header); + this->m_last = reinterpret_cast(&this->m_header); + + auto sourceNode = other.m_header.next; + auto targetNode = reinterpret_cast(&this->m_header); + for (size_t i = 0; i < other.m_size; i++) { + auto newNode = this->create(); + if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + newNode->value = sourceNode->value; + targetNode->next = newNode; + targetNode = newNode; + sourceNode = sourceNode->next; + this->m_size++; + targetNode->next = this->m_header.next; + this->m_last = targetNode; + } + } + + CircularLinkedList(CircularLinkedList &&other) { + this->m_size = other.m_size; + this->m_header = other.m_header; + this->m_last = other.m_last; + + other.m_size = 0; + other.m_header.next = nullptr; + other.m_last = reinterpret_cast(&other.m_header); + } + + void insert(size_t index, const T &value) override { + index = index % (this->m_size + 1); + if (index == this->m_size) return this->append(value); + LinkedList::insert(index, value); + if (index == 0) lastToFirst(); + } + + void removeAt(size_t index) override { + if (this->size() <= 0) + THROW_EXCEPTION(IndexOutOfBoundsException, "There is no element in the container."); + index = mod(index); + if (index == 0) { + auto toDel = this->m_header.next; + this->m_header.next = toDel->next; + this->m_size--; + if (this->m_size == 0) { + this->m_header.next = nullptr; + } else { + lastToFirst(); + } + this->destroy(toDel); + } else { + LinkedList::removeAt(index); + } + } + + virtual void clear() { + while (this->m_size > 1) { + removeAt(1); + } + if (this->m_size == 1) { + auto del = this->m_header.next; + this->m_header.next = nullptr; + this->m_size = 0; + this->destroy(del); + } + } + + Iterator end() override { return Iterator(reinterpret_cast(&this->m_header)); } + + Iterator end() const override { return Iterator(reinterpret_cast(&this->m_header)); } + + T &operator[](size_t index) override { + if (this->m_size <= 0) + THROW_EXCEPTION(InvalidOperationException, "There is no element in the container..."); + index = mod(index); + return this->position(index)->next->value; + } + + virtual ~CircularLinkedList() { clear(); } + +protected: + size_t mod(size_t index) const { return (this->m_size == 0) ? 0 : (index % this->m_size); } + + void lastToFirst() { this->position(this->m_size - 1)->next->next = this->m_header.next; } +}; +} // namespace Kylin +#endif // CIRCULARLIST_H diff --git a/DataStructure/DoublyLinkedList.h b/DataStructure/DoublyLinkedList.h new file mode 100644 index 0000000..5a2a0ac --- /dev/null +++ b/DataStructure/DoublyLinkedList.h @@ -0,0 +1,207 @@ +#ifndef DUALLINKEDLIST_H +#define DUALLINKEDLIST_H + +#include "Exception.h" +#include "List.h" +#include + +namespace Kylin { +template +class DoublyLinkedList : public List { +protected: + struct Node : public Object { + Node *prev = nullptr; + Node *next = nullptr; + T value; + }; + struct : public Object { + Node *prev = nullptr; + Node *next = nullptr; + uint8_t reserved[sizeof(T)]; + } mutable m_header; + +public: + struct Iterator { + Iterator(Node *pos = nullptr) : m_pos(pos) {} + bool operator!=(const Iterator &other) { return m_pos != other.m_pos; } + T *operator->() const { return &m_pos->value; } + T &operator*() const { return m_pos->value; } + Iterator &operator++() { + m_pos = m_pos->next; + return *this; + } + Iterator operator++(int) { + auto old = *this; + m_pos = m_pos->next; + return old; + } + + Node *m_pos; + }; + + static constexpr size_t npos = static_cast(-1); + + DoublyLinkedList() { m_last = reinterpret_cast(&m_header); } + + DoublyLinkedList(std::initializer_list init) { + m_last = reinterpret_cast(&m_header); + for (auto &value : init) append(value); + } + + DoublyLinkedList(const DoublyLinkedList &other) { + auto sourceNode = other.m_header.next; + auto targetNode = reinterpret_cast(&m_header); + while (sourceNode != nullptr) { + auto newNode = create(); + if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + newNode->value = sourceNode->value; + targetNode->next = newNode; + newNode->prev = targetNode; + targetNode = newNode; + sourceNode = sourceNode->next; + m_size++; + targetNode->next = nullptr; + m_last = targetNode; + } + } + + DoublyLinkedList(DoublyLinkedList &&other) { + m_size = other.m_size; + m_header = other.m_header; + m_last = other.m_last; + + other.m_size = 0; + other.m_header.next = nullptr; + other.m_last = reinterpret_cast(&other.m_header); + } + + void swap(DoublyLinkedList &other) { + if (this == &other) return; + auto tempSize = other.m_size; + auto tempHeader = other.m_header; + auto tempLast = other.m_last; + + other.m_header = m_header; + other.m_size = m_size; + other.m_last = m_last; + + m_header = tempHeader; + m_size = tempSize; + m_last = tempLast; + } + + /** + * @brief O(n) + */ + void append(const T &value) override { + auto node = create(); + if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + node->value = value; + + m_last->next = node; + + node->prev = m_last; + m_last = node; + m_size++; + } + + /** + * @brief O(n) + */ + virtual void insert(size_t index, const T &value) { + if (index >= m_size) return append(value); + auto node = create(); + if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to create node..."); + node->value = value; + auto prev = position(index); + auto next = prev->next; + prev->next = node; + node->next = next; + + if (prev != reinterpret_cast(&m_header)) node->prev = prev; + if (next != nullptr) next->prev = node; + m_size++; + } + + T &last() override { + if (m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the container."); + return m_last->value; + } + + /** + * @brief O(n) + */ + void removeAt(size_t index) override { + if (index >= m_size) THROW_EXCEPTION(IndexOutOfBoundsException, "The index is out if range."); + auto prev = position(index); + auto toDel = prev->next; + auto next = toDel->next; + prev->next = next; + if (next != nullptr) next->prev = prev; + if (index == m_size - 1) { + m_last = prev; + } + m_size--; + destroy(toDel); + } + + /** + * @brief O(n) + */ + virtual void clear() { + while (m_header.next != nullptr) { + auto toDel = m_header.next; + m_header.next = toDel->next; + if (m_header.next != nullptr) m_header.next->prev = nullptr; + m_size--; + destroy(toDel); + } + } + + size_t size() const noexcept override { return m_size; } + + size_t indexOf(const T &value, size_t from = 0) const override { + auto node = position(from)->next; + for (size_t i = from; i < m_size; i++) { + if (node->value == value) return i; + node = node->next; + } + return npos; + } + + Iterator begin() { return Iterator(m_header.next); } + + Iterator begin() const { return Iterator(m_header.next); } + + virtual Iterator end() { return Iterator(); } + + virtual Iterator end() const { return Iterator(); } + + T &operator[](size_t index) override { + if (index >= size()) THROW_EXCEPTION(IndexOutOfBoundsException, "The index is out of range."); + return position(index)->next->value; + } + +protected: + Node *create() { return new Node(); } + + void destroy(Node *p) { delete p; } + + /** + * @brief position to index-1 ,O(n) + */ + virtual Node *position(size_t index) const { + auto ret = reinterpret_cast(&m_header); + for (size_t i = 0; i < index; i++) { + ret = ret->next; + } + return ret; + } + +protected: + size_t m_size = 0; + Node *m_last = nullptr; +}; +} // namespace Kylin + +#endif // DUALLINKEDLIST_H diff --git a/DataStructure/DynamicArray.h b/DataStructure/DynamicArray.h new file mode 100644 index 0000000..01084af --- /dev/null +++ b/DataStructure/DynamicArray.h @@ -0,0 +1,96 @@ +#ifndef DYNAMICARRAY_H +#define DYNAMICARRAY_H + +#include "Array.h" +#include + +namespace Kylin { + +template +class DynamicArray : public Array { +public: + DynamicArray() = default; + DynamicArray(size_t size) : m_size(size) { this->m_array = makeSpace(size); } + + DynamicArray(size_t size, const T &value) : m_size(size) { + auto array = makeSpace(size); + for (size_t i = 0; i < size; i++) array[i] = value; + this->m_array = array; + } + + DynamicArray(const DynamicArray &obj) : m_size(obj.m_size) { + this->m_array = makeSpace(m_size); + copy(obj.m_array, obj.m_size, this->m_array, m_size); + } + + DynamicArray(std::initializer_list init) { + this->m_size = init.size(); + this->m_array = makeSpace(m_size); + auto begin = init.begin(); + for (size_t i = 0; i < m_size; i++) { + this->m_array[i] = *begin; + ++begin; + } + } + + DynamicArray(DynamicArray &&obj) { + m_size = obj.m_size; + this->m_array = obj.m_array; + obj.m_size = 0; + obj.m_array = nullptr; + } + + DynamicArray &operator=(DynamicArray &&obj) { + if (this->m_array != nullptr) delete[] this->m_array; + m_size = obj.m_size; + this->m_array = obj.m_array; + obj.m_size = static_cast(-1); + obj.m_array = nullptr; + return *this; + } + + ~DynamicArray() { + if (this->m_array != nullptr) delete[] this->m_array; + } + + DynamicArray &operator=(const DynamicArray &obj) { + if (this == &obj) return *this; + auto array = makeSpace(obj.m_size); + copy(obj.m_array, obj.m_size, array, obj.m_size); + update(array, obj.m_size); + return *this; + } + + void resize(size_t size) { + T *array = makeSpace(size); + copy(this->m_array, m_size, array, size); + update(array, size); + } + + virtual size_t size() const noexcept { return m_size; } + +protected: + T *makeSpace(size_t size) { + T *ret = new T[size]; + if (ret == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to alloc..."); + return ret; + } + + void copy(T *src, size_t old, T *dest, size_t now) { + auto length = now < old ? now : old; + for (size_t i = 0; i < length; i++) { + dest[i] = src[i]; + } + } + + void update(T *new_array, size_t new_size) { + delete this->m_array; + this->m_array = new_array; + this->m_size = new_size; + } + +private: + size_t m_size = 0; +}; +} // namespace Kylin +#endif // DYNAMICARRAY_H diff --git a/DataStructure/DynamicArrayList.h b/DataStructure/DynamicArrayList.h new file mode 100644 index 0000000..e65e93d --- /dev/null +++ b/DataStructure/DynamicArrayList.h @@ -0,0 +1,81 @@ +#ifndef DYNAMICSEQLIST_H +#define DYNAMICSEQLIST_H + +#include "ArrayList.h" +#include + +namespace Kylin { +/** + *Capacity不足时,直接扩容1.5倍 + */ +template +class DynamicArrayList : public ArrayList { +public: + DynamicArrayList() = default; + DynamicArrayList(size_t capacity) : m_capacity(capacity) { + this->m_array = new T[m_capacity]; + if (this->m_array == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to allocate."); + } + + DynamicArrayList(std::initializer_list init) { + this->m_array = new T[init.size()]; + if (this->m_array == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to allocate."); + m_capacity = init.size(); + for (auto &value : init) { + this->m_array[this->m_size++] = value; + } + } + + DynamicArrayList(DynamicArrayList &&other) { + m_capacity = other.m_capacity; + this->m_array = other.m_array; + this->m_size = other.m_size; + other.m_capacity = 0; + other.m_size = 0; + other.m_array = nullptr; + } + + DynamicArrayList(const DynamicArrayList &other) { + this->m_array = new T[other.m_capacity]; + if (this->m_array == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to allocate."); + m_capacity = other.m_capacity; + for (size_t i = 0; i < other.m_size; i++) { + this->m_array[i] = other.m_array[i]; + this->m_size++; + } + } + + ~DynamicArrayList() { + if (this->m_array != nullptr) delete[] this->m_array; + } + + void insert(size_t index, const T &value) override { + if (this->m_size >= m_capacity) { + resize(m_capacity * 2); + } + ArrayList::insert(index, value); + } + + virtual size_t capacity() const noexcept { return m_capacity; } + + void resize(size_t capacity) { + if (capacity == m_capacity) return; + T *array = new T[capacity]; + if (array == nullptr) { + THROW_EXCEPTION(NoEnoughMemoryException, "No memory to allocate."); + } + size_t size = this->m_size < capacity ? this->m_size : capacity; + for (size_t i = 0; i < size; i++) { + array[i] = this->m_array[i]; + } + this->m_size = size; + m_capacity = capacity; + delete[] this->m_array; + this->m_array = array; + } + +private: + size_t m_capacity = 0; +}; +} // namespace Kylin +#endif // DYNAMICSEQLIST_H diff --git a/DataStructure/Exception.cpp b/DataStructure/Exception.cpp new file mode 100644 index 0000000..06a04f5 --- /dev/null +++ b/DataStructure/Exception.cpp @@ -0,0 +1,67 @@ +#include "Exception.h" +#include +#include +#include + +namespace Kylin { + +Exception::Exception(const char *message) { init(nullptr, 0, message); } + +Exception::Exception(const char *file, int line) { init(file, line, nullptr); } + +Exception::Exception(const char *file, int line, const char *message) { init(file, line, message); } + +Exception::Exception(const Exception &e) { + m_message = strdup(e.m_message); + m_location = strdup(e.m_location); +} + +Exception &Exception::operator=(const Exception &e) { + if (this != &e) { + free(m_message); + free(m_location); + m_message = strdup(e.m_message); + m_location = strdup(e.m_location); + } + return *this; +} + +const char *Exception::message() const { return m_message; } + +const char *Exception::location() const { return m_location; } + +void Exception::init(const char *file, int line, const char *message) { + m_message = message ? strdup(message) : nullptr; + if (file == nullptr) return; + char l[16] = {0}; +#ifdef WIN32 + itoa(line, l, 10); +#else + sprintf(l, "%d", line); +#endif + + m_location = static_cast(malloc(strlen(file) + strlen(l) + 2)); + if (m_location == nullptr) return; + strcpy(m_location, file); + strcat(m_location, ":"); + strcat(m_location, l); +} + +Exception::~Exception() { + free(m_message); + free(m_location); +} + +ArithmeticException::~ArithmeticException() {} + +NullPointerException::~NullPointerException() {} + +IndexOutOfBoundsException::~IndexOutOfBoundsException() {} + +NoEnoughMemoryException::~NoEnoughMemoryException() {} + +InvalidParameterException::~InvalidParameterException() {} + +InvalidOperationException::~InvalidOperationException() {} + +} // namespace Kylin diff --git a/DataStructure/Exception.h b/DataStructure/Exception.h new file mode 100644 index 0000000..5205939 --- /dev/null +++ b/DataStructure/Exception.h @@ -0,0 +1,107 @@ +#ifndef EXCEPTION_H +#define EXCEPTION_H + +#include "Object.h" + +namespace Kylin { + +#define THROW_EXCEPTION(e, m) (throw e(__FILE__, __LINE__, m)) + +class Exception : public Object { +public: + Exception(const char *message); + Exception(const char *file, int line); + Exception(const char *file, int line, const char *message); + Exception(const Exception &e); + Exception &operator=(const Exception &e); + virtual const char *message() const; + virtual const char *location() const; + virtual ~Exception() = 0; + +protected: + void init(const char *file, int line, const char *message); + char *m_message = nullptr; + char *m_location = nullptr; +}; + +class ArithmeticException : public Exception { +public: + ArithmeticException(const char *message) : Exception(message) {} + ArithmeticException(const char *file, int line) : Exception(file, line) {} + ArithmeticException(const char *file, int line, const char *message) : Exception(file, line, message) {} + ArithmeticException(const ArithmeticException &e) : Exception(e) {} + ArithmeticException &operator=(const ArithmeticException &e) { + Exception::operator=(e); + return *this; + } + ~ArithmeticException(); +}; + +class NullPointerException : public Exception { +public: + NullPointerException(const char *message) : Exception(message) {} + NullPointerException(const char *file, int line) : Exception(file, line) {} + NullPointerException(const char *file, int line, const char *message) : Exception(file, line, message) {} + NullPointerException(const NullPointerException &e) : Exception(e) {} + NullPointerException &operator=(const NullPointerException &e) { + Exception::operator=(e); + return *this; + } + ~NullPointerException(); +}; + +class IndexOutOfBoundsException : public Exception { +public: + IndexOutOfBoundsException(const char *message) : Exception(message) {} + IndexOutOfBoundsException(const char *file, int line) : Exception(file, line) {} + IndexOutOfBoundsException(const char *file, int line, const char *message) : Exception(file, line, message) {} + IndexOutOfBoundsException(const IndexOutOfBoundsException &e) : Exception(e) {} + IndexOutOfBoundsException &operator=(const IndexOutOfBoundsException &e) { + Exception::operator=(e); + return *this; + } + ~IndexOutOfBoundsException(); +}; + +class NoEnoughMemoryException : public Exception { +public: + NoEnoughMemoryException(const char *message) : Exception(message) {} + NoEnoughMemoryException(const char *file, int line) : Exception(file, line) {} + NoEnoughMemoryException(const char *file, int line, const char *message) : Exception(file, line, message) {} + NoEnoughMemoryException(const NoEnoughMemoryException &e) : Exception(e) {} + NoEnoughMemoryException &operator=(const NoEnoughMemoryException &e) { + Exception::operator=(e); + return *this; + } + ~NoEnoughMemoryException(); +}; + +class InvalidParameterException : public Exception { +public: + InvalidParameterException(const char *message) : Exception(message) {} + InvalidParameterException(const char *file, int line) : Exception(file, line) {} + InvalidParameterException(const char *file, int line, const char *message) : Exception(file, line, message) {} + InvalidParameterException(const InvalidParameterException &e) : Exception(e) {} + InvalidParameterException &operator=(const InvalidParameterException &e) { + Exception::operator=(e); + return *this; + } + ~InvalidParameterException(); +}; + +class InvalidOperationException : public Exception { +public: + InvalidOperationException(const char *message) : Exception(message) {} + InvalidOperationException(const char *file, int line) : Exception(file, line) {} + InvalidOperationException(const char *file, int line, const char *message) : Exception(file, line, message) {} + InvalidOperationException(const InvalidOperationException &e) : Exception(e) {} + InvalidOperationException &operator=(const InvalidOperationException &e) { + Exception::operator=(e); + return *this; + } + ~InvalidOperationException(); +}; + +} // namespace Kylin + +#endif // EXCEPTION_H diff --git a/DataStructure/GeneralTree.h b/DataStructure/GeneralTree.h new file mode 100644 index 0000000..2e40f9a --- /dev/null +++ b/DataStructure/GeneralTree.h @@ -0,0 +1,212 @@ +#ifndef GENERALTREE_H +#define GENERALTREE_H + +#include "LinkedList.h" +#include "LinkedQueue.h" +#include "Tree.h" + +namespace Kylin { + +template +class GeneralTreeNode : public TreeNode { +public: + GeneralTreeNode(const T &value, TreeNode *parent = nullptr) : TreeNode(value, parent) {} + LinkedList *> children; +}; + +template +class GeneralTree : public Tree { +public: + class Iterator { + public: + Iterator(GeneralTreeNode *pos) : m_pos(pos) {} + bool operator!=(const Iterator &other) { return (m_pos != other.m_pos); } + T &operator*() { return m_pos->value; } + Iterator &operator++() { + auto &children = m_pos->children; + for (auto &child : children) { + m_queue.enqueue(child); + } + m_pos = m_queue.empty() ? nullptr : m_queue.dequeue(); + return *this; + } + + private: + GeneralTreeNode *m_pos = nullptr; + LinkedQueue *> m_queue; + }; + + GeneralTree() = default; + + GeneralTree(GeneralTree &&other) { + this->m_root = other.m_root; + other.m_root = nullptr; + } + + ~GeneralTree() { clear(); } + + bool insert(TreeNode *node) { + bool ret = false; + auto n = dynamic_cast *>(node); + if (n == nullptr) THROW_EXCEPTION(InvalidParameterException, "the node must is GeneralTreeNode."); + if (this->m_root == nullptr) { + this->m_root = node; + node->parent = nullptr; + ret = true; + } else { + if (!find(n->parent)) return false; + auto parent = dynamic_cast *>(node->parent); + parent->children.append(n); + ret = true; + } + return ret; + } + + /** + * @brief 插入成功返回TreeNode的地址,否则nullptr + */ + GeneralTreeNode *insert(const T &value, TreeNode *parent) { + auto ret = new GeneralTreeNode(value, parent); + if (ret == nullptr) + THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to insert an element."); + bool status = insert(ret); + if (!status) { + delete ret; + ret = nullptr; + } + return ret; + } + + GeneralTree remove(const T &value) { + auto node = find(value); + return node == nullptr ? GeneralTree() : remove(node); + } + + GeneralTree remove(const GeneralTreeNode *node) { + if (node == nullptr) return GeneralTree(); + GeneralTree tree; + auto n = const_cast *>(node); + if (n == this->m_root) { + this->m_root = nullptr; + tree.m_root = n; + return tree; + } + auto parent = dynamic_cast *>(n->parent); + auto &children = parent->children; + auto pos = children.indexOf(n); + if (pos == LinkedList::npos) return GeneralTree(); + children.removeAt(pos); + tree.m_root = n; + return tree; + } + + GeneralTreeNode *find(const T &value) const { + return find(dynamic_cast *>(this->m_root), value); + } + + bool find(TreeNode *node) const override { + return find(dynamic_cast *>(this->m_root), + dynamic_cast *>(node)); + } + + GeneralTreeNode *root() const { return dynamic_cast *>(this->m_root); } + + int count() const { return count(dynamic_cast *>(this->m_root)); } + + int degree() const { return degree(dynamic_cast *>(this->m_root)); } + + int height() const { return height(dynamic_cast *>(this->m_root)); } + + void clear() { + destroy(dynamic_cast *>(this->m_root)); + this->m_root = nullptr; + } + + Iterator begin() { return Iterator(dynamic_cast *>(this->m_root)); } + Iterator end() { return Iterator(nullptr); } + + GeneralTree &operator=(GeneralTree &&other) { + if (&other != this) { + auto root(this->m_root); + this->m_root = other.m_root; + other.m_root = root; + } + return *this; + } + +protected: + /** + * @brief 以Node为根节点的GeneralTree,查找的值为value的GeneralTreeNode + */ + GeneralTreeNode *find(const GeneralTreeNode *node, const T &value) const { + if (node == nullptr) return nullptr; + if (node->value == value) return const_cast *>(node); + GeneralTreeNode *ret = nullptr; + auto &children = const_cast *> &>(node->children); + for (auto &child : children) { + ret = find(child, value); + if (ret != nullptr) break; + } + return ret; + } + + /** + * @brief find 在node子树中查找obj + */ + GeneralTreeNode *find(const GeneralTreeNode *node, const GeneralTreeNode *obj) const { + if (node == nullptr) return nullptr; + if (node == obj) return const_cast *>(node); + GeneralTreeNode *result = nullptr; + auto &children = const_cast *> &>(node->children); + for (auto &child : children) { + result = find(child, obj); + if (result != nullptr) break; + } + return result; + } + + void destroy(GeneralTreeNode *node) { + if (node == nullptr) return; + auto &children = node->children; + for (auto &child : children) { + destroy(child); + } + delete node; + } + + int count(const GeneralTreeNode *node) const { + if (node == nullptr) return 0; + int ret = 1; + auto &children = const_cast *> &>(node->children); + for (auto &child : children) { + ret += count(child); + } + return ret; + } + + int height(const GeneralTreeNode *node) const { + if (node == nullptr) return 0; + int ret = 0; + auto &children = const_cast *> &>(node->children); + for (auto &child : children) { + int h = height(child); + if (ret < h) ret = h; + } + return ret + 1; + } + + int degree(const GeneralTreeNode *node) const { + if (node == nullptr) return 0; + int ret = node->children.length(); + auto &children = const_cast *> &>(node->children); + for (auto &child : children) { + int d = degree(child); + if (d > ret) ret = d; + } + + return ret; + } +}; + +} // namespace Kylin +#endif // GENERALTREE_H diff --git a/DataStructure/Graph.h b/DataStructure/Graph.h new file mode 100644 index 0000000..79de26b --- /dev/null +++ b/DataStructure/Graph.h @@ -0,0 +1,349 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include "Array.h" +#include "DynamicArray.h" +#include "DynamicArrayList.h" +#include "LinkedQueue.h" +#include "LinkedStack.h" +#include "Object.h" +#include "SharedPointer.h" +#include "Sort.h" +#include + +namespace Kylin { + +/*ListGraph用*/ +template +struct Edge : public Object { + static constexpr size_t npos = static_cast(-1); + Edge(size_t begin = npos, size_t end = npos) : begin(begin), end(end) {} + + Edge(size_t begin, size_t end, const EdgeType &value) : begin(begin), end(end), value(value) {} + + bool operator==(const Edge &obj) { return (begin == obj.begin) && (end == obj.end); } + + bool operator!=(const Edge &obj) { return !(*this == obj); } + + bool operator<(const Edge &obj) { return (value < obj.value); } + + bool operator>(const Edge &obj) { return (value > obj.value); } + + bool operator<=(const Edge &obj) { return !(*this > obj); } + size_t begin; + size_t end; + EdgeType value; +}; + +template +class Graph : public Object { +public: + virtual VertexType vertex(size_t index) const = 0; + virtual bool setVertex(size_t index, const VertexType &value) = 0; + virtual DynamicArray adjacent(size_t index) const = 0; + virtual std::optional edge(size_t start, size_t end) const = 0; + virtual bool setEdge(size_t start, size_t end, const EdgeType &value) = 0; + virtual bool removeEdge(size_t start, size_t end) = 0; + virtual size_t vertexCount() const = 0; + virtual size_t edgeCount() const = 0; + virtual size_t outDegree(size_t index) const = 0; + virtual size_t inDegree(size_t index) const = 0; + + size_t degree(size_t index) const { return outDegree(index) + inDegree(index); } + + bool asUndirected() { + bool ret = true; + auto vertexes = vertexCount(); + for (size_t i = 0; (i < vertexes) && ret; i++) { + for (size_t j = 0; (j < vertexes) && ret; j++) { + auto edge1 = edge(i, j); + if (edge1) { + auto edge2 = edge(j, i); + ret = ret && edge2 && (edge1 == edge2); + } + } + } + return ret; + } + + DynamicArrayList> prim(const EdgeType &LIMIT) { + if (!asUndirected()) THROW_EXCEPTION(InvalidOperationException, "Graph must be undirectedgraph."); + auto vertexSize = vertexCount(); + DynamicArrayList> result(vertexSize - 1); + DynamicArray edges(vertexSize); + DynamicArray costs(vertexSize, LIMIT); + DynamicArray mark(vertexSize, false); + + //以start为起点,查找邻边,获取权值。如果有最小的,则更新cost数组和edges邻边记录表。 + auto updateCosts = [this, &mark, &costs, &edges](size_t start) { + auto adjacent = this->adjacent(start); + for (size_t j = 0; j < adjacent.size(); j++) { + auto end = adjacent[j]; + auto newCost = *edge(start, end); + if (mark[end] == false && costs[end] > newCost) { + costs[end] = newCost; + edges[end] = start; + } + } + }; + + updateCosts(0); + mark[0] = true; + + for (size_t i = 1; i < vertexSize; i++) { + + //选取最小边,记录其终点 + auto miniCost = LIMIT; + size_t end = static_cast(-1); + for (size_t j = 0; j < vertexSize; j++) { + if (mark[j] == false && costs[j] < miniCost) { + miniCost = costs[j]; + end = j; + } + } + if (end == static_cast(-1)) break; + + result.append(Edge(edges[end], end, miniCost)); + mark[end] = true; + + updateCosts(end); //已上次的end为start,更新cost数组 + } + if (result.size() != (vertexSize - 1)) + THROW_EXCEPTION(InvalidOperationException, "No enough edge for prim operation..."); + return result; + } + + DynamicArrayList> kruskal() { + DynamicArrayList> result(1); + auto edges = getUndirectedEdges(); + if (edges.empty()) return result; + auto vertexSize = vertexCount(); + + DynamicArray set(vertexSize); + for (size_t i = 0; i < vertexSize; i++) { + set[i] = i; + } + auto find = [&set](size_t index) { + while (index != set[index]) { + index = set[index]; + } + return index; + }; + + Sort::quick(&edges[0], edges.size()); + for (size_t i = 0; i < edges.size(); i++) { + auto beginRoot = find(edges[i].begin); + auto endRoot = find(edges[i].end); + if (beginRoot != endRoot) { + result.append(edges[i]); + set[endRoot] = beginRoot; + } + if (result.size() >= (vertexSize - 1)) break; + } + if (result.size() != vertexSize - 1) + THROW_EXCEPTION(InvalidOperationException, "No enough edge for kruskal operation..."); + return result; + } + + DynamicArray breadthFirstSearch(size_t index) { + if (index < 0 || index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); + LinkedQueue queue; + LinkedQueue ret; + DynamicArray visited(vertexCount(), false); + queue.enqueue(index); + while (queue.length() > 0) { + auto v = queue.dequeue(); + if (visited[v]) continue; + auto aj = adjacent(v); + for (size_t j = 0; j < aj.length(); j++) { + queue.enqueue(aj.at(j)); + } + ret.enqueue(v); + visited[v] = true; + } + return toArray(ret); + } + + DynamicArray depthFirstSearch(size_t index) { + if (index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); + LinkedStack stack; + LinkedQueue ret; + DynamicArray visited(vertexCount(), false); + stack.push(index); + while (stack.size() > 0) { + auto v = stack.top(); + stack.pop(); + if (visited[v]) continue; + auto aj = adjacent(v); + for (auto value : aj) { + stack.push(value); + } + ret.enqueue(v); + visited[v] = true; + } + return toArray(ret); + } + + DynamicArray dijkstra(size_t begin, size_t end, const EdgeType &LIMIT) { + size_t vertexSize = vertexCount(); + if (begin >= vertexSize || end >= vertexSize) + THROW_EXCEPTION(InvalidParameterException, "Parameter begin or end is invalid."); + LinkedStack result; + DynamicArray distance(vertexSize, LIMIT); + DynamicArray mark(vertexSize, false); + DynamicArray path(vertexSize, static_cast(-1)); + + for (size_t i = 0; i < vertexSize; i++) { + auto edge = this->edge(begin, i); + if (edge) { + distance[i] = *edge; + path[i] = begin; + } + } + mark[begin] = true; + + for (size_t i = 1; i < vertexSize; i++) { + EdgeType mini = LIMIT; + size_t endIndex = static_cast(-1); + for (size_t j = 0; j < vertexSize; j++) { + if (mark[j] == false && distance[j] < mini) { + endIndex = j; + mini = distance[j]; + } + } + if (endIndex == static_cast(-1)) break; + mark[endIndex] = true; + for (size_t j = 0; j < vertexSize; j++) { + if (mark[j] == false) { + auto edge = this->edge(endIndex, j); + if (edge && (*edge + distance[endIndex] < distance[j])) { + distance[j] = *edge + distance[endIndex]; + path[j] = endIndex; + } + } + } + } + + result.push(end); + size_t pos = end; + while (path[pos] != begin) { + pos = path[pos]; + result.push(pos); + } + result.push(begin); + return toArray(result); + } + + DynamicArray floyd(int x, int y, const EdgeType &LIMIT) { + LinkedQueue ret; + if ((x >= 0) && (x < vertexCount()) && (y >= 0) && (y < vertexCount())) { + DynamicArray> dist(vertexCount()); + DynamicArray> path(vertexCount()); + for (int k = 0; k < vertexCount(); k++) { + dist[k].resize(vertexCount()); + path[k].resize(vertexCount()); + } + for (int i = 0; i < vertexCount(); i++) { // A -1 + for (int j = 0; j < vertexCount(); j++) { + auto edge = this->edge(i, j); + dist[i][j] = edge ? *edge : LIMIT; + path[i][j] = edge ? j : -1; + } + } + + for (int k = 0; k < vertexCount(); k++) { + for (int i = 0; i < vertexCount(); i++) { + for (int j = 0; j < vertexCount(); j++) { + if (dist[i][k] + dist[k][j] < dist[i][j]) { + dist[i][j] = dist[i][k] + dist[k][j]; + path[i][j] = path[i][k]; + } + } + } + } + while ((x != -1) && (x != y)) { + ret.enqueue(x); + x = path[x][y]; + } + + if (x != -1) { + ret.enqueue(x); + } + if (ret.size() < 2) { + THROW_EXCEPTION(InvalidOperationException, "There is no path form x to y."); + } + + } else { + THROW_EXCEPTION(InvalidParameterException, "Index is invalid ."); + } + return toArray(ret); + } + + /* DFS递归版实现 + static void DFS(Graph *graph,size_t index,Kylin::Array &visited,LinkedQueue &ret) { + if((index>=0)&&(indexvertexCount())) { + ret.add(index); + visited[index] = true; + auto aj = graph->adjacent(index); + for(size_t i=0;ilength();i++){ + if(visited[aj->at(i)]) continue; + DFS(graph,aj->at(i),visited,ret); + } + } else { + THROW_EXCEPTION(Kylin::InvalidParameterException,"Index is invalid..."); + } + } + + + SharedPointer> DFS(size_t index) { + Kylin::DynamicArray visited(vertexCount(),false); + LinkedQueue ret; + DFS(this,index,visited,ret); + return toArray(ret); + } + */ +protected: + template + static DynamicArray toArray(LinkedQueue &queue) { + DynamicArray ret(queue.length()); + for (size_t i = 0; i < ret.length(); i++) { + ret[i] = queue.dequeue(); + } + return ret; + } + + template + static DynamicArray toArray(LinkedStack &stack) { + DynamicArray ret(stack.size()); + for (size_t i = 0; i < ret.size(); i++) { + ret[i] = stack.pop(); + } + return ret; + } + + DynamicArrayList> getUndirectedEdges() { + DynamicArrayList> result(1); + if (!asUndirected()) return result; + auto vertexes = vertexCount(); + for (size_t i = 0; i < vertexes; i++) { + for (size_t j = i + 1; j < vertexes; j++) { + auto e = edge(i, j); + if (e) { + result.append(Edge(i, j, *e)); + } + } + } + + return result; + } + + size_t findTerminalVertex(Array &p, size_t v) { + while (p[v] != static_cast(-1)) { + v = p[v]; + } + return v; + } +}; // namespace Kylin + +} // namespace Kylin +#endif // GRAPH_H diff --git a/DataStructure/KylinSmartPointer.h b/DataStructure/KylinSmartPointer.h new file mode 100644 index 0000000..c1eea1b --- /dev/null +++ b/DataStructure/KylinSmartPointer.h @@ -0,0 +1,36 @@ +#ifndef DATA_SMARTPOINTER_H +#define DATA_SMARTPOINTER_H + +#include "Pointer.h" + +namespace Kylin { + +template +class SmartPointer : public Pointer { +public: + SmartPointer(T *p) { this->m_pointer = p; } + SmartPointer(SmartPointer &&other) { + this->m_pointer = other.m_pointer; + other.m_pointer = nullptr; + } + SmartPointer(const SmartPointer &) = delete; + + ~SmartPointer() { + if (this->m_pointer != nullptr) { + delete this->m_pointer; + } + } + + SmartPointer &operator=(SmartPointer &&other) { + if (this != &other) { + if (this->m_pointer != nullptr) delete this->m_pointer; + this->m_pointer = other.m_pointer; + other.m_pointer = nullptr; + } + return *this; + } +}; + +} // namespace Kylin + +#endif // SMARTPOINTER_H diff --git a/DataStructure/KylinString.cpp b/DataStructure/KylinString.cpp new file mode 100644 index 0000000..f628e41 --- /dev/null +++ b/DataStructure/KylinString.cpp @@ -0,0 +1,294 @@ +#include "KylinString.h" +#include "Exception.h" +#include + +namespace Kylin { + +String::String() { init(nullptr); } + +String::String(const char c) { + char str[] = {c, '\0'}; + init(str); +} + +String::String(const char *str) { init(str); } + +String::String(const String &str) { init(str.m_str); } + +String::String(String &&other) { + m_str = other.m_str; + m_length = other.m_length; + other.init(nullptr); +} + +String::~String() { delete m_str; } + +String &String::operator=(const String &str) { return operator=(str.m_str); } + +String &String::operator=(const char *str) { + if (m_str != str) { + auto s = strdup(str); + if (s == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "Thers is no memory to aclloc string..."); + free(m_str); + m_str = s; + m_length = strlen(m_str); + } + return *this; +} + +bool String::startWith(const char *s) const { + if (s == nullptr) return false; + auto len = strlen(s); + if (len > m_length) return false; + for (size_t i = 0; i < len; i++) { + if (s[i] != m_str[i]) return false; + } + return true; +} + +bool String::startWith(const String &s) const { return startWith(s.m_str); } + +bool String::endOf(const char *s) const { + if (s == nullptr) return false; + auto len = strlen(s); + if (len > m_length) return false; + size_t begin = m_length - len; + for (size_t i = 0; i < len; i++) { + if (s[i] != m_str[begin + i]) return false; + } + return true; +} + +bool String::endOf(const String &s) const { return endOf(s.str()); } + +String &String::insert(size_t index, const char *s) { + if (s != nullptr) { + if (index > m_length) THROW_EXCEPTION(InvalidParameterException, "Index i is a invalid parameter..."); + auto size = strlen(s); + auto str = reinterpret_cast(malloc(m_length + size + 1)); + if (str == nullptr) + THROW_EXCEPTION(NoEnoughMemoryException, "There is no memory to create string..."); + strncpy(str, m_str, index); + strcpy(str + index, s); + strcpy(str + index + size, m_str + index); + str[size + m_length] = '\0'; + free(m_str); + m_str = str; + m_length = strlen(m_str); + } + return *this; +} + +String &String::insert(size_t index, const String &s) { return insert(index, s.m_str); } + +String &String::trim() { + size_t begin = 0, end = m_length - 1; + while (m_str[begin] == ' ') begin++; + while (m_str[end] == ' ') end--; + if (begin == 0) { + m_str[end + 1] = '\0'; + m_length = end + 1; + } else { + size_t i = 0; + for (; begin <= end; i++, begin++) { + m_str[i] = m_str[begin]; + } + m_str[i] = '\0'; + m_length = i; + } + return *this; +} + +int String::indexOf(const char *s) const { return kmp(m_str, s); } + +int String::indexOf(const String &s) const { return indexOf(s.m_str); } + +String &String::remove(size_t index, size_t length) { + if (index >= m_length) THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); + size_t begin = index + length; + for (; begin < m_length; begin++, index++) { + m_str[index] = m_str[begin]; + } + m_str[index] = '\0'; + m_length = index; + return *this; +} + +String &String::remove(const char *s) { + auto pos = indexOf(s); + if (pos >= 0) remove(static_cast(pos), strlen(s)); + return *this; +} + +String &String::remove(const String &s) { return remove(s.m_str); } + +String &String::replace(const char *t, const char *s) { + auto pos = indexOf(t); + if (pos > 0) { + remove(t); + insert(static_cast(pos), s); + } + return *this; +} + +String &String::replace(const String &t, const char *s) { return replace(t.m_str, s); } + +String &String::replace(const char *t, const String &s) { return replace(t, s.m_str); } + +String &String::replace(const String &t, const String &s) { return replace(t.m_str, s.m_str); } + +String String::substr(size_t index, size_t length) const { + if (index >= m_length) THROW_EXCEPTION(InvalidParameterException, "Parameter index is invalid..."); + if ((index + length) >= m_length) length = m_length - index; + + auto str = reinterpret_cast(malloc(length + 1)); + strncpy(str, m_str + index, length); + str[length] = '\0'; + String ret(str); + free(str); + return ret; +} + +char &String::operator[](size_t index) { + if (index >= m_length) THROW_EXCEPTION(IndexOutOfBoundsException, "Index out of bounds..."); + return m_str[index]; +} + +char String::operator[](size_t index) const { return const_cast(*this)[index]; } + +bool String::operator<(const char *str) const { return (strcmp(m_str, str) < 0); } + +bool String::operator<(const String &str) const { return operator<(str.m_str); } + +bool String::operator>=(const char *str) const { return !(*this < str); } + +bool String::operator>=(const String &str) const { return !(*this < str); } + +bool String::operator>(const char *str) const { return (strcmp(m_str, str) > 0); } + +bool String::operator>(const String &str) const { return operator>(str.m_str); } + +bool String::operator<=(const char *str) const { return !(*this > str); } + +bool String::operator<=(const String &str) const { return !(*this > str); } + +bool String::operator==(const char *str) const { + if (str == nullptr && m_str == nullptr) return true; + if (str == nullptr || m_str == nullptr) return false; + return (strcmp(m_str, str) == 0); +} + +bool String::operator==(const String &str) const { return operator==(str.m_str); } + +bool String::operator!=(const char *str) const { return !(*this == str); } + +bool String::operator!=(const String &str) const { return !(*this == str); } + +String &String::operator+=(const char *str) { + if (str != nullptr) { + auto size = strlen(str); + auto s = reinterpret_cast(malloc(m_length + size + 1)); + if (s == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "Thers is no memory to alloc string..."); + strcpy(s, m_str); + strcat(s, str); + s[m_length + size] = '\0'; + free(m_str); + m_str = s; + m_length = strlen(m_str); + } + return *this; +} + +String &String::operator+=(const String &str) { return operator+=(str.m_str); } + +String String::operator+(const char *str) const { + String ret(*this); + ret += str; + return ret; +} + +String String::operator+(const String &str) const { return operator+(str.m_str); } + +String &String::operator-=(const char *str) { return remove(str); } + +String &String::operator-=(const String &str) { return remove(str); } + +String String::operator-(const char *str) const { + String ret(*this); + return (ret -= str); +} + +String String::operator-(const String &str) const { + String ret(*this); + return (ret -= str); +} + +void String::init(const char *str) { + m_str = strdup(str ? str : ""); + if (m_str == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "Thers is no memory to aclloc string..."); + m_length = strlen(m_str); +} + +size_t *String::make_pmt(const char *p) { + auto len = strlen(p); + auto *ret = reinterpret_cast(malloc(sizeof(size_t) * len)); + if (ret != nullptr) { + size_t ll = 0; + ret[0] = 0; + for (size_t i = 1; i < len; i++) { + while ((p[ll] != p[i]) && (ll > 0)) { + ll = ret[ll - 1]; + } + if (p[ll] == p[i]) ll++; + ret[i] = ll; + } + } + return ret; +} + +int String::kmp(const char *s, const char *p) { + int ret = -1; + auto sl = strlen(s); + auto pl = strlen(p); + auto pmt = make_pmt(p); + if ((pmt != nullptr) && (0 < pl) && (pl <= sl)) { + for (size_t i = 0, j = 0; i < sl; i++) { + while ((j > 0) && (s[i] != p[j])) { + j = pmt[j - 1]; + } + if (s[i] == p[j]) j++; + if (j == pl) ret = static_cast(i + 1 - pl); + } + } + free(pmt); + return ret; +} + +int String::sunday(const char *str, const char *pattern) { + static char shift[256]; + size_t patternLength = strlen(pattern); + size_t strLength = strlen(str); + if (patternLength > strLength) return -1; + for (size_t i = 0; i < 256; i++) { + shift[i] = patternLength + 1; + } + for (size_t i = 0; i < patternLength; i++) { + shift[static_cast(pattern[i])] = patternLength - i; + } + size_t pos = 0; + while (pos <= strLength - patternLength) { + size_t index = 0; + while (index < patternLength) { + if (str[pos + index] == pattern[index]) { + index++; + if (index == patternLength) return pos; + } else { + pos += shift[static_cast(str[pos + patternLength])]; + break; + } + } + } + return -1; +} + +} // namespace Kylin diff --git a/DataStructure/KylinString.h b/DataStructure/KylinString.h new file mode 100644 index 0000000..36762c9 --- /dev/null +++ b/DataStructure/KylinString.h @@ -0,0 +1,100 @@ +#ifndef KYLINSTRING_H +#define KYLINSTRING_H + +#include "Object.h" +#include + +namespace Kylin { + +class String : public Object { +public: + String(); + String(const char c); + String(const char *str); + String(const String &str); + String(String &&other); + ~String(); + String &operator=(const String &str); + String &operator=(const char *str); + inline const char *str() const { return m_str; } + inline size_t length() const { return m_length; } + + bool startWith(const char *s) const; + bool startWith(const String &s) const; + bool endOf(const char *s) const; + bool endOf(const String &s) const; + String &insert(size_t index, const char *s); + String &insert(size_t index, const String &s); + String &trim(); + + int indexOf(const char *s) const; + int indexOf(const String &s) const; + + String &remove(size_t index, size_t length); + String &remove(const char *s); + String &remove(const String &s); + + String &replace(const char *t, const char *s); + String &replace(const String &t, const char *s); + String &replace(const char *t, const String &s); + String &replace(const String &t, const String &s); + + String substr(size_t index, size_t length) const; + + char &operator[](size_t index); + char operator[](size_t index) const; + + bool operator<(const char *str) const; + bool operator<(const String &str) const; + + bool operator>=(const char *str) const; + bool operator>=(const String &str) const; + + bool operator>(const char *str) const; + bool operator>(const String &str) const; + + bool operator<=(const char *str) const; + bool operator<=(const String &str) const; + + bool operator==(const char *str) const; + bool operator==(const String &str) const; + + bool operator!=(const char *str) const; + bool operator!=(const String &str) const; + + String &operator+=(const char *str); + String &operator+=(const String &str); + + String operator+(const char *str) const; + String operator+(const String &str) const; + + String &operator-=(const char *str); + String &operator-=(const String &str); + + String operator-(const char *str) const; + String operator-(const String &str) const; + +protected: + void init(const char *str); + static size_t *make_pmt(const char *p); + static int kmp(const char *s, const char *p); + +public: + static int sunday(const char *str, const char *pattern); + +private: + char *m_str = nullptr; + size_t m_length = 0; +}; +} // namespace Kylin + +#include +namespace std { +inline std::ostream &operator<<(std::ostream &stream, const Kylin::String &string) { + stream << string.str(); + return stream; +} + +} // namespace std + +#endif // KYLINSTRING_H diff --git a/DataStructure/LinkedList.h b/DataStructure/LinkedList.h new file mode 100644 index 0000000..23233f8 --- /dev/null +++ b/DataStructure/LinkedList.h @@ -0,0 +1,194 @@ +#ifndef LINKEDLIST_H +#define LINKEDLIST_H + +#include "Exception.h" +#include "List.h" +#include + +namespace Kylin { + +template +class LinkedList : public List { +protected: + struct Node : public Object { + T value; + Node *next = nullptr; + }; + + struct : public Object { + char reserved[sizeof(T)]; + Node *next = nullptr; + } mutable m_header; + +public: + class Iterator : public Object { + friend class LinkedList; + + public: + Iterator() = default; + Iterator(Node *pos) : pos(pos) {} + Iterator &operator++() { + pos = pos->next; + return *this; + } + Iterator operator++(int) { + auto old = *this; + pos = pos->next; + return old; + } + + Iterator operator+=(size_t size) { + for (size_t i = 0; (i < size) && (pos != nullptr); i++) { + pos = &(*pos)->next; + } + } + T *operator->() const { return &pos->value; } + T &operator*() const { return pos->value; } + bool operator!=(const Iterator &iter) { return pos != iter.pos; } + bool operator==(const Iterator &iter) { return pos == iter.pos; } + + private: + Node *pos = nullptr; + }; + + LinkedList() { m_last = reinterpret_cast(&m_header); } + + LinkedList(std::initializer_list init) { + m_last = reinterpret_cast(&m_header); + for (auto &value : init) { + append(value); + } + } + + LinkedList(const LinkedList &other) { + auto sourceNode = other.m_header.next; + auto targetNode = reinterpret_cast(&m_header); + while (sourceNode != nullptr) { + auto newNode = create(); + if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + newNode->value = sourceNode->value; + targetNode->next = newNode; + targetNode = newNode; + sourceNode = sourceNode->next; + m_size++; + targetNode->next = nullptr; + m_last = targetNode; + } + } + + LinkedList(LinkedList &&other) { + m_size = other.m_size; + m_header = other.m_header; + m_last = other.m_last; + + other.m_size = 0; + other.m_header.next = nullptr; + other.m_last = reinterpret_cast(&other.m_header); + } + + ~LinkedList() { clear(); } + + void swap(LinkedList &other) { + if (this == &other) return; + auto tempSize = other.m_size; + auto tempHeader = other.m_header; + auto tempLast = other.m_last; + + other.m_header = m_header; + other.m_size = m_size; + other.m_last = m_last; + + m_header = tempHeader; + m_size = tempSize; + m_last = tempLast; + } + + virtual void append(const T &value) { + auto node = create(); + if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + node->value = value; + + node->next = m_last->next; // for circular linked list + m_last->next = node; + m_last = node; + m_size++; + } + + virtual void insert(size_t index, const T &value) { + if (index >= m_size) return append(value); + Node *prev = position(index); + Node *node = create(); + if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ..."); + node->value = value; + node->next = prev->next; + prev->next = node; + m_size += 1; + } + + T &last() override { + if (m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the container."); + return m_last->value; + } + + void removeAt(size_t index) override { + if (index >= m_size) THROW_EXCEPTION(IndexOutOfBoundsException, "The index is out of range."); + Node *prev = position(index); + Node *toDel = prev->next; + prev->next = toDel->next; + if (index == m_size - 1) m_last = prev; + m_size--; + destroy(toDel); + } + + virtual void clear() { + while (m_header.next != nullptr) { + Node *del = m_header.next; + m_header.next = del->next; + m_size--; + destroy(del); + } + m_last = reinterpret_cast(&m_header); + } + + virtual size_t size() const noexcept { return m_size; } + + virtual size_t indexOf(const T &value, size_t from = 0) const final { + auto node = position(from)->next; + for (size_t i = from; i < m_size; i++, node = node->next) { + if (node->value == value) return i; + } + return LinkedList::npos; + } + + Iterator begin() { return Iterator(m_header.next); } + + Iterator begin() const { return Iterator(m_header.next); } + + virtual Iterator end() { return Iterator(); } + + virtual Iterator end() const { return Iterator(); } + + T &operator[](size_t index) override { + if (index >= m_size) THROW_EXCEPTION(IndexOutOfBoundsException, "Index out of bounds..."); + return position(index)->next->value; + } + +protected: + Node *position(size_t index) const { + Node *ret = reinterpret_cast(&m_header); + for (size_t i = 0; i < index; i++) { + ret = ret->next; + } + return ret; + } + + virtual Node *create() { return new Node(); } + + virtual void destroy(Node *p) { delete p; } + + size_t m_size = 0; + + Node *m_last = nullptr; +}; +} // namespace Kylin +#endif // LINKEDLIST_H diff --git a/DataStructure/LinkedQueue.h b/DataStructure/LinkedQueue.h new file mode 100644 index 0000000..04d8ae1 --- /dev/null +++ b/DataStructure/LinkedQueue.h @@ -0,0 +1,48 @@ +#ifndef LINKEDQUEUE_H +#define LINKEDQUEUE_H + +#include "Exception.h" +#include "LinkedList.h" +#include "Queue.h" +#include "utility" +#include + +namespace Kylin { +template +class LinkedQueue : public Queue { +public: + LinkedQueue() = default; + LinkedQueue(std::initializer_list init) { + for (auto &value : init) enqueue(value); + } + + LinkedQueue(LinkedQueue &&other) : m_list(std::move(other.m_list)) {} + + void swap(LinkedQueue &other) { m_list.swap(other.m_list); } + + void enqueue(const T &value) final { m_list.append(value); } + + T dequeue() final { + auto value = m_list.at(0); + m_list.removeAt(0); + return value; + } + + T &head() final { return m_list[0]; } + + void clear() final { m_list.clear(); } + + size_t size() const noexcept override { return m_list.size(); } + + LinkedQueue &operator=(LinkedQueue &&other) { + if (&other != this) { + swap(other); + } + return *this; + } + +private: + LinkedList m_list; +}; +} // namespace Kylin +#endif // LINKEDQUEUE_H diff --git a/DataStructure/LinkedStack.h b/DataStructure/LinkedStack.h new file mode 100644 index 0000000..fd010c4 --- /dev/null +++ b/DataStructure/LinkedStack.h @@ -0,0 +1,37 @@ +#ifndef LINKEDSTACK_H +#define LINKEDSTACK_H + +#include "LinkedList.h" +#include "Stack.h" +#include "utility" +#include + +namespace Kylin { +template +class LinkedStack : public Stack { +public: + LinkedStack() = default; + LinkedStack(LinkedStack &&other) : m_list(std::move(other.m_list)) {} + LinkedStack(std::initializer_list init) { + for (auto &value : init) push(value); + } + virtual void push(const T &value) { m_list.insert(0, value); } + + T pop() final { + if (m_list.size() <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in stack..."); + auto value = m_list[0]; + m_list.removeAt(0); + return value; + } + + virtual T &top() { return m_list[0]; } + + virtual void clear() { m_list.clear(); } + + virtual size_t size() const { return m_list.size(); } + +private: + LinkedList m_list; +}; +} // namespace Kylin +#endif // LINKEDSTACK_H diff --git a/DataStructure/LinuxList.h b/DataStructure/LinuxList.h new file mode 100644 index 0000000..a2e095a --- /dev/null +++ b/DataStructure/LinuxList.h @@ -0,0 +1,672 @@ +#ifndef LINUXLIST_H +#define LINUXLIST_H + +// #include +// #include +// #include +// #include + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) (static_cast(&(reinterpret_cast(0))->MEMBER)) +#endif + +#ifndef container_of +#define container_of(ptr, type, member) \ + (reinterpret_cast(reinterpret_cast(ptr) - offsetof(type, member))) +#endif + +#define prefetch(x) ((void)x) + +#define LIST_POISON1 (nullptr) +#define LIST_POISON2 (nullptr) + +struct list_head { + struct list_head *next, *prev; +}; + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_HEAD_INIT(name) \ + { &(name), &(name) } + +#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) + +static void INIT_LIST_HEAD(struct list_head *list) { + list->next = list; + list->prev = list; +} + +/* + * Insert a node entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +#ifndef CONFIG_DEBUG_LIST +static void __list_add(struct list_head *node, struct list_head *prev, struct list_head *next) { + next->prev = node; + node->next = next; + node->prev = prev; + prev->next = node; +} +#else +extern void __list_add(struct list_head *node, struct list_head *prev, struct list_head *next); +#endif + +/** + * list_add - add a node entry + * @node: node entry to be added + * @head: list head to add it after + * + * Insert a node entry after the specified head. + * This is good for implementing stacks. + */ +static void list_add(struct list_head *node, struct list_head *head) { __list_add(node, head, head->next); } + +/** + * list_add_tail - add a node entry + * @node: node entry to be added + * @head: list head to add it before + * + * Insert a node entry before the specified head. + * This is useful for implementing queues. + */ +static void list_add_tail(struct list_head *node, struct list_head *head) { __list_add(node, head->prev, head); } + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static void __list_del(struct list_head *prev, struct list_head *next) { + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +#ifndef CONFIG_DEBUG_LIST +inline void __list_del_entry(struct list_head *entry) { __list_del(entry->prev, entry->next); } + +inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} +#else +extern void __list_del_entry(struct list_head *entry); +extern void list_del(struct list_head *entry); +#endif + +/** + * list_replace - replace old entry by node one + * @old : the element to be replaced + * @node : the node element to insert + * + * If @old was empty, it will be overwritten. + */ +inline void list_replace(struct list_head *old, struct list_head *node) { + node->next = old->next; + node->next->prev = node; + node->prev = old->prev; + node->prev->next = node; +} + +inline void list_replace_init(struct list_head *old, struct list_head *node) { + list_replace(old, node); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +inline void list_del_init(struct list_head *entry) { + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +inline void list_move(struct list_head *list, struct list_head *head) { + __list_del_entry(list); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +inline void list_move_tail(struct list_head *list, struct list_head *head) { + __list_del_entry(list); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +inline int list_empty(const struct list_head *head) { return head->next == head; } + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +inline int list_empty_careful(const struct list_head *head) { + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +inline void list_rotate_left(struct list_head *head) { + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static int list_is_singular(const struct list_head *head) { return !list_empty(head) && (head->next == head->prev); } + +static void __list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { + struct list_head *node_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = node_first; + node_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a node list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +inline void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { + if (list_empty(head)) return; + if (list_is_singular(head) && (head->next != entry && head != entry)) return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + +static void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the node list to add. + * @head: the place to add it in the first list. + */ +inline void list_splice(const struct list_head *list, struct list_head *head) { + if (!list_empty(list)) __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the node list to add. + * @head: the place to add it in the first list. + */ +inline void list_splice_tail(struct list_head *list, struct list_head *head) { + if (!list_empty(list)) __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the node list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +inline void list_splice_init(struct list_head *list, struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the node list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +inline void list_splice_tail_init(struct list_head *list, struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) for (pos = (head)->prev; prefetch(pos->prev), pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; prefetch(pos->prev), pos != (head); pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) ((pos) ?: list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue - continue list iteration safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from - iterate over list from current point safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_struct within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_safe_reset_next(pos, n, member) n = list_entry(pos->member.next, typeof(*pos), member) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +#define HLIST_HEAD_INIT \ + { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = {.first = NULL} +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static void INIT_HLIST_NODE(struct hlist_node *h) { + h->next = nullptr; + h->pprev = nullptr; +} + +inline int hlist_unhashed(const struct hlist_node *h) { return !h->pprev; } + +inline int hlist_empty(const struct hlist_head *h) { return !h->first; } + +inline void __hlist_del(struct hlist_node *n) { + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) next->pprev = pprev; +} + +inline void hlist_del(struct hlist_node *n) { + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +inline void hlist_del_init(struct hlist_node *n) { + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { + struct hlist_node *first = h->first; + n->next = first; + if (first) first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next) { + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next) { + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if (next->next) next->next->pprev = &next->next; +} + +/* after that we'll appear to be on some hlist and hlist_del will work */ +inline void hlist_add_fake(struct hlist_node *n) { n->pprev = &n->next; } + +/* + * Move a list from one list head to another. Fixup the pprev + * reference of the first entry if it exists. + */ +inline void hlist_move_list(struct hlist_head *old, struct hlist_head *node) { + node->first = old->first; + if (node->first) node->first->pprev = &node->first; + old->first = nullptr; +} + +#define hlist_entry(ptr, type, member) container_of(ptr, type, member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ \ + prefetch(pos->next); \ + 1; \ + }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ \ + n = pos->next; \ + 1; \ + }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; pos && ({ \ + prefetch(pos->next); \ + 1; \ + }) && \ + ({ \ + tpos = hlist_entry(pos, typeof(*tpos), member); \ + 1; \ + }); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; pos && ({ \ + prefetch(pos->next); \ + 1; \ + }) && \ + ({ \ + tpos = hlist_entry(pos, typeof(*tpos), member); \ + 1; \ + }); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ \ + prefetch(pos->next); \ + 1; \ + }) && \ + ({ \ + tpos = hlist_entry(pos, typeof(*tpos), member); \ + 1; \ + }); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; pos && ({ \ + n = pos->next; \ + 1; \ + }) && \ + ({ \ + tpos = hlist_entry(pos, typeof(*tpos), member); \ + 1; \ + }); \ + pos = n) + +#endif diff --git a/DataStructure/List.h b/DataStructure/List.h new file mode 100644 index 0000000..c71a938 --- /dev/null +++ b/DataStructure/List.h @@ -0,0 +1,42 @@ +#ifndef LIST_H +#define LIST_H + +#include "Object.h" + +namespace Kylin { + +template +class List : public Object { +public: + static constexpr size_t npos = static_cast(-1); + + virtual void append(const T &value) = 0; + const T &at(size_t index) const { return const_cast(this)->operator[](index); } + + virtual inline void push_back(const T &value) { append(value); } + + /** + * @brief Inserts value at index position i in the list. + * If i >= size(), the value is appended to the list. + */ + virtual void insert(size_t index, const T &value) = 0; + + virtual void removeAt(size_t index) = 0; + virtual void clear() = 0; + virtual size_t size() const noexcept = 0; + size_t length() const noexcept { return size(); } + + bool empty() const noexcept { return size() == 0; } + + virtual size_t indexOf(const T &value, size_t from = 0) const = 0; + + virtual T &last() = 0; + const T &last() const { return const_cast(this)->last(); } + + virtual T &operator[](size_t index) = 0; + const T &operator[](size_t index) const { return const_cast(this)->operator[](index); } +}; + +} // namespace Kylin + +#endif // LIST_H diff --git a/DataStructure/ListGraph.h b/DataStructure/ListGraph.h new file mode 100644 index 0000000..cad92e4 --- /dev/null +++ b/DataStructure/ListGraph.h @@ -0,0 +1,186 @@ +#ifndef LISTGRAPH_H +#define LISTGRAPH_H + +#include "DynamicArray.h" +#include "Exception.h" +#include "Graph.h" +#include "LinkedList.h" + +namespace Kylin { + +template +class ListGraph : public Graph { +public: + ListGraph(size_t n = 0) { + for (unsigned int i = 0; i < n; i++) { + addVertex(); + } + } + + size_t addVertex() { + auto v = new Vertex(); + if (v != nullptr) { + m_vertexes.append(v); + return m_vertexes.length() - 1; + } else { + THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create new vertex object ..."); + } + } + + size_t addVertex(const VertexType &value) { + auto ret = addVertex(); + setVertex(ret, value); + return ret; + } + + bool setVertex(size_t index, const VertexType &value) final { + bool ret = ((0 <= index) && (index < vertexCount())); + if (!ret) return false; + auto vertex = m_vertexes.at(index); + auto data = vertex->value; + if (data == nullptr) data = new VertexType(); + if (data != nullptr) { + *data = value; + vertex->value = data; + } else { + THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create new vertex object ..."); + } + return ret; + } + + VertexType vertex(size_t index) const final { + if (index >= vertexCount()) THROW_EXCEPTION(IndexOutOfBoundsException, "Index is out of bounds."); + auto v = m_vertexes.at(index); + if (v->value != nullptr) { + return *(v->value); + } else { + THROW_EXCEPTION(InvalidOperationException, "No value assigned to this vertex ..."); + } + } + + /** + * @brief removeVertex 删除最近添加的Vertex和与之相关联的Edge + */ + void removeVertex() { + if (m_vertexes.size() <= 0) + THROW_EXCEPTION(InvalidOperationException, "No vertex in current graph..."); + + auto removeIndex = m_vertexes.length() - 1; + auto removeVertex = m_vertexes.at(removeIndex); + m_vertexes.removeAt(removeIndex); + size_t index = 0; + for (const auto &vertex : m_vertexes) { + auto &edges = vertex->edges; + auto pos = edges.indexOf(Edge(index, removeIndex)); + if (pos != LinkedList::npos) edges.removeAt(pos); + index++; + } + delete removeVertex->value; + delete removeVertex; + } + + DynamicArray adjacent(size_t index) const final { + if ((0 <= index) && (index < vertexCount())) { + auto vertex = m_vertexes.at(index); + auto &edges = vertex->edges; + DynamicArray ret(edges.length()); + size_t index = 0; + for (const auto &edge : edges) { + ret[index++] = edge.end; + } + return ret; + } else { + THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); + } + } + + std::optional edge(size_t start, size_t end) const final { + bool status = (start < vertexCount() && end < vertexCount()); + if (!status) return std::nullopt; + auto &edges = m_vertexes.at(start)->edges; + auto pos = edges.indexOf(Edge(start, end)); + if (pos == LinkedList::npos) return std::nullopt; + return std::make_optional(edges.at(pos).value); + } + + bool setEdge(size_t start, size_t end, const EdgeType &value) final { + bool ret = ((0 <= start) && (start < vertexCount()) && (0 <= end) && (end < vertexCount())); + if (!ret) return false; + auto vertex = m_vertexes.at(start); + auto &edges = vertex->edges; + auto pos = edges.indexOf(Edge(start, end)); + if (pos != LinkedList::npos) { + edges[pos] = Edge(start, end, value); + } else { + edges.insert(0, Edge(start, end, value)); + } + return ret; + } + + bool removeEdge(size_t start, size_t end) { + bool ret = ((0 <= start) && (start < vertexCount()) && (0 <= end) && (end < vertexCount())); + if (!ret) return false; + auto vertex = m_vertexes.at(start); + auto &edges = vertex->edges; + auto pos = edges.indexOf(Edge(start, end)); + if (pos != LinkedList::npos) edges.removeAt(pos); + return ret; + } + + size_t vertexCount() const final { return m_vertexes.length(); } + + size_t edgeCount() const final { + size_t ret = 0; + for (const auto &vertex : m_vertexes) { + ret += vertex->edges.length(); + } + return ret; + } + + size_t outDegree(size_t index) const final { + size_t ret = 0; + if ((0 <= index) && (index < vertexCount())) { + ret = m_vertexes.at(index)->edges.length(); + } else { + THROW_EXCEPTION(InvalidParameterException, "Index i is invalid..."); + } + return ret; + } + + size_t inDegree(size_t index) const final { + size_t ret = 0; + if (index < 0 || index >= vertexCount()) + THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); + for (const auto &vertex : m_vertexes) { + auto &edges = vertex->edges; + for (const auto &edge : edges) { + if (edge.end == index) { + ret++; + break; + } + } + } + return ret; + } + + ~ListGraph() { + while (m_vertexes.length() > 0) { + auto toDel = m_vertexes.at(0); + m_vertexes.removeAt(0); + delete toDel->value; + delete toDel; + } + } + +protected: + struct Vertex : public Object { + VertexType *value = nullptr; + LinkedList> edges; + }; + + LinkedList m_vertexes; +}; + +} // namespace Kylin + +#endif // LISTGRAPH_H diff --git a/DataStructure/MatrixGraph.h b/DataStructure/MatrixGraph.h new file mode 100644 index 0000000..60b096f --- /dev/null +++ b/DataStructure/MatrixGraph.h @@ -0,0 +1,145 @@ +#ifndef MATRIXGRAPH_H +#define MATRIXGRAPH_H + +#include "DynamicArray.h" +#include "Exception.h" +#include "Graph.h" + +namespace Kylin { + +/** + * MatrixGraph row即为起始点Vertex的index,col即为终止点的index + */ +template +class MatrixGraph : public Graph { +public: + VertexType vertex(size_t index) const final { + if (index >= vertexCount()) THROW_EXCEPTION(IndexOutOfBoundsException, "Index is out of bounds."); + if (m_vetexes[index] != nullptr) { + return *(m_vetexes[index]); + } else { + THROW_EXCEPTION(InvalidOperationException, "No value assigned to this vertex."); + } + } + + bool setVertex(size_t index, const VertexType &value) final { + bool ret = ((0 <= index) && (index < vertexCount())); + if (!ret) return false; + auto data = m_vetexes[index]; + if (data == nullptr) data = new VertexType(); + if (data != nullptr) { + *data = value; + m_vetexes[index] = data; + } else { + THROW_EXCEPTION(NoEnoughMemoryException, "No memory to store new vertex value ..."); + } + return ret; + } + + /** + * @brief 获取与Vertex[index]相邻接的顶点(Vertex[index]作为起始点) + */ + DynamicArray adjacent(size_t index) const final { + if ((0 <= index) && (index < vertexCount())) { + size_t n = 0; + for (size_t j = 0; j < vertexCount(); j++) { + if (m_edges[index][j] != nullptr) { + n++; + } + } + DynamicArray ret(n); + for (size_t j = 0, k = 0; j < vertexCount(); j++) { + if (m_edges[index][j] != nullptr) ret[k++] = j; + } + return ret; + } else { + THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); + } + } + + std::optional edge(size_t start, size_t end) const final { + bool status = ((0 <= start) && (start < vertexCount())) && ((0 <= end) && (end < vertexCount())); + if (!status) return std::optional{}; + if (m_edges[start][end] != nullptr) { + return std::optional{*(m_edges[start][end])}; + } else { + return std::optional{}; + } + } + + bool setEdge(size_t start, size_t end, const EdgeType &value) final { + bool ret = ((0 <= start) && (start < vertexCount())) && ((0 <= end) && (end < vertexCount())); + if (!ret) return false; + auto ne = m_edges[start][end]; + if (ne == nullptr) { + ne = new EdgeType(); + if (ne != nullptr) { + *ne = value; + m_edges[start][end] = ne; + m_edgeCount++; + } else { + THROW_EXCEPTION(NoEnoughMemoryException, "No memory to store new edge value ..."); + } + } else { + *ne = value; + } + return ret; + } + + bool removeEdge(size_t start, size_t end) final { + bool ret = ((0 <= start) && (start < vertexCount())) && ((0 <= end) && (end < vertexCount())); + if (!ret) return false; + auto toDel = m_edges[start][end]; + m_edges[start][end] = nullptr; + if (toDel != nullptr) { + m_edgeCount--; + delete toDel; + } + return ret; + } + + size_t vertexCount() const final { return N; } + + size_t edgeCount() const final { return m_edgeCount; } + + size_t outDegree(size_t index) const final { + size_t ret = 0; + if ((0 <= index) && (index < vertexCount())) { + for (size_t j = 0; j < vertexCount(); j++) { + if (m_edges[index][j] != nullptr) ret++; + } + } else { + THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ..."); + } + return ret; + } + + size_t inDegree(size_t index) const final { + size_t ret = 0; + if ((0 <= index) && (index < vertexCount())) { + for (size_t i = 0; i < vertexCount(); i++) { + if (m_edges[i][index] != nullptr) ret++; + } + } else { + THROW_EXCEPTION(InvalidParameterException, "Index j is invalid ..."); + } + return ret; + } + + ~MatrixGraph() { + auto vetexes = vertexCount(); + for (size_t i = 0; i < vetexes; i++) { + for (size_t j = 0; j < vetexes; j++) { + delete m_edges[i][j]; + } + delete m_vetexes[i]; + } + } + +protected: + VertexType *m_vetexes[N] = {nullptr}; + EdgeType *m_edges[N][N] = {nullptr}; + size_t m_edgeCount = 0; +}; +} // namespace Kylin +#endif // MATRIXGRAPH_H diff --git a/DataStructure/Object.cpp b/DataStructure/Object.cpp new file mode 100644 index 0000000..ae3fd15 --- /dev/null +++ b/DataStructure/Object.cpp @@ -0,0 +1,16 @@ +#include "Object.h" +#include + +namespace Kylin { + +void *Object::operator new(size_t size) noexcept { return malloc(size); } + +void Object::operator delete(void *p) { free(p); } + +void *Object::operator new[](size_t size) noexcept { return malloc(size); } + +void Object::operator delete[](void *p) { free(p); } + +Object::~Object() {} + +} // namespace Kylin diff --git a/DataStructure/Object.h b/DataStructure/Object.h new file mode 100644 index 0000000..14aeb0d --- /dev/null +++ b/DataStructure/Object.h @@ -0,0 +1,20 @@ +#ifndef OBJECT_H +#define OBJECT_H + +#include +#include + +namespace Kylin { + +class Object { +public: + void *operator new(size_t size) noexcept; + void operator delete(void *p); + void *operator new[](size_t size) noexcept; + void operator delete[](void *p); + virtual ~Object() = 0; +}; + +} // namespace Kylin + +#endif // OBJECT_H diff --git a/DataStructure/Pointer.h b/DataStructure/Pointer.h new file mode 100644 index 0000000..afd4e9e --- /dev/null +++ b/DataStructure/Pointer.h @@ -0,0 +1,38 @@ +#ifndef POINTER_H +#define POINTER_H + +#include "Object.h" + +namespace Kylin { + +template +class Pointer : public Object{ +public: + T* get() const{ + return m_pointer; + } + + T& operator *() const{ + return *m_pointer; + } + + T* operator ->() const{ + return m_pointer; + } + + bool isNull() const{ + return (m_pointer==nullptr); + } + virtual ~Pointer() = 0; +protected: + T *m_pointer = nullptr; +}; + +template +Pointer::~Pointer() +{ + +} + +} +#endif // POINTER_H diff --git a/DataStructure/Queue.h b/DataStructure/Queue.h new file mode 100644 index 0000000..f29bcee --- /dev/null +++ b/DataStructure/Queue.h @@ -0,0 +1,20 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include "Object.h" + +namespace Kylin { +template +class Queue : public Object { +public: + virtual T &head() = 0; + const T &head() const { return const_cast(this)->head(); } + virtual T dequeue() = 0; + virtual void enqueue(const T &t) = 0; + virtual void clear() = 0; + virtual size_t size() const noexcept = 0; + inline virtual size_t length() const noexcept { return size(); } + inline virtual bool empty() const noexcept { return size() == 0; } +}; +} // namespace Kylin +#endif // QUEUE_H diff --git a/DataStructure/QueueToStack.h b/DataStructure/QueueToStack.h new file mode 100644 index 0000000..90afdb0 --- /dev/null +++ b/DataStructure/QueueToStack.h @@ -0,0 +1,60 @@ +#ifndef QUEUE2STACK_H +#define QUEUE2STACK_H + +#include "LinkedQueue.h" +#include "Stack.h" +#include + +namespace Kylin { +template +class QueueToStack : public Stack { +public: + QueueToStack(std::initializer_list init) { + for (auto &value : init) push(value); + } + void push(const T &value) final { + makeOutQueueEmpty(); + m_inQueue.enqueue(value); + } + + T pop() final { + if (size() <= 0) + THROW_EXCEPTION(InvalidOperationException, "There is no element in QueueToStack ..."); + if (m_outQueue.size() > 0) return m_outQueue.dequeue(); + moveAnElementToEmptyOutQueue(); + return m_outQueue.dequeue(); + } + + virtual T &top() { + if (size() <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in stack..."); + if (m_outQueue.size() > 0) return m_outQueue.head(); + moveAnElementToEmptyOutQueue(); + return m_outQueue.head(); + } + + virtual void clear() { + m_inQueue.clear(); + m_outQueue.clear(); + } + + virtual size_t size() const { return m_inQueue.size() + m_outQueue.size(); } + +protected: + void moveAnElementToEmptyOutQueue() { + while (m_inQueue.size() > 1) m_outQueue.enqueue(m_inQueue.dequeue()); + m_inQueue.swap(m_outQueue); + } + + void makeOutQueueEmpty() { + while (!m_outQueue.empty()) { + m_inQueue.enqueue(m_outQueue.dequeue()); + } + } + +private: + LinkedQueue m_inQueue; + LinkedQueue m_outQueue; +}; +} // namespace Kylin + +#endif // QUEUE2STACK_H diff --git a/DataStructure/RandomIterator.h b/DataStructure/RandomIterator.h new file mode 100644 index 0000000..53ce9af --- /dev/null +++ b/DataStructure/RandomIterator.h @@ -0,0 +1,25 @@ +#ifndef RANDOMITERATOR_H +#define RANDOMITERATOR_H + +#include "Object.h" + +namespace Kylin { + +template +class RandomIterator : public Object { +public: + RandomIterator(T *pos) : m_pos(pos) {} + T &operator*() { return *m_pos; } + RandomIterator &operator++() { + m_pos++; + return *this; + } + bool operator!=(const RandomIterator &other) { return m_pos != other.m_pos; } + +private: + T *m_pos = nullptr; +}; + +} // namespace Kylin + +#endif // RANDOMITERATOR_H diff --git a/DataStructure/Readme.md b/DataStructure/Readme.md new file mode 100644 index 0000000..f7eb87a --- /dev/null +++ b/DataStructure/Readme.md @@ -0,0 +1,30 @@ +```mermaid +classDiagram + Object <|.. Array + Array <|-- StaticArray + Array <|-- DynamicArray + + Object <|.. Pointer + Pointer <|-- SmartPointer + Pointer <|-- SharedPointer + + Object <|.. Exception + Exception <|-- ArithmeticException + Exception <|-- InvalidParameterException + Exception <|-- InvalidOperationException + Exception <|-- NoEnoughMemoryException + Exception <|-- IndexOutOfBoundsException + + Object <|.. List + List <|-- ArrayList + List <|-- LinkedList + List <|-- DualLinkedList + + Object <|.. Graph + Graph <|-- ListGraph + Graph <|-- MatrixGraph + + + +``` + diff --git a/DataStructure/SharedPointer.h b/DataStructure/SharedPointer.h new file mode 100644 index 0000000..2cc4eae --- /dev/null +++ b/DataStructure/SharedPointer.h @@ -0,0 +1,51 @@ +#ifndef SHAREDPOINTER_H +#define SHAREDPOINTER_H + +#include "Pointer.h" + +namespace Kylin { +template +class SharedPointer : public Pointer { +public: + SharedPointer(T *p) { + if (p == nullptr) return; + this->m_pointer = p; + m_counter = new size_t(1); + } + SharedPointer(const SharedPointer &obj) { + if (obj.m_counter == nullptr) return; + m_counter = obj.m_counter; + this->m_pointer = obj.m_pointer; + (*m_counter)++; + } + + SharedPointer &operator=(const SharedPointer &obj) { + if (this != &obj) { + clear(); + m_counter = obj.m_counter; + this->m_pointer = obj.m_pointer; + (*m_counter)++; + } + } + + void clear() { + if (m_counter == nullptr) return; + (*m_counter)--; + if (*m_counter == 0) { + delete m_counter; + delete this->m_pointer; + } + this->m_pointer = nullptr; + m_counter = nullptr; + } + + bool operator==(const SharedPointer &obj) const { return (this->m_pointer == obj.m_pointer); } + + ~SharedPointer() { clear(); } + +private: + size_t *m_counter = nullptr; +}; + +} // namespace Kylin +#endif // SHAREDPOINTER_H diff --git a/DataStructure/Sort.h b/DataStructure/Sort.h new file mode 100644 index 0000000..1bcac32 --- /dev/null +++ b/DataStructure/Sort.h @@ -0,0 +1,151 @@ +#ifndef SORT_H +#define SORT_H + +#include "Array.h" +#include "Object.h" + +namespace Kylin { + +class Sort : public Object { +public: + template + static void select(T array[], size_t size) { + for (size_t i = 0; i < size; i++) { + size_t index = i; + for (size_t j = i + 1; j < size; j++) { + if (array[j] < array[index]) index = j; + } + if (index != i) swap(array[i], array[index]); + } + } + + template + static void insert(T array[], int size) { + for (int i = 1; i < size; i++) { + T value = array[i]; + int index = i; + for (int j = i - 1; j >= 0; j--) { + if (value < array[j]) { + array[j + 1] = array[j]; + index = j; + } else + break; + } + if (index != i) array[index] = value; + } + } + + template + static void bubble(T array[], int size) { + bool swaped = true; + for (int i = 0; (i < size) && swaped; i++) { + swaped = false; + for (int j = size - 1; j > i; j--) { + if (array[j] < array[j - 1]) { + swap(array[j], array[j - 1]); + swaped = true; + } + } + } + } + + template + static void shell(T array[], size_t size) { + size_t gap = size; + do { + gap = gap / 3 + 1; + for (size_t i = 0; i < size; i += gap) { + size_t index = i; + for (size_t j = i + gap; j < size; j++) { + if (array[j] < array[index]) { + index = j; + } + } + if (index != i) swap(array[index], array[i]); + } + + } while (gap > 1); + } + + template + static void quick(T array[], size_t size) { + quick(array, 0, size - 1); + } + + template + static void merge(T array[], size_t size) { + T *helper = new T[size]; + merge(array, helper, 0, size - 1); + delete[] helper; + } + +protected: + template + static void merge(T array[], T helper[], size_t begin, size_t end) { + if (begin >= end) return; + size_t middle = (begin + end) / 2; + merge(array, helper, begin, middle); + if (middle < end) merge(array, helper, middle + 1, end); + merge(array, helper, begin, middle, end); + } + + template + static void merge(T array[], T helper[], size_t begin, size_t middle, size_t end) { + size_t i = begin, j = middle + 1, k = begin; + while ((i <= middle) && (j <= end)) { + if (array[i] < array[j]) { + helper[k++] = array[i++]; + } else { + helper[k++] = array[j++]; + } + } + while (i <= middle) { + helper[k++] = array[i++]; + } + while (j <= end) { + helper[k++] = array[j++]; + } + + for (size_t i = begin; i <= end; i++) { + array[i] = helper[i]; + } + } + + template + static void quick(T array[], size_t begin, size_t end) { + if (begin >= end) return; + auto pivot = partition(array, begin, end); + if (pivot > 0) quick(array, begin, pivot - 1); + quick(array, pivot + 1, end); + } + + template + static size_t partition(T array[], size_t begin, size_t end) { + T value = array[begin]; + while (begin < end) { + while ((begin < end) && (array[end] > value)) { + end--; + } + swap(array[begin], array[end]); + while ((begin < end) && (array[begin] <= value)) { + begin++; + } + swap(array[begin], array[end]); + } + return begin; + } + + template + static void swap(T &a, T &b) { + T c(a); + a = b; + b = c; + } + + Sort() = delete; + Sort(const Sort &) = delete; + Sort &operator=(const Sort &) = delete; +}; +} // namespace Kylin + +#endif // SORT_H diff --git a/DataStructure/Stack.h b/DataStructure/Stack.h new file mode 100644 index 0000000..8429eb5 --- /dev/null +++ b/DataStructure/Stack.h @@ -0,0 +1,18 @@ +#ifndef STACK_H +#define STACK_H + +#include "Object.h" + +namespace Kylin { +template +class Stack : public Object { +public: + virtual void push(const T &value) = 0; + virtual T pop() = 0; + virtual T &top() = 0; + const T &top() const { return const_cast(this)->top(); } + virtual void clear() = 0; + virtual size_t size() const = 0; +}; +} // namespace Kylin +#endif // STACK_H diff --git a/DataStructure/StackToQueue.h b/DataStructure/StackToQueue.h new file mode 100644 index 0000000..3a6e0c2 --- /dev/null +++ b/DataStructure/StackToQueue.h @@ -0,0 +1,52 @@ +#ifndef STACK2QUEUE_H +#define STACK2QUEUE_H + +#include "LinkedStack.h" +#include "Queue.h" +#include + +namespace Kylin { +template +class StackToQueue : public Queue { +public: + StackToQueue(std::initializer_list init) { + for (auto &value : init) enqueue(value); + } + void enqueue(const T &value) final { m_in.push(value); } + + T dequeue() final { + if (size() <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the queue..."); + auto value = head(); + move(); + m_out.pop(); + return value; + } + T &head() final { + if (size() <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the queue..."); + move(); + return m_out.top(); + } + + virtual void clear() { + m_in.clear(); + m_out.clear(); + } + + size_t size() const noexcept override { return m_in.size() + m_out.size(); } + +protected: + void move() const { + if (m_out.size() <= 0) { + while (m_in.size() > 0) { + m_out.push(m_in.top()); + m_in.pop(); + } + } + } + +private: + mutable LinkedStack m_in; + mutable LinkedStack m_out; +}; +} // namespace Kylin +#endif // STACK2QUEUE_H diff --git a/DataStructure/StaticArray.h b/DataStructure/StaticArray.h new file mode 100644 index 0000000..3c67d50 --- /dev/null +++ b/DataStructure/StaticArray.h @@ -0,0 +1,24 @@ +#ifndef STATICARRAY_H +#define STATICARRAY_H + +#include "Array.h" + +namespace Kylin { + +template +class StaticArray : public Array { +public: + StaticArray() { this->m_array = m_space; } + StaticArray(const StaticArray &other) { + this->m_array = m_space; + for (size_t i = 0; i < N; i++) { + m_space[i] = other.m_space[i]; + } + } + size_t size() const noexcept override { return N; } + +private: + T m_space[N]; +}; +} // namespace Kylin +#endif // STATICARRAY_H diff --git a/DataStructure/StaticArrayList.h b/DataStructure/StaticArrayList.h new file mode 100644 index 0000000..f7f2bc4 --- /dev/null +++ b/DataStructure/StaticArrayList.h @@ -0,0 +1,26 @@ +#ifndef STATICSEQLIST_H +#define STATICSEQLIST_H + +#include "ArrayList.h" + +namespace Kylin { + +template +class StaticArrayList : public ArrayList { +public: + StaticArrayList() { this->m_array = m_space; } + StaticArrayList(const StaticArrayList &other) { + this->m_array = m_space; + for (size_t i = 0; i < other.m_size; i++) { + m_space[i] = other.m_space[i]; + this->m_size++; + } + } + virtual size_t capacity() const noexcept { return N; } + +private: + T m_space[N]; +}; +} // namespace Kylin + +#endif // STATICSEQLIST_H diff --git a/DataStructure/StaticLinkedList.h b/DataStructure/StaticLinkedList.h new file mode 100644 index 0000000..69ed67e --- /dev/null +++ b/DataStructure/StaticLinkedList.h @@ -0,0 +1,67 @@ +#ifndef STATICLINKEDLIST_H +#define STATICLINKEDLIST_H + +#include "LinkedList.h" + +namespace Kylin { + +template +class StaticLinkedList : public LinkedList { + using Node = typename LinkedList::Node; + struct StaticNode : public Node { + void *operator new(size_t /*size*/, void *p) { return p; } + }; + +public: + StaticLinkedList() = default; + StaticLinkedList(const StaticLinkedList &other) { + auto sourceNode = other.m_header.next; + auto targetNode = reinterpret_cast(&this->m_header); + while (sourceNode != nullptr) { + auto newNode = create(); + if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node..."); + newNode->value = sourceNode->value; + targetNode->next = newNode; + targetNode = newNode; + sourceNode = sourceNode->next; + this->m_size++; + targetNode->next = nullptr; + this->m_last = targetNode; + } + } + ~StaticLinkedList() { this->clear(); } + size_t capacity() const { return N; } + + void swap(StaticLinkedList & /*other*/) { + THROW_EXCEPTION(InvalidOperationException, "StaticLinkedList can`t do swap operate."); + } + +protected: + Node *create() override { + Node *ret = nullptr; + for (size_t i = 0; i < N; i++) { + if (m_used[i]) continue; + ret = reinterpret_cast(m_space) + i; + ret = new (ret) StaticNode(); + m_used[i] = true; + break; + } + return ret; + } + + void destroy(Node *p) override { + auto del = dynamic_cast(p); + for (size_t i = 0; i < N; i++) { + if ((reinterpret_cast(m_space) + i) != del) continue; + m_used[i] = false; + del->~StaticNode(); + break; + } + } + +private: + uint8_t m_space[N * sizeof(StaticNode)]; + bool m_used[N]{false}; +}; +} // namespace Kylin +#endif // STATICLINKEDLIST_H diff --git a/DataStructure/StaticQueue.h b/DataStructure/StaticQueue.h new file mode 100644 index 0000000..7e3930f --- /dev/null +++ b/DataStructure/StaticQueue.h @@ -0,0 +1,48 @@ +#ifndef STATICQUEUE_H +#define STATICQUEUE_H + +#include "Exception.h" +#include "Queue.h" + +namespace Kylin { +template +class StaticQueue : public Queue { +public: + T &head() override { + if (m_size <= 0) THROW_EXCEPTION(InvalidParameterException, "There is no element in queue..."); + return m_space[m_front]; + } + + void enqueue(const T &value) override { + if (m_size >= N) THROW_EXCEPTION(InvalidParameterException, "There is no space..."); + m_space[m_rear] = value; + m_rear = (m_rear + 1) % N; + m_size++; + } + + T dequeue() override { + if (m_size <= 0) THROW_EXCEPTION(InvalidParameterException, "There is no element in queue..."); + auto result = m_space[m_front]; + m_front = (m_front + 1) % N; + m_size--; + return result; + } + + virtual void clear() { + m_front = 0; + m_rear = 0; + m_size = 0; + } + + size_t size() const noexcept override { return m_size; } + + size_t capacity() const { return N; } + +private: + T m_space[N]; + size_t m_front = 0; + size_t m_rear = 0; + size_t m_size = 0; +}; +} // namespace Kylin +#endif // STATICQUEUE_H diff --git a/DataStructure/StaticStack.h b/DataStructure/StaticStack.h new file mode 100644 index 0000000..d121c9a --- /dev/null +++ b/DataStructure/StaticStack.h @@ -0,0 +1,40 @@ +#ifndef STATICSTACK_H +#define STATICSTACK_H + +#include "Exception.h" +#include "Stack.h" + +namespace Kylin { +template +class StaticStack : public Stack { +public: + virtual void push(const T &value) { + if (m_size >= N) THROW_EXCEPTION(InvalidOperationException, "There is no space to push element..."); + m_array[m_size] = value; + m_size++; + } + + T pop() final { + if (m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in stack..."); + auto value = top(); + m_size--; + return value; + } + + virtual T &top() { + if (m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in stack..."); + return m_array[m_size - 1]; + } + + virtual void clear() { m_size = 0; } + + virtual size_t size() const { return m_size; } + + size_t capacity() const { return N; } + +protected: + T m_array[N]; + size_t m_size = 0; +}; +} // namespace Kylin +#endif // STATICSTACK_H diff --git a/DataStructure/Tree.h b/DataStructure/Tree.h new file mode 100644 index 0000000..63d7cd2 --- /dev/null +++ b/DataStructure/Tree.h @@ -0,0 +1,36 @@ +#ifndef TREE_H +#define TREE_H + +#include "Object.h" + +namespace Kylin { + +template + +class TreeNode { +public: + TreeNode(const T &value, TreeNode *parent) : value(value), parent(parent) {} + T value; + TreeNode *parent = nullptr; + virtual ~TreeNode() {} +}; + +template +class Tree : public Object { +public: + virtual bool insert(TreeNode *node) = 0; + virtual TreeNode *find(const T &value) const = 0; + virtual bool find(TreeNode *node) const = 0; + virtual TreeNode *root() const = 0; + virtual int degree() const = 0; + virtual int count() const = 0; + virtual int height() const = 0; + virtual void clear() = 0; + +protected: + TreeNode *m_root = nullptr; +}; + +} // namespace Kylin + +#endif // TREE_H diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/UnitTest/CMakeLists.txt b/UnitTest/CMakeLists.txt index 763d656..06d30c4 100644 --- a/UnitTest/CMakeLists.txt +++ b/UnitTest/CMakeLists.txt @@ -5,6 +5,29 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(UnitTest main.cpp + DataStructure/BinarySearchTreeTest.cpp + DataStructure/BinaryTreeTest.cpp + DataStructure/CircularDoublyLinkedListTest.cpp + DataStructure/CircularLinkedListTest.cpp + DataStructure/DoublyLinkedListTest.cpp + DataStructure/DynamicArrayListTest.cpp + DataStructure/DynamicArrayTest.cpp + DataStructure/GeneralTreeTest.cpp + DataStructure/LinkedListTest.cpp + DataStructure/LinkedQueueTest.cpp + DataStructure/LinkedStackTest.cpp + DataStructure/ListGraphTest.cpp + DataStructure/MatrixGraphTest.cpp + DataStructure/QueueToStackTest.cpp + DataStructure/SmartPointerTest.cpp + DataStructure/StackToQueueTest.cpp + DataStructure/StaticArrayListTest.cpp + DataStructure/StaticArrayTest.cpp + DataStructure/StaticLinkedListTest.cpp + DataStructure/StaticQueueTest.cpp + DataStructure/StaticStackTest.cpp + DataStructure/StringTest.cpp + Universal/BoostLogTest.cpp ) target_compile_definitions(UnitTest @@ -13,4 +36,6 @@ target_compile_definitions(UnitTest target_link_libraries(UnitTest PRIVATE Boost::unit_test_framework + PRIVATE DataStructure + PRIVATE Universal ) diff --git a/UnitTest/DataStructure/BinarySearchTreeTest.cpp b/UnitTest/DataStructure/BinarySearchTreeTest.cpp new file mode 100644 index 0000000..befc6bc --- /dev/null +++ b/UnitTest/DataStructure/BinarySearchTreeTest.cpp @@ -0,0 +1,69 @@ +#include "BinarySearchTree.h" +#include + +using namespace Kylin; + +class BinarySearchTreeTest { +public: + BinarySearchTreeTest() { + for (size_t i = 0; i < 11; i++) { + tree.insert(unsorted[i]); + } + } + BinarySearchTree tree; + size_t sorted[11]{6, 8, 9, 10, 11, 15, 17, 18, 19, 20, 22}; + size_t unsorted[11]{15, 9, 20, 6, 10, 18, 22, 8, 11, 17, 19}; +}; + +/* + 15 + 9 20 + 6 10 18 22 + 8 11 17 19 +*/ + +BOOST_FIXTURE_TEST_CASE(Find, BinarySearchTreeTest) { + auto node = tree.find(18); + BOOST_CHECK_EQUAL(node->value, 18); +} + +BOOST_FIXTURE_TEST_CASE(Maximum, BinarySearchTreeTest) { BOOST_CHECK_EQUAL(tree.maximum(), 22); } + +BOOST_FIXTURE_TEST_CASE(Minimum, BinarySearchTreeTest) { BOOST_CHECK_EQUAL(tree.minimum(), 6); } + +BOOST_FIXTURE_TEST_CASE(PredecessorIsLeft, BinarySearchTreeTest) { + auto node = tree.find(18); + auto predecessor = tree.predecessor(node); + BOOST_CHECK_EQUAL(predecessor->value, 17); +} + +BOOST_FIXTURE_TEST_CASE(PredecessorIsNotLeft, BinarySearchTreeTest) { + auto node = tree.find(17); + auto predecessor = tree.predecessor(node); + BOOST_CHECK_EQUAL(predecessor->value, 15); +} + +BOOST_FIXTURE_TEST_CASE(SuccessorIsRight, BinarySearchTreeTest) { + auto node = tree.find(20); + auto successor = tree.successor(node); + BOOST_CHECK_EQUAL(successor->value, 22); +} + +BOOST_FIXTURE_TEST_CASE(SuccessorIsNotRight, BinarySearchTreeTest) { + auto node = tree.find(17); + auto successor = tree.successor(node); + BOOST_CHECK_EQUAL(successor->value, 18); +} + +BOOST_FIXTURE_TEST_CASE(SuccessorIsGrandParent, BinarySearchTreeTest) { + auto node = tree.find(19); + auto successor = tree.successor(node); + BOOST_CHECK_EQUAL(successor->value, 20); +} + +BOOST_FIXTURE_TEST_CASE(iterator, BinarySearchTreeTest) { + size_t i = 0; + for (const auto &iter : tree) { + BOOST_CHECK_EQUAL(iter, sorted[i++]); + } +} diff --git a/UnitTest/DataStructure/BinaryTreeTest.cpp b/UnitTest/DataStructure/BinaryTreeTest.cpp new file mode 100644 index 0000000..33b8848 --- /dev/null +++ b/UnitTest/DataStructure/BinaryTreeTest.cpp @@ -0,0 +1,273 @@ +#include "BinaryTree.h" +#include + +using namespace Kylin; + +class BinaryTreeTest { +public: + /* + 1 + 2 3 + 4 5 6 7 + 8 9 10 11 + */ + + BinaryTreeTest() { + auto node1 = new BinaryTreeNode(1); + tree.insert(node1); + + auto node2 = new BinaryTreeNode(2, node1); + node3 = new BinaryTreeNode(3, node1); + tree.insert(node2); + tree.insert(node3); + + auto node4 = new BinaryTreeNode(4, node2); + node5 = new BinaryTreeNode(5, node2); + tree.insert(node4); + tree.insert(node5); + + node6 = new BinaryTreeNode(6, node3); + auto node7 = new BinaryTreeNode(7, node3); + tree.insert(node6); + tree.insert(node7); + + auto node8 = new BinaryTreeNode(8, node4); + auto node9 = new BinaryTreeNode(9, node4); + tree.insert(node8); + tree.insert(node9); + + auto node10 = new BinaryTreeNode(10, node5); + tree.insert(node10); + + auto node11 = new BinaryTreeNode(11, node6); + tree.insert(node11); + + initAddedTree(); + } + + /* + * 0 + * 6 2 + * 7 8 + */ + void initAddedTree() { + auto node0 = new BinaryTreeNode(0); + addedTree.insert(node0); + + auto node6 = new BinaryTreeNode(6, node0); + auto node2 = new BinaryTreeNode(2, node0); + addedTree.insert(node6); + addedTree.insert(node2); + + auto node7 = new BinaryTreeNode(7, node2); + auto node8 = new BinaryTreeNode(8, node2); + addedTree.insert(node7); + addedTree.insert(node8); + } + + BinaryTreeNode *node3 = nullptr; + BinaryTreeNode *node5 = nullptr; + BinaryTreeNode *node6 = nullptr; + BinaryTree tree; + BinaryTree addedTree; + + size_t preOrder[11]{1, 2, 4, 8, 9, 5, 10, 3, 6, 11, 7}; + size_t inOrder[11]{8, 4, 9, 2, 10, 5, 1, 11, 6, 3, 7}; + size_t postOrder[11]{8, 9, 4, 10, 5, 2, 11, 6, 7, 3, 1}; + size_t levelOrder[11]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; +}; +BOOST_AUTO_TEST_SUITE(BinaryTreeTestCase) +BOOST_FIXTURE_TEST_CASE(Count, BinaryTreeTest) { BOOST_CHECK_EQUAL(tree.count(), 11); } + +BOOST_FIXTURE_TEST_CASE(Height, BinaryTreeTest) { BOOST_CHECK_EQUAL(tree.height(), 4); } + +BOOST_FIXTURE_TEST_CASE(Degree, BinaryTreeTest) { BOOST_CHECK_EQUAL(tree.degree(), 2); } + +BOOST_FIXTURE_TEST_CASE(FindWithValue, BinaryTreeTest) { + auto node = tree.find(5); + BOOST_CHECK_EQUAL(node != nullptr, true); + BOOST_CHECK_EQUAL(node->value, 5); +} + +BOOST_FIXTURE_TEST_CASE(FindWithNode, BinaryTreeTest) { + auto result = tree.find(node5); + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_FIXTURE_TEST_CASE(InsertWithValue, BinaryTreeTest) { + auto status = tree.insert(12, node6, BinaryTree::Right); + BOOST_CHECK_EQUAL(status, true); +} + +BOOST_FIXTURE_TEST_CASE(InsertWithNode, BinaryTreeTest) { + auto node12 = new BinaryTreeNode(12); + node12->parent = node6; + auto result = tree.insert(node12); + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_FIXTURE_TEST_CASE(Clear, BinaryTreeTest) { + tree.clear(); + BOOST_CHECK_EQUAL(tree.count(), 0); +} + +BOOST_FIXTURE_TEST_CASE(RemoveWithValue, BinaryTreeTest) { + auto removeTree = tree.remove(3); + BOOST_CHECK_EQUAL(removeTree.count(), 4); +} + +BOOST_FIXTURE_TEST_CASE(RemoveWithNode, BinaryTreeTest) { + auto removeTree = tree.remove(node3); + BOOST_CHECK_EQUAL(removeTree.count(), 4); +} + +BOOST_FIXTURE_TEST_CASE(PreOrderTraversal, BinaryTreeTest) { + auto array = tree.traversal(BinaryTree::Preorder); + BOOST_CHECK_EQUAL(array.size(), 11); + for (size_t i = 0; i < 11; i++) { + BOOST_CHECK_EQUAL(array[i], preOrder[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(InOrderTraversal, BinaryTreeTest) { + auto array = tree.traversal(BinaryTree::Inorder); + BOOST_CHECK_EQUAL(array.size(), 11); + for (size_t i = 0; i < 11; i++) { + BOOST_CHECK_EQUAL(array[i], inOrder[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(PostOrderTraversal, BinaryTreeTest) { + auto array = tree.traversal(BinaryTree::Postorder); + BOOST_CHECK_EQUAL(array.size(), 11); + for (size_t i = 0; i < 11; i++) { + BOOST_CHECK_EQUAL(array[i], postOrder[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Iterator, BinaryTreeTest) { + size_t index = 1; + for (auto v : tree) { + BOOST_CHECK_EQUAL(v, index++); + } + BOOST_CHECK_EQUAL(index, 12); +} + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, BinaryTreeTest) { + auto tree2(tree); + BOOST_CHECK_EQUAL(tree2.count(), 11); +} + +BOOST_FIXTURE_TEST_CASE(Equal, BinaryTreeTest) { + BinaryTree tree2; + auto node1 = new BinaryTreeNode(1); + tree2.insert(node1); + + auto node2 = new BinaryTreeNode(2, node1); + auto node3 = new BinaryTreeNode(3, node1); + tree2.insert(node2); + tree2.insert(node3); + + auto node4 = new BinaryTreeNode(4, node2); + auto node5 = new BinaryTreeNode(5, node2); + tree2.insert(node4); + tree2.insert(node5); + + auto node6 = new BinaryTreeNode(6, node3); + auto node7 = new BinaryTreeNode(7, node3); + tree2.insert(node6); + tree2.insert(node7); + + auto node8 = new BinaryTreeNode(8, node4); + auto node9 = new BinaryTreeNode(9, node4); + tree2.insert(node8); + tree2.insert(node9); + + auto node10 = new BinaryTreeNode(10, node5); + tree2.insert(node10); + + auto node11 = new BinaryTreeNode(11, node6); + tree2.insert(node11); + + BOOST_TEST((tree2 == tree)); +} + +BOOST_FIXTURE_TEST_CASE(Add, BinaryTreeTest) { + + BinaryTree resultTree; + auto node1 = new BinaryTreeNode(1); + resultTree.insert(node1); + + auto node8from1 = new BinaryTreeNode(8, node1); + auto node5from1 = new BinaryTreeNode(5, node1); + resultTree.insert(node8from1); + resultTree.insert(node5from1); + + auto node4 = new BinaryTreeNode(4, node8from1); + auto node5from8 = new BinaryTreeNode(5, node8from1); + resultTree.insert(node4); + resultTree.insert(node5from8); + + auto node13 = new BinaryTreeNode(13, node5from1); + auto node15 = new BinaryTreeNode(15, node5from1); + resultTree.insert(node13); + resultTree.insert(node15); + + auto node8from4 = new BinaryTreeNode(8, node4); + auto node9 = new BinaryTreeNode(9, node4); + resultTree.insert(node8from4); + resultTree.insert(node9); + + auto node10 = new BinaryTreeNode(10, node5from8); + resultTree.insert(node10); + + auto node11 = new BinaryTreeNode(11, node13); + resultTree.insert(node11); + BOOST_CHECK_EQUAL(resultTree.count(), 11); + BOOST_TEST((tree + addedTree == resultTree)); +} + +BOOST_FIXTURE_TEST_CASE(PreorderThreaded, BinaryTreeTest) { + auto head = tree.threaded(BinaryTree::Preorder); + size_t index = 0; + while (head != nullptr) { + BOOST_CHECK_EQUAL(head->value, preOrder[index++]); + head = head->right; + } + BOOST_CHECK_EQUAL(index, 11); + BOOST_CHECK_EQUAL(tree.count(), 0); +} + +BOOST_FIXTURE_TEST_CASE(InorderThreaded, BinaryTreeTest) { + auto head = tree.threaded(BinaryTree::Inorder); + size_t index = 0; + while (head != nullptr) { + BOOST_CHECK_EQUAL(head->value, inOrder[index++]); + head = head->right; + } + BOOST_CHECK_EQUAL(index, 11); + BOOST_CHECK_EQUAL(tree.count(), 0); +} + +BOOST_FIXTURE_TEST_CASE(PostorderThreaded, BinaryTreeTest) { + auto head = tree.threaded(BinaryTree::Postorder); + size_t index = 0; + while (head != nullptr) { + BOOST_CHECK_EQUAL(head->value, postOrder[index++]); + head = head->right; + } + BOOST_CHECK_EQUAL(index, 11); + BOOST_CHECK_EQUAL(tree.count(), 0); +} + +BOOST_FIXTURE_TEST_CASE(LevelorderThreaded, BinaryTreeTest) { + auto head = tree.threaded(BinaryTree::Levelorder); + size_t index = 0; + while (head != nullptr) { + BOOST_CHECK_EQUAL(head->value, levelOrder[index++]); + head = head->right; + } + BOOST_CHECK_EQUAL(index, 11); + BOOST_CHECK_EQUAL(tree.count(), 0); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/CircularDoublyLinkedListTest.cpp b/UnitTest/DataStructure/CircularDoublyLinkedListTest.cpp new file mode 100644 index 0000000..ce263b3 --- /dev/null +++ b/UnitTest/DataStructure/CircularDoublyLinkedListTest.cpp @@ -0,0 +1,108 @@ +#include "CircularDoublyLinkedList.h" +#include +#include + +using namespace Kylin; + +class CircularDoublyLinkedListTest { +public: + CircularDoublyLinkedList list{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_AUTO_TEST_SUITE(CircularDoublyLinkedListTestCase) +BOOST_FIXTURE_TEST_CASE(At, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.at(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Size, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Last, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.last(), 9); } + +BOOST_FIXTURE_TEST_CASE(EmptyListCallLastCauseException, CircularDoublyLinkedListTest) { + CircularDoublyLinkedList emptyList; + BOOST_CHECK_THROW(emptyList.last(), InvalidOperationException); +} + +BOOST_FIXTURE_TEST_CASE(CallLastAfterRemoveLastElement, CircularDoublyLinkedListTest) { + list.removeAt(list.size() - 1); + BOOST_CHECK_EQUAL(list.last(), 8); +} + +BOOST_FIXTURE_TEST_CASE(RemoveIndexLessThenSize, CircularDoublyLinkedListTest) { + list.removeAt(3); + BOOST_CHECK_EQUAL(list[3], 4); + BOOST_CHECK_EQUAL(list.length(), 9); +} + +BOOST_FIXTURE_TEST_CASE(RemoveIndexBigThenSize, CircularDoublyLinkedListTest) { + list.removeAt(15); + BOOST_CHECK_EQUAL(list[5], 6); + BOOST_CHECK_EQUAL(list.length(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Clear, CircularDoublyLinkedListTest) { + list.clear(); + BOOST_CHECK_EQUAL(list.length(), 0); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, CircularDoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Append, CircularDoublyLinkedListTest) { + list.append(198); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(list.size() - 1), 198); +} + +BOOST_FIXTURE_TEST_CASE(Swap, CircularDoublyLinkedListTest) { + CircularDoublyLinkedList list2; + for (size_t i = 0; i < 5; i++) { + list2.insert(list2.length(), i + 10); + } + + list2.swap(list); + + BOOST_CHECK_EQUAL(list.size(), 5); + BOOST_CHECK_EQUAL(list2.size(), 10); + + for (size_t i = 0; i < 5; i++) { + BOOST_CHECK_EQUAL(list.at(i), i + 10); + } + + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(list2.at(i), i); + } +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexLessThenSize, CircularDoublyLinkedListTest) { + list.insert(4, 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(4), 456); + BOOST_CHECK_EQUAL(list.at(5), 4); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexEuqalSize, CircularDoublyLinkedListTest) { + list.insert(list.size(), 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(list.size() - 1), 456); +} + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, CircularDoublyLinkedListTest) { + auto list2(list); + BOOST_CHECK_EQUAL(list2.size(), 10); + list[9] = 2; //测试是否为浅拷贝 + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, CircularDoublyLinkedListTest) { + auto list2(std::move(list)); + BOOST_CHECK_EQUAL(list.empty(), true); + BOOST_CHECK_EQUAL(list2.size(), 10); + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(Iterator, CircularDoublyLinkedListTest) { + size_t i = 0; + for (const auto &value : list) { + BOOST_CHECK_EQUAL(value, i++); + } + BOOST_CHECK_EQUAL(list.size(), i); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/CircularLinkedListTest.cpp b/UnitTest/DataStructure/CircularLinkedListTest.cpp new file mode 100644 index 0000000..33c621c --- /dev/null +++ b/UnitTest/DataStructure/CircularLinkedListTest.cpp @@ -0,0 +1,103 @@ +#include "CircularLinkedList.h" +#include + +using namespace Kylin; + +class CircularListTest { +public: + CircularLinkedList list{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_AUTO_TEST_SUITE(CircularListTestCase) +BOOST_FIXTURE_TEST_CASE(AtIndexLessThanSize, CircularListTest) { BOOST_CHECK_EQUAL(list.at(5), 5); } + +BOOST_FIXTURE_TEST_CASE(AtIndexBiggerThanSize, CircularListTest) { BOOST_CHECK_EQUAL(list.at(15), 5); } + +BOOST_FIXTURE_TEST_CASE(Size, CircularListTest) { BOOST_CHECK_EQUAL(list.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Last, CircularListTest) { BOOST_CHECK_EQUAL(list.last(), 9); } + +BOOST_FIXTURE_TEST_CASE(EmptyListCallLastCauseException, CircularListTest) { + CircularLinkedList emptyList; + BOOST_CHECK_THROW(emptyList.last(), InvalidOperationException); +} + +BOOST_FIXTURE_TEST_CASE(RemoveAtIndexLessThanSize, CircularListTest) { + list.removeAt(3); + BOOST_CHECK_EQUAL(list.at(3), 4); + BOOST_CHECK_EQUAL(list.length(), 9); +} + +BOOST_FIXTURE_TEST_CASE(RemoveAtIndexBiggerThanSize, CircularListTest) { + list.removeAt(15); + BOOST_CHECK_EQUAL(list.length(), 9); + BOOST_CHECK_EQUAL(list.at(15), 7); +} + +BOOST_FIXTURE_TEST_CASE(Clear, CircularListTest) { + list.clear(); + BOOST_CHECK_EQUAL(list.length(), 0); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, CircularListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Append, CircularListTest) { + list.append(198); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(10), 198); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexLessThenSize, CircularListTest) { + list.insert(4, 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(4), 456); + BOOST_CHECK_EQUAL(list.at(5), 4); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexBiggerSize, CircularListTest) { + list.insert(15, 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(4), 456); +} + +BOOST_FIXTURE_TEST_CASE(Swap, CircularListTest) { + CircularLinkedList list2; + for (size_t i = 0; i < 5; i++) { + list2.insert(list2.length(), i + 10); + } + + list2.swap(list); + + BOOST_CHECK_EQUAL(list.size(), 5); + BOOST_CHECK_EQUAL(list2.size(), 10); + + for (size_t i = 0; i < 5; i++) { + BOOST_CHECK_EQUAL(list.at(i), i + 10); + } + + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(list2.at(i), i); + } +} + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, CircularListTest) { + auto list2(list); + BOOST_CHECK_EQUAL(list2.size(), 10); + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, CircularListTest) { + auto list2(std::move(list)); + BOOST_CHECK_EQUAL(list.empty(), true); + BOOST_CHECK_EQUAL(list2.size(), 10); + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(Iterator, CircularListTest) { + size_t value = 0; + for (const auto &v : list) { + BOOST_CHECK_EQUAL(v, value++); + } + BOOST_CHECK_EQUAL(value, 10); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/DoublyLinkedListTest.cpp b/UnitTest/DataStructure/DoublyLinkedListTest.cpp new file mode 100644 index 0000000..7ff0eff --- /dev/null +++ b/UnitTest/DataStructure/DoublyLinkedListTest.cpp @@ -0,0 +1,101 @@ +#include "DoublyLinkedList.h" +#include + +using namespace Kylin; + +class DoublyLinkedListTest { +public: + DoublyLinkedList list{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_AUTO_TEST_SUITE(DoublyLinkedListTestCase) +BOOST_FIXTURE_TEST_CASE(At, DoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.at(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Size, DoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Last, DoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.last(), 9); } + +BOOST_FIXTURE_TEST_CASE(EmptyListCallLastCauseException, DoublyLinkedListTest) { + DoublyLinkedList emptyList; + BOOST_CHECK_THROW(emptyList.last(), InvalidOperationException); +} + +BOOST_FIXTURE_TEST_CASE(CallLastAfterRemoveLastElement, DoublyLinkedListTest) { + list.removeAt(list.size() - 1); + BOOST_CHECK_EQUAL(list.last(), 8); +} + +BOOST_FIXTURE_TEST_CASE(RemoveAt, DoublyLinkedListTest) { + list.removeAt(3); + BOOST_CHECK_EQUAL(list.at(3), 4); + BOOST_CHECK_EQUAL(list.length(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Clear, DoublyLinkedListTest) { + list.clear(); + BOOST_CHECK_EQUAL(list.length(), 0); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, DoublyLinkedListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Append, DoublyLinkedListTest) { + list.append(198); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(list.size() - 1), 198); +} + +BOOST_FIXTURE_TEST_CASE(Swap, DoublyLinkedListTest) { + Kylin::DoublyLinkedList list2; + for (size_t i = 0; i < 5; i++) { + list2.insert(list2.length(), i + 10); + } + + list2.swap(list); + + BOOST_CHECK_EQUAL(list.size(), 5); + BOOST_CHECK_EQUAL(list2.size(), 10); + + for (size_t i = 0; i < 5; i++) { + BOOST_CHECK_EQUAL(list.at(i), i + 10); + } + + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(list2.at(i), i); + } +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexLessThenSize, DoublyLinkedListTest) { + list.insert(4, 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(4), 456); + BOOST_CHECK_EQUAL(list.at(5), 4); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexEuqalSize, DoublyLinkedListTest) { + list.insert(list.size(), 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(list.size() - 1), 456); +} + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, DoublyLinkedListTest) { + auto list2(list); + BOOST_CHECK_EQUAL(list2.size(), 10); + list[9] = 2; //测试是否为浅拷贝 + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, DoublyLinkedListTest) { + auto list2(std::move(list)); + BOOST_CHECK_EQUAL(list.empty(), true); + BOOST_CHECK_EQUAL(list2.size(), 10); + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(Iterator, DoublyLinkedListTest) { + size_t value = 0; + for (const auto &v : list) { + BOOST_CHECK_EQUAL(v, value++); + } + BOOST_CHECK_EQUAL(value, list.size()); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/DynamicArrayListTest.cpp b/UnitTest/DataStructure/DynamicArrayListTest.cpp new file mode 100644 index 0000000..7833c52 --- /dev/null +++ b/UnitTest/DataStructure/DynamicArrayListTest.cpp @@ -0,0 +1,75 @@ +#include "DynamicArrayList.h" +#include + +using namespace Kylin; + +class DynamicArrayListTest { +public: + DynamicArrayList list{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; +BOOST_AUTO_TEST_SUITE(DynamicArrayListTestCase) +BOOST_FIXTURE_TEST_CASE(At, DynamicArrayListTest) { BOOST_CHECK_EQUAL(list.at(4), 4); } + +BOOST_FIXTURE_TEST_CASE(Size, DynamicArrayListTest) { BOOST_CHECK_EQUAL(list.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Capacity, DynamicArrayListTest) { BOOST_CHECK_EQUAL(list.capacity(), 10); } + +BOOST_FIXTURE_TEST_CASE(Last, DynamicArrayListTest) { BOOST_CHECK_EQUAL(list.last(), 9); } + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, DynamicArrayListTest) { + auto list1(list); + + BOOST_CHECK_EQUAL(list1.size(), 10); + BOOST_CHECK_EQUAL(list1.capacity(), 10); + BOOST_CHECK_EQUAL(list1.at(4), 4); +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, DynamicArrayListTest) { + auto list1(std::move(list)); + + BOOST_CHECK_EQUAL(list.size(), 0); + BOOST_CHECK_EQUAL(list1.size(), 10); + + BOOST_CHECK_EQUAL(list.capacity(), 0); + BOOST_CHECK_EQUAL(list1.capacity(), 10); + + BOOST_CHECK_EQUAL(list1.at(4), 4); +} + +BOOST_FIXTURE_TEST_CASE(Append, DynamicArrayListTest) { + list.append(456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list[10], 456); + BOOST_CHECK_EQUAL(list.capacity(), 20); // 此时append会引发扩容2倍空间 +} + +BOOST_FIXTURE_TEST_CASE(Insert, DynamicArrayListTest) { + list.insert(4, 789); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list[4], 789); + BOOST_CHECK_EQUAL(list[5], 4); + BOOST_CHECK_EQUAL(list.capacity(), 20); // 此时insert会引发扩容2倍空间 +} + +BOOST_FIXTURE_TEST_CASE(RemoveAt, DynamicArrayListTest) { + list.removeAt(3); + BOOST_CHECK_EQUAL(list[3], 4); + BOOST_CHECK_EQUAL(list.length(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Clear, DynamicArrayListTest) { + list.clear(); + BOOST_CHECK_EQUAL(list.length(), 0); + BOOST_CHECK_EQUAL(list.capacity(), 10); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, DynamicArrayListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(ForEach, DynamicArrayListTest) { + size_t index = 0; + for (auto value : list) { + BOOST_CHECK_EQUAL(value, index++); + } + BOOST_CHECK_EQUAL(10, index); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/DynamicArrayTest.cpp b/UnitTest/DataStructure/DynamicArrayTest.cpp new file mode 100644 index 0000000..21af3b1 --- /dev/null +++ b/UnitTest/DataStructure/DynamicArrayTest.cpp @@ -0,0 +1,28 @@ +#include "DynamicArray.h" +#include + +using namespace Kylin; + +class DynamicArrayTest { +public: + DynamicArray array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // size:10 +}; +BOOST_AUTO_TEST_SUITE(DynamicArrayTestCase) +BOOST_FIXTURE_TEST_CASE(Size, DynamicArrayTest) { BOOST_CHECK_EQUAL(array.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(InitializerListConstructor, DynamicArrayTest) { + for (size_t i = 0; i < array.size(); i++) { + BOOST_CHECK_EQUAL(array[i], i); + } +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, DynamicArrayTest) { BOOST_CHECK_EQUAL(array.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(ForEach, DynamicArrayTest) { + size_t index = 0; + for (auto value : array) { + BOOST_CHECK_EQUAL(value, index++); + } + BOOST_CHECK_EQUAL(index, 10); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/GeneralTreeTest.cpp b/UnitTest/DataStructure/GeneralTreeTest.cpp new file mode 100644 index 0000000..c112144 --- /dev/null +++ b/UnitTest/DataStructure/GeneralTreeTest.cpp @@ -0,0 +1,84 @@ +#include "GeneralTree.h" +#include +#include + +using namespace Kylin; + +class GeneralTreeTest { +public: + GeneralTreeTest() { + auto nodeA = new GeneralTreeNode('A'); + nodeA->value = 'A'; + + tree.insert(nodeA); + + auto nodeB = tree.insert('B', nodeA); + nodeC = tree.insert('C', nodeA); + nodeD = tree.insert('D', nodeA); + + nodeE = tree.insert('E', nodeB); + /*auto nodeF =*/tree.insert('F', nodeB); + + /*auto nodeH =*/tree.insert('H', nodeD); + /*auto nodeI =*/tree.insert('I', nodeD); + /*auto nodeJ =*/tree.insert('J', nodeD); + } + char values[9]{'A', 'B', 'C', 'D', 'E', 'F', 'H', 'I', 'J'}; + GeneralTree tree; + GeneralTreeNode *nodeE = nullptr; + GeneralTreeNode *nodeC = nullptr; + GeneralTreeNode *nodeD = nullptr; +}; +BOOST_AUTO_TEST_SUITE(GeneralTreeTestCase) +BOOST_FIXTURE_TEST_CASE(Count, GeneralTreeTest) { BOOST_CHECK_EQUAL(tree.count(), 9); } + +BOOST_FIXTURE_TEST_CASE(Height, GeneralTreeTest) { BOOST_CHECK_EQUAL(tree.height(), 3); } + +BOOST_FIXTURE_TEST_CASE(Degree, GeneralTreeTest) { BOOST_CHECK_EQUAL(tree.degree(), 3); } + +BOOST_FIXTURE_TEST_CASE(FindWithValue, GeneralTreeTest) { + auto node = tree.find('H'); + BOOST_CHECK_EQUAL(node != nullptr, true); + BOOST_CHECK_EQUAL(node->value, 'H'); +} + +BOOST_FIXTURE_TEST_CASE(FindWithNode, GeneralTreeTest) { + auto result = tree.find(nodeE); + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_FIXTURE_TEST_CASE(InsertWithValue, GeneralTreeTest) { + auto nodeG = tree.insert('G', nodeC); + BOOST_CHECK_EQUAL(nodeG != nullptr, true); + BOOST_CHECK_EQUAL(nodeG->value, 'G'); +} + +BOOST_FIXTURE_TEST_CASE(InsertWithNode, GeneralTreeTest) { + auto nodeG = new GeneralTreeNode('G', nodeC); + auto result = tree.insert(nodeG); + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_FIXTURE_TEST_CASE(Clear, GeneralTreeTest) { + tree.clear(); + BOOST_CHECK_EQUAL(tree.count(), 0); +} + +BOOST_FIXTURE_TEST_CASE(RemoveWithValue, GeneralTreeTest) { + auto &&removeTree = tree.remove('D'); + BOOST_CHECK_EQUAL(removeTree.count(), 4); +} + +BOOST_FIXTURE_TEST_CASE(RemoveWithNode, GeneralTreeTest) { + auto removeTree = tree.remove(nodeD); + BOOST_CHECK_EQUAL(removeTree.count(), 4); +} + +BOOST_FIXTURE_TEST_CASE(Iterator, GeneralTreeTest) { + size_t index = 0; + for (auto v : tree) { + BOOST_CHECK_EQUAL(v, values[index++]); + } + BOOST_CHECK_EQUAL(index, 9); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/LinkedListTest.cpp b/UnitTest/DataStructure/LinkedListTest.cpp new file mode 100644 index 0000000..d01b02f --- /dev/null +++ b/UnitTest/DataStructure/LinkedListTest.cpp @@ -0,0 +1,101 @@ +#include "LinkedList.h" +#include + +using namespace Kylin; + +class LinkedListTest { +public: + LinkedList list{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_AUTO_TEST_SUITE(LinkedListTestCase) +BOOST_FIXTURE_TEST_CASE(At, LinkedListTest) { BOOST_CHECK_EQUAL(list.at(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Size, LinkedListTest) { BOOST_CHECK_EQUAL(list.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Last, LinkedListTest) { BOOST_CHECK_EQUAL(list.last(), 9); } + +BOOST_FIXTURE_TEST_CASE(EmptyListCallLastCauseException, LinkedListTest) { + LinkedList emptyList; + + BOOST_CHECK_THROW(emptyList.last(), InvalidOperationException); +} + +BOOST_FIXTURE_TEST_CASE(CallLastAfterRemoveLastElement, LinkedListTest) { + list.removeAt(list.size() - 1); + BOOST_CHECK_EQUAL(list.last(), 8); +} + +BOOST_FIXTURE_TEST_CASE(RemoveAt, LinkedListTest) { + list.removeAt(3); + BOOST_CHECK_EQUAL(list.at(3), 4); + BOOST_CHECK_EQUAL(list.length(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Clear, LinkedListTest) { + list.clear(); + BOOST_CHECK_EQUAL(list.length(), 0); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, LinkedListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Append, LinkedListTest) { + list.append(198); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(10), 198); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexLessThenSize, LinkedListTest) { + list.insert(4, 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(4), 456); + BOOST_CHECK_EQUAL(list.at(5), 4); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexEuqalSize, LinkedListTest) { + list.insert(list.size(), 456); + BOOST_CHECK_EQUAL(list.length(), 11); + BOOST_CHECK_EQUAL(list.at(list.size() - 1), 456); +} + +BOOST_FIXTURE_TEST_CASE(Swap, LinkedListTest) { + Kylin::LinkedList list2; + for (size_t i = 0; i < 5; i++) { + list2.insert(list2.length(), i + 10); + } + + list2.swap(list); + + BOOST_CHECK_EQUAL(list.size(), 5); + BOOST_CHECK_EQUAL(list2.size(), 10); + + for (size_t i = 0; i < 5; i++) { + BOOST_CHECK_EQUAL(list.at(i), i + 10); + } + + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(list2.at(i), i); + } +} + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, LinkedListTest) { + auto list2(list); + BOOST_CHECK_EQUAL(list2.size(), 10); + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, LinkedListTest) { + auto list2(std::move(list)); + BOOST_CHECK_EQUAL(list.empty(), true); + BOOST_CHECK_EQUAL(list2.size(), 10); + BOOST_CHECK_EQUAL(list2[9], 9); +} + +BOOST_FIXTURE_TEST_CASE(Iterator, LinkedListTest) { + size_t value = 0; + for (const auto &v : list) { + BOOST_CHECK_EQUAL(v, value++); + } + BOOST_CHECK_EQUAL(value, 10); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/LinkedQueueTest.cpp b/UnitTest/DataStructure/LinkedQueueTest.cpp new file mode 100644 index 0000000..57db90d --- /dev/null +++ b/UnitTest/DataStructure/LinkedQueueTest.cpp @@ -0,0 +1,56 @@ +#include "LinkedQueue.h" +#include + +using namespace Kylin; + +class LinkedQueueTest { +public: + LinkedQueue queue{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_AUTO_TEST_SUITE(LinkedQueueTestCase) +BOOST_FIXTURE_TEST_CASE(Size, LinkedQueueTest) { BOOST_CHECK_EQUAL(queue.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Head, LinkedQueueTest) { BOOST_CHECK_EQUAL(queue.head(), 0); } + +BOOST_FIXTURE_TEST_CASE(Enqueue, LinkedQueueTest) { + queue.enqueue(10); + BOOST_CHECK_EQUAL(queue.size(), 11); +} + +BOOST_FIXTURE_TEST_CASE(Dequeue, LinkedQueueTest) { + BOOST_CHECK_EQUAL(queue.dequeue(), 0); + BOOST_CHECK_EQUAL(queue.size(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Clear, LinkedQueueTest) { + queue.clear(); + BOOST_CHECK_EQUAL(queue.size(), 0); +} + +BOOST_FIXTURE_TEST_CASE(Swap, LinkedQueueTest) { + Kylin::LinkedQueue queue2; + for (size_t i = 0; i < 5; i++) { + queue2.enqueue(i + 10); + } + + queue.swap(queue2); + + BOOST_CHECK_EQUAL(queue.size(), 5); + BOOST_CHECK_EQUAL(queue2.size(), 10); + + for (size_t i = 0; i < 5; i++) { + BOOST_CHECK_EQUAL(queue.dequeue(), i + 10); + } + + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(queue2.dequeue(), i); + } +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, LinkedQueueTest) { + auto queue2(std::move(queue)); + BOOST_CHECK_EQUAL(queue.empty(), true); + BOOST_CHECK_EQUAL(queue2.size(), 10); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/LinkedStackTest.cpp b/UnitTest/DataStructure/LinkedStackTest.cpp new file mode 100644 index 0000000..3805fbf --- /dev/null +++ b/UnitTest/DataStructure/LinkedStackTest.cpp @@ -0,0 +1,39 @@ +#include "LinkedStack.h" +#include + +using namespace Kylin; + +class LinkedStackTest { +public: + LinkedStack stack{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_AUTO_TEST_SUITE(LinkedStackTestCase) +BOOST_FIXTURE_TEST_CASE(Push, LinkedStackTest) { + stack.push(123); + BOOST_CHECK_EQUAL(stack.size(), 11); +} + +BOOST_FIXTURE_TEST_CASE(Pop, LinkedStackTest) { + BOOST_CHECK_EQUAL(stack.pop(), 9); + BOOST_CHECK_EQUAL(stack.size(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Top, LinkedStackTest) { + BOOST_CHECK_EQUAL(stack.top(), 9); + BOOST_CHECK_EQUAL(stack.size(), 10); +} + +BOOST_FIXTURE_TEST_CASE(Size, LinkedStackTest) { BOOST_CHECK_EQUAL(stack.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Clear, LinkedStackTest) { + stack.clear(); + BOOST_CHECK_EQUAL(stack.size(), 0); +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, LinkedStackTest) { + auto stack2(std::move(stack)); + BOOST_CHECK_EQUAL(stack.size(), 0); + BOOST_CHECK_EQUAL(stack2.size(), 10); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/ListGraphTest.cpp b/UnitTest/DataStructure/ListGraphTest.cpp new file mode 100644 index 0000000..aacc43c --- /dev/null +++ b/UnitTest/DataStructure/ListGraphTest.cpp @@ -0,0 +1,229 @@ +#include "ListGraph.h" +#include + +using namespace Kylin; + +class ListGraphTest { +public: + void initComplexGraph() { + complexGraph.setEdge(0, 1, 10); + complexGraph.setEdge(1, 0, 10); + + complexGraph.setEdge(0, 5, 11); + complexGraph.setEdge(5, 0, 11); + + complexGraph.setEdge(1, 2, 18); + complexGraph.setEdge(2, 1, 18); + + complexGraph.setEdge(1, 8, 12); + complexGraph.setEdge(8, 1, 12); + + complexGraph.setEdge(1, 6, 16); + complexGraph.setEdge(6, 1, 16); + + complexGraph.setEdge(2, 3, 22); + complexGraph.setEdge(3, 2, 22); + + complexGraph.setEdge(2, 8, 8); + complexGraph.setEdge(8, 2, 8); + + complexGraph.setEdge(3, 8, 21); + complexGraph.setEdge(8, 3, 21); + + complexGraph.setEdge(3, 6, 24); + complexGraph.setEdge(6, 3, 24); + + complexGraph.setEdge(3, 7, 16); + complexGraph.setEdge(7, 3, 16); + + complexGraph.setEdge(3, 4, 20); + complexGraph.setEdge(4, 3, 20); + + complexGraph.setEdge(4, 5, 26); + complexGraph.setEdge(5, 4, 26); + + complexGraph.setEdge(4, 7, 7); + complexGraph.setEdge(7, 4, 7); + + complexGraph.setEdge(5, 6, 17); + complexGraph.setEdge(6, 5, 17); + + complexGraph.setEdge(6, 7, 19); + complexGraph.setEdge(7, 6, 19); + } + + void initSearchGraph() { + auto VD = "ABEDCGFHI"; + for (size_t i = 0; i < 9; i++) searchGraph.setVertex(i, VD[i]); + searchGraph.setEdge(0, 1, 0); + searchGraph.setEdge(1, 0, 0); + + searchGraph.setEdge(0, 3, 0); + searchGraph.setEdge(3, 0, 0); + + searchGraph.setEdge(0, 4, 0); + searchGraph.setEdge(4, 0, 0); + + searchGraph.setEdge(1, 2, 0); + searchGraph.setEdge(2, 1, 0); + + searchGraph.setEdge(1, 4, 0); + searchGraph.setEdge(4, 1, 0); + + searchGraph.setEdge(2, 5, 0); + searchGraph.setEdge(5, 2, 0); + + searchGraph.setEdge(3, 6, 0); + searchGraph.setEdge(6, 3, 0); + + searchGraph.setEdge(4, 6, 0); + searchGraph.setEdge(6, 4, 0); + + searchGraph.setEdge(6, 7, 0); + searchGraph.setEdge(7, 6, 0); + + searchGraph.setEdge(7, 8, 0); + searchGraph.setEdge(8, 7, 0); + } + + void initPathGraph() { + pathGraph.setEdge(0, 1, 10); + pathGraph.setEdge(0, 3, 30); + pathGraph.setEdge(0, 4, 100); + + pathGraph.setEdge(1, 2, 50); + + pathGraph.setEdge(2, 4, 10); + + pathGraph.setEdge(3, 2, 20); + pathGraph.setEdge(3, 4, 60); + } + ListGraphTest() { + graph.addVertex('A'); + graph.addVertex('B'); + graph.addVertex('C'); + graph.addVertex('D'); + + graph.setEdge(0, 1, 5); + graph.setEdge(0, 3, 6); + graph.setEdge(1, 2, 8); + graph.setEdge(2, 3, 2); + graph.setEdge(3, 1, 9); + + initSearchGraph(); + initComplexGraph(); + initPathGraph(); + } + + ListGraph graph{0}; + ListGraph complexGraph{9}; + ListGraph searchGraph{9}; + ListGraph pathGraph{5}; +}; + +BOOST_FIXTURE_TEST_CASE(Vertex, ListGraphTest) { BOOST_CHECK_EQUAL(graph.vertex(2), 'C'); } + +BOOST_FIXTURE_TEST_CASE(SetVertex, ListGraphTest) { + graph.setVertex(2, 'Z'); + BOOST_CHECK_EQUAL(graph.vertex(2), 'Z'); +} + +BOOST_FIXTURE_TEST_CASE(Adjacent, ListGraphTest) { + auto adjacent = graph.adjacent(0); + BOOST_CHECK_EQUAL(adjacent.size(), 2); + BOOST_CHECK_EQUAL(adjacent[0], 3); + BOOST_CHECK_EQUAL(adjacent[1], 1); +} + +BOOST_FIXTURE_TEST_CASE(Edge1, ListGraphTest) { BOOST_CHECK_EQUAL(*graph.edge(1, 2), 8); } + +BOOST_FIXTURE_TEST_CASE(SetEdge, ListGraphTest) { + BOOST_CHECK_EQUAL(graph.setEdge(1, 3, 123), true); + BOOST_CHECK_EQUAL(*(graph.edge(1, 3)), 123); +} + +BOOST_FIXTURE_TEST_CASE(RemoveEdge, ListGraphTest) { + graph.removeEdge(3, 1); + BOOST_CHECK_EQUAL(graph.edgeCount(), 4); + BOOST_CHECK_EQUAL(static_cast(graph.edge(3, 1)), false); +} + +BOOST_FIXTURE_TEST_CASE(VertexCount, ListGraphTest) { + BOOST_CHECK_EQUAL(graph.vertexCount(), 4); + BOOST_CHECK_EQUAL(complexGraph.vertexCount(), 9); +} + +BOOST_FIXTURE_TEST_CASE(EdgeCount, ListGraphTest) { BOOST_CHECK_EQUAL(graph.edgeCount(), 5); } + +BOOST_FIXTURE_TEST_CASE(OutDegree, ListGraphTest) { BOOST_CHECK_EQUAL(graph.outDegree(1), 1); } + +BOOST_FIXTURE_TEST_CASE(InDegree, ListGraphTest) { BOOST_CHECK_EQUAL(graph.inDegree(1), 2); } + +BOOST_FIXTURE_TEST_CASE(Degree, ListGraphTest) { BOOST_CHECK_EQUAL(graph.degree(1), 3); } + +BOOST_FIXTURE_TEST_CASE(RemoveVertex, ListGraphTest) { + graph.removeVertex(); + BOOST_CHECK_EQUAL(graph.edgeCount(), 2); +} + +BOOST_FIXTURE_TEST_CASE(BreadthFirstSearch, ListGraphTest) { + auto sa = searchGraph.breadthFirstSearch(0); + size_t searchIndex[9]{0, 4, 3, 1, 6, 2, 7, 5, 8}; + for (size_t i = 0; i < sa.length(); i++) { + BOOST_CHECK_EQUAL(sa[i], searchIndex[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(DepthFirstSearch, ListGraphTest) { + auto sa = searchGraph.depthFirstSearch(0); + size_t searchIndex[9]{0, 1, 2, 5, 4, 6, 3, 7, 8}; + for (size_t i = 0; i < sa.length(); i++) { + BOOST_CHECK_EQUAL(sa[i], searchIndex[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Prim, ListGraphTest) { + auto edges = complexGraph.prim(10000); + size_t cost = 0; + + for (size_t i = 0; i < edges.size(); i++) { + cost += edges[i].value; + } + BOOST_CHECK_EQUAL(cost, 99); +} + +BOOST_FIXTURE_TEST_CASE(Kruskai, ListGraphTest) { + + auto edges = complexGraph.kruskal(); + size_t cost = 0; + + for (size_t i = 0; i < edges.length(); i++) { + cost += edges[i].value; + } + BOOST_CHECK_EQUAL(cost, 99); +} + +BOOST_FIXTURE_TEST_CASE(Dijsktra, ListGraphTest) { + size_t paths[]{0, 3, 2, 4}; + auto path = pathGraph.dijkstra(0, 4, 10000); + BOOST_CHECK_EQUAL(path.size(), 4); + for (size_t i = 0; i < 4; i++) { + BOOST_CHECK_EQUAL(path[i], paths[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Floy, ListGraphTest) { + ListGraph graph(3); + graph.setEdge(0, 1, 4); + graph.setEdge(0, 2, 11); + graph.setEdge(1, 2, 2); + graph.setEdge(1, 0, 6); + graph.setEdge(2, 0, 3); + + size_t paths[]{0, 1, 2}; + auto path = graph.floyd(0, 2, 10000); + BOOST_CHECK_EQUAL(path.size(), 3); + for (size_t i = 0; i < 3; i++) { + BOOST_CHECK_EQUAL(path[i], paths[i]); + } +} diff --git a/UnitTest/DataStructure/MatrixGraphTest.cpp b/UnitTest/DataStructure/MatrixGraphTest.cpp new file mode 100644 index 0000000..e0c8f73 --- /dev/null +++ b/UnitTest/DataStructure/MatrixGraphTest.cpp @@ -0,0 +1,73 @@ +#include "MatrixGraph.h" +#include + +using namespace Kylin; + +class MatrixGraphTest { +public: + MatrixGraphTest() { + + graph.setVertex(2, 2); + + graph.setEdge(0, 1, 1); + graph.setEdge(1, 0, 1); + + graph.setEdge(0, 2, 3); + graph.setEdge(2, 0, 3); + + graph.setEdge(1, 2, 1); + graph.setEdge(2, 1, 1); + + graph.setEdge(1, 3, 4); + graph.setEdge(3, 1, 4); + + graph.setEdge(2, 3, 1); + graph.setEdge(3, 2, 1); + } + MatrixGraph<4, size_t, size_t> graph; +}; +BOOST_AUTO_TEST_SUITE(MatrixGraphTestCase) +BOOST_FIXTURE_TEST_CASE(Vertex, MatrixGraphTest) { BOOST_CHECK_EQUAL(graph.vertex(2), 2); } + +BOOST_FIXTURE_TEST_CASE(SetVertex, MatrixGraphTest) { + graph.setVertex(2, 250); + BOOST_CHECK_EQUAL(graph.vertex(2), 250); +} + +BOOST_FIXTURE_TEST_CASE(Adjacent, MatrixGraphTest) { + size_t adjacents[3]{0, 1, 3}; + auto adjacent = graph.adjacent(2); + BOOST_CHECK_EQUAL(adjacent.size(), 3); + size_t i = 0; + for (auto adj : adjacent) { + BOOST_CHECK_EQUAL(adj, adjacents[i++]); + } +} + +BOOST_FIXTURE_TEST_CASE(Edge1, MatrixGraphTest) { + auto edge = graph.edge(1, 3); + BOOST_CHECK_EQUAL(static_cast(edge), true); + BOOST_CHECK_EQUAL(*edge, 4); +} + +BOOST_FIXTURE_TEST_CASE(SetEdge, MatrixGraphTest) { + BOOST_CHECK_EQUAL(graph.setEdge(1, 3, 8), true); + BOOST_CHECK_EQUAL(*(graph.edge(1, 3)), 8); +} + +BOOST_FIXTURE_TEST_CASE(RemoveEdge, MatrixGraphTest) { + BOOST_CHECK_EQUAL(graph.removeEdge(1, 3), true); + BOOST_CHECK_EQUAL(graph.edgeCount(), 9); + BOOST_CHECK_EQUAL(static_cast(graph.edge(1, 3)), false); +} + +BOOST_FIXTURE_TEST_CASE(VertexCount, MatrixGraphTest) { BOOST_CHECK_EQUAL(graph.vertexCount(), 4); } + +BOOST_FIXTURE_TEST_CASE(EdgeCount, MatrixGraphTest) { BOOST_CHECK_EQUAL(graph.edgeCount(), 10); } + +BOOST_FIXTURE_TEST_CASE(OutDegree, MatrixGraphTest) { BOOST_CHECK_EQUAL(graph.outDegree(2), 3); } + +BOOST_FIXTURE_TEST_CASE(InDegree, MatrixGraphTest) { BOOST_CHECK_EQUAL(graph.inDegree(2), 3); } + +BOOST_FIXTURE_TEST_CASE(Degree, MatrixGraphTest) { BOOST_CHECK_EQUAL(graph.degree(2), 6); } +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/QueueToStackTest.cpp b/UnitTest/DataStructure/QueueToStackTest.cpp new file mode 100644 index 0000000..d8c138e --- /dev/null +++ b/UnitTest/DataStructure/QueueToStackTest.cpp @@ -0,0 +1,33 @@ +#include "QueueToStack.h" +#include + +using namespace Kylin; + +class QueueToStackTest { +public: + QueueToStack stack{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_AUTO_TEST_SUITE(QueueToStackTestCase) +BOOST_FIXTURE_TEST_CASE(Push, QueueToStackTest) { + stack.push(123); + BOOST_CHECK_EQUAL(stack.size(), 11); +} + +BOOST_FIXTURE_TEST_CASE(Pop, QueueToStackTest) { + BOOST_CHECK_EQUAL(stack.pop(), 9); + BOOST_CHECK_EQUAL(stack.size(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Top, QueueToStackTest) { + BOOST_CHECK_EQUAL(stack.top(), 9); + BOOST_CHECK_EQUAL(stack.size(), 10); +} + +BOOST_FIXTURE_TEST_CASE(Size, QueueToStackTest) { BOOST_CHECK_EQUAL(stack.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Clear, QueueToStackTest) { + stack.clear(); + BOOST_CHECK_EQUAL(stack.size(), 0); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/SmartPointerTest.cpp b/UnitTest/DataStructure/SmartPointerTest.cpp new file mode 100644 index 0000000..057f21f --- /dev/null +++ b/UnitTest/DataStructure/SmartPointerTest.cpp @@ -0,0 +1,64 @@ +#include "KylinSmartPointer.h" +#include "SharedPointer.h" +#include + +using namespace Kylin; + +class SmartPointerTest { +public: + class TestObject { + public: + TestObject(bool &status) : m_status(status) {} + ~TestObject() { m_status = false; } + bool &m_status; + }; + + bool status = true; +}; + +BOOST_FIXTURE_TEST_CASE(exampleOne, SmartPointerTest) { + { Kylin::SmartPointer pointer(new TestObject(status)); } + BOOST_CHECK_EQUAL(status, false); +} + +BOOST_FIXTURE_TEST_CASE(Move, SmartPointerTest) { + { + SmartPointer pointer(new TestObject(status)); + auto p1 = std::move(pointer); + BOOST_CHECK_EQUAL(pointer.isNull(), true); + } + BOOST_CHECK_EQUAL(status, false); +} + +class SharedPointerTest { +public: + class TestObject { + public: + TestObject(bool &status) : m_status(status) {} + ~TestObject() { m_status = false; } + bool &m_status; + }; + + bool status = true; +}; + +BOOST_FIXTURE_TEST_CASE(example1, SharedPointerTest) { + { SharedPointer pointer(new TestObject(status)); } + BOOST_CHECK_EQUAL(status, false); +} + +BOOST_FIXTURE_TEST_CASE(Count, SharedPointerTest) { + { + SharedPointer pointer(new TestObject(status)); + { auto p1 = pointer; } + BOOST_CHECK_EQUAL(status, true); + } + + BOOST_CHECK_EQUAL(status, false); +} + +BOOST_FIXTURE_TEST_CASE(Equal, SharedPointerTest) { + SharedPointer pointer(new TestObject(status)); + auto p1 = pointer; + BOOST_TEST((pointer == p1)); +} diff --git a/UnitTest/DataStructure/SortTest.cpp b/UnitTest/DataStructure/SortTest.cpp new file mode 100644 index 0000000..fcdf37d --- /dev/null +++ b/UnitTest/DataStructure/SortTest.cpp @@ -0,0 +1,68 @@ +#include "Sort.h" +#include "DynamicArray.h" +#include "SharedPointer.h" +#include + +using namespace Kylin; + +class SortTest { +public: + size_t unsort[10] = {84, 102, 5, 60, 78, 14, 66, 60, 11, 86}; + size_t sort[10] = {5, 11, 14, 60, 60, 66, 78, 84, 86, 102}; +}; + +BOOST_FIXTURE_TEST_CASE(Select, SortTest) { + Sort::select(unsort, 10); + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(unsort[i], sort[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Insert, SortTest) { + Sort::insert(unsort, 10); + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(unsort[i], sort[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Bubble, SortTest) { + Sort::bubble(unsort, 10); + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(unsort[i], sort[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Shell, SortTest) { + Sort::shell(unsort, 10); + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(unsort[i], sort[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Quick, SortTest) { + Sort::quick(unsort, 10); + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(unsort[i], sort[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(Merge, SortTest) { + Sort::merge(unsort, 10); + for (size_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(unsort[i], sort[i]); + } +} + +// class Data{ +// public: +// size_t id; +// double data1[1000]; +// size_t data2[1000]; +// float data3[1000]; +//}; + +// TEST(Sort,large_data) { +//// Data data[1000]; +//// for(size_t i=0;i<1000;i++) data[i].id = i; + +//} diff --git a/UnitTest/DataStructure/StackToQueueTest.cpp b/UnitTest/DataStructure/StackToQueueTest.cpp new file mode 100644 index 0000000..8fe91ce --- /dev/null +++ b/UnitTest/DataStructure/StackToQueueTest.cpp @@ -0,0 +1,29 @@ +#include + +#include "StackToQueue.h" + +using namespace Kylin; + +class StackToQueueTest { +public: + StackToQueue queue{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +}; + +BOOST_FIXTURE_TEST_CASE(Size, StackToQueueTest) { BOOST_CHECK_EQUAL(queue.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Head, StackToQueueTest) { BOOST_CHECK_EQUAL(queue.head(), 0); } + +BOOST_FIXTURE_TEST_CASE(Enqueue, StackToQueueTest) { + queue.enqueue(10); + BOOST_CHECK_EQUAL(queue.size(), 11); +} + +BOOST_FIXTURE_TEST_CASE(Dequeue, StackToQueueTest) { + BOOST_CHECK_EQUAL(queue.dequeue(), 0); + BOOST_CHECK_EQUAL(queue.size(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Clear, StackToQueueTest) { + queue.clear(); + BOOST_CHECK_EQUAL(queue.size(), 0); +} diff --git a/UnitTest/DataStructure/StaticArrayListTest.cpp b/UnitTest/DataStructure/StaticArrayListTest.cpp new file mode 100644 index 0000000..3ef6916 --- /dev/null +++ b/UnitTest/DataStructure/StaticArrayListTest.cpp @@ -0,0 +1,66 @@ +#include + +#include "StaticArrayList.h" + +using namespace Kylin; + +class StaticArrayListTest { +public: + StaticArrayListTest() { + for (size_t i = 0; i < 8; i++) { + list.insert(list.length(), i); + } + } + StaticArrayList list; +}; +BOOST_AUTO_TEST_SUITE(StaticArrayListTestCase) +BOOST_FIXTURE_TEST_CASE(Size, StaticArrayListTest) { BOOST_CHECK_EQUAL(list.size(), 8); } + +BOOST_FIXTURE_TEST_CASE(Capacity, StaticArrayListTest) { BOOST_CHECK_EQUAL(list.capacity(), 10); } + +BOOST_FIXTURE_TEST_CASE(Last, StaticArrayListTest) { BOOST_CHECK_EQUAL(list.last(), 7); } + +BOOST_FIXTURE_TEST_CASE(At, StaticArrayListTest) { BOOST_CHECK_EQUAL(list.at(4), 4); } + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, StaticArrayListTest) { + auto list1 = list; + BOOST_CHECK_EQUAL(list1.size(), 8); + BOOST_CHECK_EQUAL(list1.capacity(), 10); + BOOST_CHECK_EQUAL(list1.at(4), 4); +} + +BOOST_FIXTURE_TEST_CASE(Append, StaticArrayListTest) { + list.append(456); + BOOST_CHECK_EQUAL(list.length(), 9); + BOOST_CHECK_EQUAL(list[8], 456); +} + +BOOST_FIXTURE_TEST_CASE(Insert, StaticArrayListTest) { + list.insert(4, 789); + BOOST_CHECK_EQUAL(list.length(), 9); + BOOST_CHECK_EQUAL(list[4], 789); + BOOST_CHECK_EQUAL(list[5], 4); +} + +BOOST_FIXTURE_TEST_CASE(RemoveAt, StaticArrayListTest) { + list.removeAt(3); + BOOST_CHECK_EQUAL(list[3], 4); + BOOST_CHECK_EQUAL(list.length(), 7); +} + +BOOST_FIXTURE_TEST_CASE(Clear, StaticArrayListTest) { + list.clear(); + BOOST_CHECK_EQUAL(list.length(), 0); + BOOST_CHECK_EQUAL(list.capacity(), 10); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, StaticArrayListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(ForEach, StaticArrayListTest) { + size_t index = 0; + for (auto value : list) { + BOOST_CHECK_EQUAL(value, index++); + } + BOOST_CHECK_EQUAL(8, index); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/StaticArrayTest.cpp b/UnitTest/DataStructure/StaticArrayTest.cpp new file mode 100644 index 0000000..c03e668 --- /dev/null +++ b/UnitTest/DataStructure/StaticArrayTest.cpp @@ -0,0 +1,38 @@ +#include "StaticArray.h" +#include + +using namespace Kylin; + +class StaticArrayTest { +public: + Kylin::StaticArray array; +}; +BOOST_AUTO_TEST_SUITE(StaticArrayTestCase) +BOOST_FIXTURE_TEST_CASE(Size, StaticArrayTest) { BOOST_CHECK_EQUAL(array.size(), 10); } + +BOOST_FIXTURE_TEST_CASE(Length, StaticArrayTest) { BOOST_CHECK_EQUAL(array.length(), 10); } + +BOOST_FIXTURE_TEST_CASE(At, StaticArrayTest) { + array[3] = 5; + BOOST_CHECK_EQUAL(array.at(3), 5); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, StaticArrayTest) { + array[3] = 5; + BOOST_CHECK_EQUAL(array.indexOf(5), 3); +} + +BOOST_FIXTURE_TEST_CASE(ForEach, StaticArrayTest) { + size_t index = 0; + for (auto &value : array) { + value = index++; + } + BOOST_CHECK_EQUAL(index, 10); + + index = 0; + for (auto value : array) { + BOOST_CHECK_EQUAL(value, index++); + } + BOOST_CHECK_EQUAL(index, 10); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/StaticLinkedListTest.cpp b/UnitTest/DataStructure/StaticLinkedListTest.cpp new file mode 100644 index 0000000..214a5b2 --- /dev/null +++ b/UnitTest/DataStructure/StaticLinkedListTest.cpp @@ -0,0 +1,80 @@ +#include "StaticLinkedList.h" +#include + +using namespace Kylin; + +class StaticLinkedListTest { +public: + StaticLinkedListTest() { + for (size_t i = 0; i < 8; i++) { + list.append(i); + } + } + StaticLinkedList list; +}; +BOOST_AUTO_TEST_SUITE(StaticLinkedListTestCase) +BOOST_FIXTURE_TEST_CASE(At, StaticLinkedListTest) { BOOST_CHECK_EQUAL(list.at(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Size, StaticLinkedListTest) { BOOST_CHECK_EQUAL(list.size(), 8); } + +BOOST_FIXTURE_TEST_CASE(Last, StaticLinkedListTest) { BOOST_CHECK_EQUAL(list.last(), 7); } + +BOOST_FIXTURE_TEST_CASE(EmptyListCallLastCauseException, StaticLinkedListTest) { + StaticLinkedList emptyList; + BOOST_CHECK_THROW(emptyList.last(), InvalidOperationException); +} + +BOOST_FIXTURE_TEST_CASE(RemoveAt, StaticLinkedListTest) { + list.removeAt(3); + BOOST_CHECK_EQUAL(list.at(3), 4); + BOOST_CHECK_EQUAL(list.length(), 7); +} + +BOOST_FIXTURE_TEST_CASE(Clear, StaticLinkedListTest) { + list.clear(); + BOOST_CHECK_EQUAL(list.length(), 0); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, StaticLinkedListTest) { BOOST_CHECK_EQUAL(list.indexOf(5), 5); } + +BOOST_FIXTURE_TEST_CASE(Append, StaticLinkedListTest) { + list.append(198); + BOOST_CHECK_EQUAL(list.length(), 9); + BOOST_CHECK_EQUAL(list.at(8), 198); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexLessThenSize, StaticLinkedListTest) { + list.insert(4, 456); + BOOST_CHECK_EQUAL(list.length(), 9); + BOOST_CHECK_EQUAL(list.at(4), 456); + BOOST_CHECK_EQUAL(list.at(5), 4); +} + +BOOST_FIXTURE_TEST_CASE(InsertToIndexEuqalSize, StaticLinkedListTest) { + list.insert(list.size(), 456); + BOOST_CHECK_EQUAL(list.length(), 9); + BOOST_CHECK_EQUAL(list.at(list.size() - 1), 456); +} + +BOOST_FIXTURE_TEST_CASE(Swap, StaticLinkedListTest) { + StaticLinkedList list2; + for (size_t i = 0; i < 5; i++) { + list2.insert(list2.length(), i + 10); + } + BOOST_CHECK_THROW(list2.swap(list), InvalidOperationException); +} + +BOOST_FIXTURE_TEST_CASE(CopyConstructor, StaticLinkedListTest) { + auto list2(list); + BOOST_CHECK_EQUAL(list2.size(), 8); + BOOST_CHECK_EQUAL(list2[5], 5); +} + +BOOST_FIXTURE_TEST_CASE(Iterator, StaticLinkedListTest) { + size_t value = 0; + for (const auto &v : list) { + BOOST_CHECK_EQUAL(v, value++); + } + BOOST_CHECK_EQUAL(value, 8); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/StaticQueueTest.cpp b/UnitTest/DataStructure/StaticQueueTest.cpp new file mode 100644 index 0000000..becccc7 --- /dev/null +++ b/UnitTest/DataStructure/StaticQueueTest.cpp @@ -0,0 +1,36 @@ +#include "StaticQueue.h" +#include + +using namespace Kylin; + +class StaticQueueTest { +public: + StaticQueue queue; + StaticQueueTest() { + for (size_t i = 0; i < 8; i++) { + queue.enqueue(i); + } + } +}; +BOOST_AUTO_TEST_SUITE(StaticQueueTestCase) +BOOST_FIXTURE_TEST_CASE(Size, StaticQueueTest) { BOOST_CHECK_EQUAL(queue.size(), 8); } + +BOOST_FIXTURE_TEST_CASE(Capacity, StaticQueueTest) { BOOST_CHECK_EQUAL(queue.capacity(), 10); } + +BOOST_FIXTURE_TEST_CASE(Head, StaticQueueTest) { BOOST_CHECK_EQUAL(queue.head(), 0); } + +BOOST_FIXTURE_TEST_CASE(Enqueue, StaticQueueTest) { + queue.enqueue(8); + BOOST_CHECK_EQUAL(queue.size(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Dequeue, StaticQueueTest) { + BOOST_CHECK_EQUAL(queue.dequeue(), 0); + BOOST_CHECK_EQUAL(queue.size(), 7); +} + +BOOST_FIXTURE_TEST_CASE(Clear, StaticQueueTest) { + queue.clear(); + BOOST_CHECK_EQUAL(queue.size(), 0); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/StaticStackTest.cpp b/UnitTest/DataStructure/StaticStackTest.cpp new file mode 100644 index 0000000..a4ec3f7 --- /dev/null +++ b/UnitTest/DataStructure/StaticStackTest.cpp @@ -0,0 +1,38 @@ +#include + +#include "StaticStack.h" + +class StaticStackTest { +public: + Kylin::StaticStack stack; + StaticStackTest() { + for (size_t i = 0; i < 8; i++) { + stack.push(i); + } + } +}; +BOOST_AUTO_TEST_SUITE(StaticStackTestCase) +BOOST_FIXTURE_TEST_CASE(Push, StaticStackTest) { + stack.push(8); + BOOST_CHECK_EQUAL(stack.size(), 9); +} + +BOOST_FIXTURE_TEST_CASE(Pop, StaticStackTest) { + BOOST_CHECK_EQUAL(stack.pop(), 7); + BOOST_CHECK_EQUAL(stack.size(), 7); +} + +BOOST_FIXTURE_TEST_CASE(Top, StaticStackTest) { + BOOST_CHECK_EQUAL(stack.top(), 7); + BOOST_CHECK_EQUAL(stack.size(), 8); +} + +BOOST_FIXTURE_TEST_CASE(Size, StaticStackTest) { BOOST_CHECK_EQUAL(stack.size(), 8); } + +BOOST_FIXTURE_TEST_CASE(Clear, StaticStackTest) { + stack.clear(); + BOOST_CHECK_EQUAL(stack.size(), 0); +} + +BOOST_FIXTURE_TEST_CASE(Capacity, StaticStackTest) { BOOST_CHECK_EQUAL(stack.capacity(), 10); } +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/DataStructure/StringTest.cpp b/UnitTest/DataStructure/StringTest.cpp new file mode 100644 index 0000000..231a11a --- /dev/null +++ b/UnitTest/DataStructure/StringTest.cpp @@ -0,0 +1,74 @@ +#include "KylinString.h" +#include + +using namespace Kylin; + +class StringTest { +public: + std::string utf8String = "我爱你"; + String str{"Hello World!"}; // length: 12 + String spaceStr{" Hello World! "}; + const size_t length = 12; +}; + +BOOST_AUTO_TEST_SUITE(StringTestCase) +BOOST_FIXTURE_TEST_CASE(Length, StringTest) { + BOOST_CHECK_EQUAL(str.length(), length); +} + +BOOST_FIXTURE_TEST_CASE(Equal, StringTest) { + BOOST_CHECK_EQUAL(str, "Hello World!"); +} + +BOOST_FIXTURE_TEST_CASE(MoveConstructor, StringTest) { + String str1(std::move(str)); + BOOST_CHECK_EQUAL(str.length(), 0); + BOOST_CHECK_EQUAL(str1.length(), length); + BOOST_CHECK_EQUAL(str1, "Hello World!"); +} + +BOOST_FIXTURE_TEST_CASE(Add, StringTest) { + BOOST_CHECK_EQUAL(str + "World", "Hello World!World"); +} + +BOOST_FIXTURE_TEST_CASE(StartWith, StringTest) { + BOOST_CHECK_EQUAL(str.startWith("Hell"), true); + BOOST_CHECK_EQUAL(str.startWith("rld"), false); +} + +BOOST_FIXTURE_TEST_CASE(EndOf, StringTest) { + BOOST_CHECK_EQUAL(str.endOf("rld!"), true); + BOOST_CHECK_EQUAL(str.endOf("Hell"), false); +} + +BOOST_FIXTURE_TEST_CASE(Insert, StringTest) { + BOOST_CHECK_EQUAL(str.insert(5, " kylin"), "Hello kylin World!"); +} + +BOOST_FIXTURE_TEST_CASE(Trim, StringTest) { + BOOST_CHECK_EQUAL(spaceStr.trim(), str); +} + +BOOST_FIXTURE_TEST_CASE(IndexOf, StringTest) { + BOOST_CHECK_EQUAL(str.indexOf("llo"), 2); +} + +BOOST_FIXTURE_TEST_CASE(Remove, StringTest) { + BOOST_CHECK_EQUAL(str.remove("llo"), "He World!"); +} + +BOOST_FIXTURE_TEST_CASE(Replace, StringTest) { + BOOST_CHECK_EQUAL(str.replace("llo", "kylin") == "Hekylin World!", true); +} + +BOOST_FIXTURE_TEST_CASE(Substr, StringTest) { + BOOST_CHECK_EQUAL(str.substr(3, 4), "lo W"); +} + +BOOST_FIXTURE_TEST_CASE(sunday, StringTest) { + BOOST_CHECK_EQUAL(Kylin::String::sunday("Hello World", "Hello World"), 0); + BOOST_CHECK_EQUAL(Kylin::String::sunday("Hello World", "o W"), 4); + BOOST_CHECK_EQUAL(Kylin::String::sunday("Hello World", "o W1"), -1); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/UnitTest/Universal/BoostLogTest.cpp b/UnitTest/Universal/BoostLogTest.cpp new file mode 100644 index 0000000..c0e13ec --- /dev/null +++ b/UnitTest/Universal/BoostLogTest.cpp @@ -0,0 +1,7 @@ +#include "BoostLog.h" +#include + +BOOST_AUTO_TEST_CASE(BoostLogTest) { + boost::log::initialize(); + LOG(info) << "this is a test output."; +} \ No newline at end of file diff --git a/Universal/BoostLog.cpp b/Universal/BoostLog.cpp index 5fd5608..cd5e93e 100644 --- a/Universal/BoostLog.cpp +++ b/Universal/BoostLog.cpp @@ -17,7 +17,9 @@ BOOST_LOG_GLOBAL_LOGGER_INIT(location_logger, LocationLogger(LOG_FILTER_LEVEL)); +void initialize(const std::string &filename = "logs/app", const std::string &target = "logs", + trivial::severity_level filter = static_cast(LOG_FILTER_LEVEL)); +} // namespace log +} // namespace boost namespace AmassKeywords {