Add unit test.

This commit is contained in:
luocai 2023-12-27 10:29:16 +08:00
parent a7442cb0ca
commit e68f8d5a3a
70 changed files with 6752 additions and 7 deletions

View File

@ -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)

50
DataStructure/Array.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef ARRAY_H
#define ARRAY_H
#include "Exception.h"
#include "Object.h"
#include "RandomIterator.h"
namespace Kylin {
template <typename T>
class Array : public Object {
public:
using Iterator = RandomIterator<T>;
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<size_t>(-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<Array *>(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

65
DataStructure/ArrayList.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef SEQLIST_H
#define SEQLIST_H
#include "Exception.h"
#include "List.h"
#include "RandomIterator.h"
namespace Kylin {
template <typename T>
class ArrayList : public List<T> {
public:
static const size_t npos = static_cast<size_t>(-1);
using Iterator = RandomIterator<T>;
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<int>(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

View File

@ -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 <typename T>
class BinarySearchTree : public BinaryTree<T> {
public:
using NodeT = BinaryTreeNode<T>;
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<NodeT *>(pos->parent)->right == pos))
pos = dynamic_cast<NodeT *>(pos->parent);
pos = dynamic_cast<NodeT *>(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<T> *find(const T &value) const override {
return find(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), value);
}
T maximum() {
auto node = maximumOfNode(dynamic_cast<BinaryTreeNode<T> *>(this->m_root));
if (node != nullptr)
return node->value;
else
return T();
}
T minimum() {
auto node = minimumOfNode(dynamic_cast<BinaryTreeNode<T> *>(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<T> *predecessor(BinaryTreeNode<T> *node) {
if (node == nullptr) return node;
if (node->left != nullptr) return maximumOfNode(node->left);
auto parent = dynamic_cast<BinaryTreeNode<T> *>(node->parent);
while ((parent != nullptr) && (parent->left == node)) {
node = parent;
parent = dynamic_cast<BinaryTreeNode<T> *>(node->parent);
}
return parent;
}
/**
* @brief successor Find the mininum node which these node are bigger than arg node.
* @param node
* @return
*/
BinaryTreeNode<T> *successor(BinaryTreeNode<T> *node) {
if (node == nullptr) return node;
if (node->right != nullptr) return minimumOfNode(node->right);
auto parent = dynamic_cast<BinaryTreeNode<T> *>(node->parent);
if (node->right == nullptr && parent->left == node) return parent;
while ((parent != nullptr) && (parent->right == node)) {
node = parent;
parent = dynamic_cast<BinaryTreeNode<T> *>(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<T> *node = find(value);
if (node == nullptr) return;
auto del = remove(node, dynamic_cast<BinaryTreeNode<T> *>(this->m_root));
if (del != nullptr) delete del;
}
protected:
/**
* @brief find
* @param node the root of sub-tree
* @param value
* @return
*/
BinaryTreeNode<T> *find(BinaryTreeNode<T> *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<T> *find1(BinaryTreeNode<T> *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<T> *maximumOfNode(BinaryTreeNode<T> *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<T> *minimumOfNode(BinaryTreeNode<T> *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<NodeT **>(&(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<T> *remove(BinaryTreeNode<T> *node, BinaryTreeNode<T> *tree) {
auto parent = dynamic_cast<BinaryTreeNode<T> *>(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<T> *del = nullptr;
BinaryTreeNode<T> *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

412
DataStructure/BinaryTree.h Normal file
View File

@ -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 <typename T>
class BinaryTreeNode : public TreeNode<T> {
public:
BinaryTreeNode(const T &value, BinaryTreeNode *parent = nullptr) : TreeNode<T>(value, parent) {}
BinaryTreeNode *left = nullptr;
BinaryTreeNode *right = nullptr;
};
template <typename T>
class BinaryTree : public Tree<T> {
public:
enum Pos { //子树节点位置
Any,
Left,
Right
};
enum Traversal { //遍历顺序
Preorder, //先序遍历
Inorder, //中序遍历
Postorder, //后续遍历
Levelorder //层次遍历
};
class Iterator {
public:
Iterator(BinaryTreeNode<T> *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<T> *m_pos = nullptr;
LinkedQueue<BinaryTreeNode<T> *> m_queue;
};
BinaryTree() = default;
BinaryTree(const BinaryTree &other) { this->m_root = clone(dynamic_cast<BinaryTreeNode<T> *>(other.m_root)); }
BinaryTree(BinaryTree &&other) {
this->m_root = other.m_root;
other.m_root = nullptr;
}
~BinaryTree() { clear(); }
virtual BinaryTreeNode<T> *root() const { return dynamic_cast<BinaryTreeNode<T> *>(this->m_root); }
int degree() const { return degree(dynamic_cast<BinaryTreeNode<T> *>(this->m_root)); }
int height() const { return height(dynamic_cast<BinaryTreeNode<T> *>(this->m_root)); }
int count() const { return count(dynamic_cast<BinaryTreeNode<T> *>(this->m_root)); }
void clear() {
free(dynamic_cast<BinaryTreeNode<T> *>(this->m_root));
this->m_root = nullptr;
}
BinaryTree operator+(const BinaryTree &other) {
BinaryTree result;
result.m_root =
add(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), dynamic_cast<BinaryTreeNode<T> *>(other.m_root));
return result;
}
BinaryTree<T> &operator=(const BinaryTree &other) {
if (&other != this) {
clear();
this->m_root = clone(other.m_root);
}
return *this;
}
bool operator==(const BinaryTree<T> &other) const {
return equal(dynamic_cast<const BinaryTreeNode<T> *>(this->m_root),
dynamic_cast<const BinaryTreeNode<T> *>(other.m_root));
}
bool operator!=(const BinaryTree<T> &other) const { return !(*this == other); }
DynamicArray<T> traversal(Traversal order) {
LinkedQueue<BinaryTreeNode<T> *> queue;
traversal(order, queue);
auto size = queue.size();
DynamicArray<T> result(size);
for (size_t i = 0; i < size; i++) {
result[i] = queue.dequeue()->value;
}
return result;
}
bool insert(TreeNode<T> *node) override { return insert(node, Any); }
virtual bool insert(TreeNode<T> *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<BinaryTreeNode<T> *>(node), dynamic_cast<BinaryTreeNode<T> *>(node->parent), pos);
}
bool insert(const T &value, TreeNode<T> *parent, Pos pos) {
bool ret = false;
auto n = new BinaryTreeNode<T>(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<T> *find(const T &value) const {
return find(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), value);
}
bool find(TreeNode<T> *node) const {
return find(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), dynamic_cast<BinaryTreeNode<T> *>(node));
}
BinaryTree<T> remove(const T &value) {
auto node = find(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), value);
if (node == nullptr) return BinaryTree<T>();
auto parent = dynamic_cast<BinaryTreeNode<T> *>(node->parent);
if (parent->left == node) {
parent->left = nullptr;
} else if (parent->right == node) {
parent->right = nullptr;
}
node->parent = nullptr;
BinaryTree<T> result;
result.m_root = node;
return result;
}
BinaryTree<T> remove(TreeNode<T> *node) {
auto status = find(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), dynamic_cast<BinaryTreeNode<T> *>(node));
if (!status) return BinaryTree();
auto parent = dynamic_cast<BinaryTreeNode<T> *>(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<T> *threaded(Traversal order) {
BinaryTreeNode<T> *ret = nullptr;
LinkedQueue<BinaryTreeNode<T> *> queue;
traversal(order, queue);
ret = connect(queue);
this->m_root = nullptr;
return ret;
}
Iterator begin() { return Iterator(dynamic_cast<BinaryTreeNode<T> *>(this->m_root)); }
Iterator end() { return Iterator(nullptr); }
protected:
BinaryTreeNode<T> *find(BinaryTreeNode<T> *node, const T &value) const {
BinaryTreeNode<T> *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<T> *node, BinaryTreeNode<T> *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<T> *node, BinaryTreeNode<T> *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<T> *node) {
if (node == nullptr) return;
if (node->left != nullptr) {
free(node->left);
}
if (node->right != nullptr) {
free(node->right);
}
delete node;
}
int count(BinaryTreeNode<T> *node) const {
if (node == nullptr) return 0;
int ret = 1;
ret += count(node->left);
ret += count(node->right);
return ret;
}
size_t height(BinaryTreeNode<T> *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<T> *node) const {
if (node == nullptr) return 0;
int ret = 0;
ret = (!!node->left) + (!!node->right);
BinaryTreeNode<T> *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<T> *clone(BinaryTreeNode<T> *node) const {
if (node == nullptr) return nullptr;
auto ret = new BinaryTreeNode<T>(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<T> *lh, const BinaryTreeNode<T> *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<T> *add(BinaryTreeNode<T> *lh, BinaryTreeNode<T> *rh) const {
BinaryTreeNode<T> *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<T>(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<BinaryTreeNode<T> *> &queue) {
switch (order) {
case Preorder:
preOrderTraversal(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), queue);
break;
case Inorder:
inOrderTraversal(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), queue);
break;
case Postorder:
postOrderTraversal(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), queue);
break;
case Levelorder:
levelOrderTraversal(dynamic_cast<BinaryTreeNode<T> *>(this->m_root), queue);
break;
default:
break;
}
}
/**
* @brief
*/
void preOrderTraversal(BinaryTreeNode<T> *node, LinkedQueue<BinaryTreeNode<T> *> &queue) {
if (node == nullptr) return;
queue.enqueue(node);
preOrderTraversal(node->left, queue);
preOrderTraversal(node->right, queue);
}
/**
* @brief
*/
void inOrderTraversal(BinaryTreeNode<T> *node, LinkedQueue<BinaryTreeNode<T> *> &queue) {
if (node == nullptr) return;
inOrderTraversal(node->left, queue);
queue.enqueue(node);
inOrderTraversal(node->right, queue);
}
void postOrderTraversal(BinaryTreeNode<T> *node, LinkedQueue<BinaryTreeNode<T> *> &queue) {
if (node == nullptr) return;
postOrderTraversal(node->left, queue);
postOrderTraversal(node->right, queue);
queue.enqueue(node);
}
/**
* @brief
*/
void levelOrderTraversal(BinaryTreeNode<T> *node, LinkedQueue<BinaryTreeNode<T> *> &queue) {
if (node == nullptr) return;
LinkedQueue<BinaryTreeNode<T> *> 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<T> *connect(LinkedQueue<BinaryTreeNode<T> *> &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

View File

@ -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}
)

View File

@ -0,0 +1,141 @@
#ifndef DUALCIRCULARLIST_H
#define DUALCIRCULARLIST_H
#include "DoublyLinkedList.h"
namespace Kylin {
template <typename T>
class CircularDoublyLinkedList : public DoublyLinkedList<T> {
using Node = typename DoublyLinkedList<T>::Node;
using Iterator = typename DoublyLinkedList<T>::Iterator;
public:
static constexpr size_t npos = static_cast<size_t>(-1);
CircularDoublyLinkedList() {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
}
CircularDoublyLinkedList(std::initializer_list<T> init) {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
for (auto &value : init) append(value);
}
CircularDoublyLinkedList(const CircularDoublyLinkedList &other) {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
auto sourceNode = other.m_header.next;
auto targetNode = reinterpret_cast<Node *>(&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<Node *>(&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<Node *>(&this->m_header)); }
Iterator end() const override { return Iterator(reinterpret_cast<Node *>(&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<Node *>(&(this->m_header));
for (size_t i = 0; i < index; i++) {
node = node->next;
}
return node;
}
};
} // namespace Kylin
#endif // DUALCIRCULARLIST_H

View File

@ -0,0 +1,109 @@
#ifndef CIRCULARLIST_H
#define CIRCULARLIST_H
#include "LinkedList.h"
namespace Kylin {
template <typename T>
class CircularLinkedList : public LinkedList<T> {
using Node = typename LinkedList<T>::Node;
using Iterator = typename LinkedList<T>::Iterator;
public:
CircularLinkedList() = default;
CircularLinkedList(std::initializer_list<T> init) {
this->m_header.next = reinterpret_cast<Node *>(&this->m_header);
this->m_last = reinterpret_cast<Node *>(&this->m_header);
for (auto &value : init) {
this->append(value);
}
}
CircularLinkedList(const CircularLinkedList &other) {
this->m_header.next = reinterpret_cast<Node *>(&this->m_header);
this->m_last = reinterpret_cast<Node *>(&this->m_header);
auto sourceNode = other.m_header.next;
auto targetNode = reinterpret_cast<Node *>(&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<Node *>(&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<T>::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<T>::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<Node *>(&this->m_header)); }
Iterator end() const override { return Iterator(reinterpret_cast<Node *>(&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

View File

@ -0,0 +1,207 @@
#ifndef DUALLINKEDLIST_H
#define DUALLINKEDLIST_H
#include "Exception.h"
#include "List.h"
#include <initializer_list>
namespace Kylin {
template <typename T>
class DoublyLinkedList : public List<T> {
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<size_t>(-1);
DoublyLinkedList() { m_last = reinterpret_cast<Node *>(&m_header); }
DoublyLinkedList(std::initializer_list<T> init) {
m_last = reinterpret_cast<Node *>(&m_header);
for (auto &value : init) append(value);
}
DoublyLinkedList(const DoublyLinkedList &other) {
auto sourceNode = other.m_header.next;
auto targetNode = reinterpret_cast<Node *>(&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<Node *>(&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<Node *>(&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<Node *>(&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

View File

@ -0,0 +1,96 @@
#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H
#include "Array.h"
#include <initializer_list>
namespace Kylin {
template <typename T>
class DynamicArray : public Array<T> {
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<T> 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<size_t>(-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

View File

@ -0,0 +1,81 @@
#ifndef DYNAMICSEQLIST_H
#define DYNAMICSEQLIST_H
#include "ArrayList.h"
#include <initializer_list>
namespace Kylin {
/**
*Capacity不足时1.5
*/
template <typename T>
class DynamicArrayList : public ArrayList<T> {
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<T> 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<T>::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

View File

@ -0,0 +1,67 @@
#include "Exception.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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<char *>(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

107
DataStructure/Exception.h Normal file
View File

@ -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

212
DataStructure/GeneralTree.h Normal file
View File

@ -0,0 +1,212 @@
#ifndef GENERALTREE_H
#define GENERALTREE_H
#include "LinkedList.h"
#include "LinkedQueue.h"
#include "Tree.h"
namespace Kylin {
template <typename T>
class GeneralTreeNode : public TreeNode<T> {
public:
GeneralTreeNode(const T &value, TreeNode<T> *parent = nullptr) : TreeNode<T>(value, parent) {}
LinkedList<GeneralTreeNode<T> *> children;
};
template <typename T>
class GeneralTree : public Tree<T> {
public:
class Iterator {
public:
Iterator(GeneralTreeNode<T> *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<T> *m_pos = nullptr;
LinkedQueue<GeneralTreeNode<T> *> m_queue;
};
GeneralTree() = default;
GeneralTree(GeneralTree &&other) {
this->m_root = other.m_root;
other.m_root = nullptr;
}
~GeneralTree() { clear(); }
bool insert(TreeNode<T> *node) {
bool ret = false;
auto n = dynamic_cast<GeneralTreeNode<T> *>(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<GeneralTreeNode<T> *>(node->parent);
parent->children.append(n);
ret = true;
}
return ret;
}
/**
* @brief TreeNode的地址nullptr
*/
GeneralTreeNode<T> *insert(const T &value, TreeNode<T> *parent) {
auto ret = new GeneralTreeNode<T>(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<T> remove(const T &value) {
auto node = find(value);
return node == nullptr ? GeneralTree<T>() : remove(node);
}
GeneralTree<T> remove(const GeneralTreeNode<T> *node) {
if (node == nullptr) return GeneralTree<T>();
GeneralTree<T> tree;
auto n = const_cast<GeneralTreeNode<T> *>(node);
if (n == this->m_root) {
this->m_root = nullptr;
tree.m_root = n;
return tree;
}
auto parent = dynamic_cast<GeneralTreeNode<T> *>(n->parent);
auto &children = parent->children;
auto pos = children.indexOf(n);
if (pos == LinkedList<T>::npos) return GeneralTree<T>();
children.removeAt(pos);
tree.m_root = n;
return tree;
}
GeneralTreeNode<T> *find(const T &value) const {
return find(dynamic_cast<GeneralTreeNode<T> *>(this->m_root), value);
}
bool find(TreeNode<T> *node) const override {
return find(dynamic_cast<GeneralTreeNode<T> *>(this->m_root),
dynamic_cast<GeneralTreeNode<T> *>(node));
}
GeneralTreeNode<T> *root() const { return dynamic_cast<GeneralTreeNode<T> *>(this->m_root); }
int count() const { return count(dynamic_cast<GeneralTreeNode<T> *>(this->m_root)); }
int degree() const { return degree(dynamic_cast<GeneralTreeNode<T> *>(this->m_root)); }
int height() const { return height(dynamic_cast<GeneralTreeNode<T> *>(this->m_root)); }
void clear() {
destroy(dynamic_cast<GeneralTreeNode<T> *>(this->m_root));
this->m_root = nullptr;
}
Iterator begin() { return Iterator(dynamic_cast<GeneralTreeNode<T> *>(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<T> *find(const GeneralTreeNode<T> *node, const T &value) const {
if (node == nullptr) return nullptr;
if (node->value == value) return const_cast<GeneralTreeNode<T> *>(node);
GeneralTreeNode<T> *ret = nullptr;
auto &children = const_cast<LinkedList<GeneralTreeNode<T> *> &>(node->children);
for (auto &child : children) {
ret = find(child, value);
if (ret != nullptr) break;
}
return ret;
}
/**
* @brief find node子树中查找obj
*/
GeneralTreeNode<T> *find(const GeneralTreeNode<T> *node, const GeneralTreeNode<T> *obj) const {
if (node == nullptr) return nullptr;
if (node == obj) return const_cast<GeneralTreeNode<T> *>(node);
GeneralTreeNode<T> *result = nullptr;
auto &children = const_cast<LinkedList<GeneralTreeNode<T> *> &>(node->children);
for (auto &child : children) {
result = find(child, obj);
if (result != nullptr) break;
}
return result;
}
void destroy(GeneralTreeNode<T> *node) {
if (node == nullptr) return;
auto &children = node->children;
for (auto &child : children) {
destroy(child);
}
delete node;
}
int count(const GeneralTreeNode<T> *node) const {
if (node == nullptr) return 0;
int ret = 1;
auto &children = const_cast<LinkedList<GeneralTreeNode<T> *> &>(node->children);
for (auto &child : children) {
ret += count(child);
}
return ret;
}
int height(const GeneralTreeNode<T> *node) const {
if (node == nullptr) return 0;
int ret = 0;
auto &children = const_cast<LinkedList<GeneralTreeNode<T> *> &>(node->children);
for (auto &child : children) {
int h = height(child);
if (ret < h) ret = h;
}
return ret + 1;
}
int degree(const GeneralTreeNode<T> *node) const {
if (node == nullptr) return 0;
int ret = node->children.length();
auto &children = const_cast<LinkedList<GeneralTreeNode<T> *> &>(node->children);
for (auto &child : children) {
int d = degree(child);
if (d > ret) ret = d;
}
return ret;
}
};
} // namespace Kylin
#endif // GENERALTREE_H

349
DataStructure/Graph.h Normal file
View File

@ -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 <optional>
namespace Kylin {
/*ListGraph用*/
template <typename EdgeType>
struct Edge : public Object {
static constexpr size_t npos = static_cast<size_t>(-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 <typename VertexType, typename EdgeType>
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<size_t> adjacent(size_t index) const = 0;
virtual std::optional<EdgeType> 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<Edge<EdgeType>> prim(const EdgeType &LIMIT) {
if (!asUndirected()) THROW_EXCEPTION(InvalidOperationException, "Graph must be undirectedgraph.");
auto vertexSize = vertexCount();
DynamicArrayList<Edge<EdgeType>> result(vertexSize - 1);
DynamicArray<size_t> edges(vertexSize);
DynamicArray<EdgeType> costs(vertexSize, LIMIT);
DynamicArray<bool> 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<size_t>(-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<size_t>(-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<Edge<EdgeType>> kruskal() {
DynamicArrayList<Edge<EdgeType>> result(1);
auto edges = getUndirectedEdges();
if (edges.empty()) return result;
auto vertexSize = vertexCount();
DynamicArray<size_t> 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<size_t> breadthFirstSearch(size_t index) {
if (index < 0 || index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid...");
LinkedQueue<size_t> queue;
LinkedQueue<size_t> ret;
DynamicArray<bool> 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<size_t> depthFirstSearch(size_t index) {
if (index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid...");
LinkedStack<size_t> stack;
LinkedQueue<size_t> ret;
DynamicArray<bool> 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<size_t> 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<size_t> result;
DynamicArray<EdgeType> distance(vertexSize, LIMIT);
DynamicArray<bool> mark(vertexSize, false);
DynamicArray<size_t> path(vertexSize, static_cast<size_t>(-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<size_t>(-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<size_t>(-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<int> floyd(int x, int y, const EdgeType &LIMIT) {
LinkedQueue<int> ret;
if ((x >= 0) && (x < vertexCount()) && (y >= 0) && (y < vertexCount())) {
DynamicArray<DynamicArray<EdgeType>> dist(vertexCount());
DynamicArray<DynamicArray<int>> 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<x,y> is invalid .");
}
return toArray(ret);
}
/* DFS递归版实现
static void DFS(Graph *graph,size_t index,Kylin::Array<bool> &visited,LinkedQueue<size_t> &ret) {
if((index>=0)&&(index<graph->vertexCount())) {
ret.add(index);
visited[index] = true;
auto aj = graph->adjacent(index);
for(size_t i=0;i<aj->length();i++){
if(visited[aj->at(i)]) continue;
DFS(graph,aj->at(i),visited,ret);
}
} else {
THROW_EXCEPTION(Kylin::InvalidParameterException,"Index is invalid...");
}
}
SharedPointer<Array<size_t>> DFS(size_t index) {
Kylin::DynamicArray<bool> visited(vertexCount(),false);
LinkedQueue<size_t> ret;
DFS(this,index,visited,ret);
return toArray(ret);
}
*/
protected:
template <typename T>
static DynamicArray<T> toArray(LinkedQueue<T> &queue) {
DynamicArray<T> ret(queue.length());
for (size_t i = 0; i < ret.length(); i++) {
ret[i] = queue.dequeue();
}
return ret;
}
template <typename T>
static DynamicArray<T> toArray(LinkedStack<T> &stack) {
DynamicArray<T> ret(stack.size());
for (size_t i = 0; i < ret.size(); i++) {
ret[i] = stack.pop();
}
return ret;
}
DynamicArrayList<Edge<EdgeType>> getUndirectedEdges() {
DynamicArrayList<Edge<EdgeType>> 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<EdgeType>(i, j, *e));
}
}
}
return result;
}
size_t findTerminalVertex(Array<size_t> &p, size_t v) {
while (p[v] != static_cast<size_t>(-1)) {
v = p[v];
}
return v;
}
}; // namespace Kylin
} // namespace Kylin
#endif // GRAPH_H

View File

@ -0,0 +1,36 @@
#ifndef DATA_SMARTPOINTER_H
#define DATA_SMARTPOINTER_H
#include "Pointer.h"
namespace Kylin {
template <typename T>
class SmartPointer : public Pointer<T> {
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

View File

@ -0,0 +1,294 @@
#include "KylinString.h"
#include "Exception.h"
#include <stdlib.h>
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<char *>(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<size_t>(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<size_t>(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<char *>(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<String &>(*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<char *>(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<size_t *>(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<int>(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<size_t>(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<size_t>(str[pos + patternLength])];
break;
}
}
}
return -1;
}
} // namespace Kylin

100
DataStructure/KylinString.h Normal file
View File

@ -0,0 +1,100 @@
#ifndef KYLINSTRING_H
#define KYLINSTRING_H
#include "Object.h"
#include <string.h>
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 <ostream>
namespace std {
inline std::ostream &operator<<(std::ostream &stream, const Kylin::String &string) {
stream << string.str();
return stream;
}
} // namespace std
#endif // KYLINSTRING_H

194
DataStructure/LinkedList.h Normal file
View File

@ -0,0 +1,194 @@
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Exception.h"
#include "List.h"
#include <initializer_list>
namespace Kylin {
template <typename T>
class LinkedList : public List<T> {
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<Node *>(&m_header); }
LinkedList(std::initializer_list<T> init) {
m_last = reinterpret_cast<Node *>(&m_header);
for (auto &value : init) {
append(value);
}
}
LinkedList(const LinkedList &other) {
auto sourceNode = other.m_header.next;
auto targetNode = reinterpret_cast<Node *>(&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<Node *>(&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<Node *>(&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<Node *>(&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

View File

@ -0,0 +1,48 @@
#ifndef LINKEDQUEUE_H
#define LINKEDQUEUE_H
#include "Exception.h"
#include "LinkedList.h"
#include "Queue.h"
#include "utility"
#include <initializer_list>
namespace Kylin {
template <typename T>
class LinkedQueue : public Queue<T> {
public:
LinkedQueue() = default;
LinkedQueue(std::initializer_list<T> 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<T> &operator=(LinkedQueue<T> &&other) {
if (&other != this) {
swap(other);
}
return *this;
}
private:
LinkedList<T> m_list;
};
} // namespace Kylin
#endif // LINKEDQUEUE_H

View File

@ -0,0 +1,37 @@
#ifndef LINKEDSTACK_H
#define LINKEDSTACK_H
#include "LinkedList.h"
#include "Stack.h"
#include "utility"
#include <initializer_list>
namespace Kylin {
template <typename T>
class LinkedStack : public Stack<T> {
public:
LinkedStack() = default;
LinkedStack(LinkedStack &&other) : m_list(std::move(other.m_list)) {}
LinkedStack(std::initializer_list<T> 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<T> m_list;
};
} // namespace Kylin
#endif // LINKEDSTACK_H

672
DataStructure/LinuxList.h Normal file
View File

@ -0,0 +1,672 @@
#ifndef LINUXLIST_H
#define LINUXLIST_H
// #include <linux/types.h>
// #include <linux/stddef.h>
// #include <linux/poison.h>
// #include <linux/prefetch.h>
#ifndef offsetof
#define offsetof(TYPE, MEMBER) (static_cast<size_t>(&(reinterpret_cast<TYPE *>(0))->MEMBER))
#endif
#ifndef container_of
#define container_of(ptr, type, member) \
(reinterpret_cast<type *>(reinterpret_cast<char *>(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

42
DataStructure/List.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef LIST_H
#define LIST_H
#include "Object.h"
namespace Kylin {
template <typename T>
class List : public Object {
public:
static constexpr size_t npos = static_cast<size_t>(-1);
virtual void append(const T &value) = 0;
const T &at(size_t index) const { return const_cast<List *>(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<List *>(this)->last(); }
virtual T &operator[](size_t index) = 0;
const T &operator[](size_t index) const { return const_cast<List *>(this)->operator[](index); }
};
} // namespace Kylin
#endif // LIST_H

186
DataStructure/ListGraph.h Normal file
View File

@ -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 <typename VertexType, typename EdgeType>
class ListGraph : public Graph<VertexType, EdgeType> {
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<EdgeType>(index, removeIndex));
if (pos != LinkedList<Vertex *>::npos) edges.removeAt(pos);
index++;
}
delete removeVertex->value;
delete removeVertex;
}
DynamicArray<size_t> adjacent(size_t index) const final {
if ((0 <= index) && (index < vertexCount())) {
auto vertex = m_vertexes.at(index);
auto &edges = vertex->edges;
DynamicArray<size_t> 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<EdgeType> 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<EdgeType>(start, end));
if (pos == LinkedList<Vertex *>::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<EdgeType>(start, end));
if (pos != LinkedList<Vertex *>::npos) {
edges[pos] = Edge<EdgeType>(start, end, value);
} else {
edges.insert(0, Edge<EdgeType>(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<EdgeType>(start, end));
if (pos != LinkedList<Vertex *>::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<Edge<EdgeType>> edges;
};
LinkedList<Vertex *> m_vertexes;
};
} // namespace Kylin
#endif // LISTGRAPH_H

145
DataStructure/MatrixGraph.h Normal file
View File

@ -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 <int N, typename VertexType, typename EdgeType>
class MatrixGraph : public Graph<VertexType, EdgeType> {
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<size_t> 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<size_t> 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<EdgeType> edge(size_t start, size_t end) const final {
bool status = ((0 <= start) && (start < vertexCount())) && ((0 <= end) && (end < vertexCount()));
if (!status) return std::optional<EdgeType>{};
if (m_edges[start][end] != nullptr) {
return std::optional<EdgeType>{*(m_edges[start][end])};
} else {
return std::optional<EdgeType>{};
}
}
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

16
DataStructure/Object.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "Object.h"
#include <stdlib.h>
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

20
DataStructure/Object.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef OBJECT_H
#define OBJECT_H
#include <stddef.h>
#include <stdint.h>
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

38
DataStructure/Pointer.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef POINTER_H
#define POINTER_H
#include "Object.h"
namespace Kylin {
template<typename T>
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<typename T>
Pointer<T>::~Pointer()
{
}
}
#endif // POINTER_H

20
DataStructure/Queue.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef QUEUE_H
#define QUEUE_H
#include "Object.h"
namespace Kylin {
template <typename T>
class Queue : public Object {
public:
virtual T &head() = 0;
const T &head() const { return const_cast<Queue *>(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

View File

@ -0,0 +1,60 @@
#ifndef QUEUE2STACK_H
#define QUEUE2STACK_H
#include "LinkedQueue.h"
#include "Stack.h"
#include <initializer_list>
namespace Kylin {
template <typename T>
class QueueToStack : public Stack<T> {
public:
QueueToStack(std::initializer_list<T> 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<T> m_inQueue;
LinkedQueue<T> m_outQueue;
};
} // namespace Kylin
#endif // QUEUE2STACK_H

View File

@ -0,0 +1,25 @@
#ifndef RANDOMITERATOR_H
#define RANDOMITERATOR_H
#include "Object.h"
namespace Kylin {
template <typename T>
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

30
DataStructure/Readme.md Normal file
View File

@ -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
```

View File

@ -0,0 +1,51 @@
#ifndef SHAREDPOINTER_H
#define SHAREDPOINTER_H
#include "Pointer.h"
namespace Kylin {
template <typename T>
class SharedPointer : public Pointer<T> {
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

151
DataStructure/Sort.h Normal file
View File

@ -0,0 +1,151 @@
#ifndef SORT_H
#define SORT_H
#include "Array.h"
#include "Object.h"
namespace Kylin {
class Sort : public Object {
public:
template <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
static void quick(T array[], size_t size) {
quick(array, 0, size - 1);
}
template <typename T>
static void merge(T array[], size_t size) {
T *helper = new T[size];
merge(array, helper, 0, size - 1);
delete[] helper;
}
protected:
template <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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

18
DataStructure/Stack.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef STACK_H
#define STACK_H
#include "Object.h"
namespace Kylin {
template <typename T>
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<Stack *>(this)->top(); }
virtual void clear() = 0;
virtual size_t size() const = 0;
};
} // namespace Kylin
#endif // STACK_H

View File

@ -0,0 +1,52 @@
#ifndef STACK2QUEUE_H
#define STACK2QUEUE_H
#include "LinkedStack.h"
#include "Queue.h"
#include <initializer_list>
namespace Kylin {
template <typename T>
class StackToQueue : public Queue<T> {
public:
StackToQueue(std::initializer_list<T> 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<T> m_in;
mutable LinkedStack<T> m_out;
};
} // namespace Kylin
#endif // STACK2QUEUE_H

View File

@ -0,0 +1,24 @@
#ifndef STATICARRAY_H
#define STATICARRAY_H
#include "Array.h"
namespace Kylin {
template <typename T, size_t N>
class StaticArray : public Array<T> {
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

View File

@ -0,0 +1,26 @@
#ifndef STATICSEQLIST_H
#define STATICSEQLIST_H
#include "ArrayList.h"
namespace Kylin {
template <typename T, size_t N>
class StaticArrayList : public ArrayList<T> {
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

View File

@ -0,0 +1,67 @@
#ifndef STATICLINKEDLIST_H
#define STATICLINKEDLIST_H
#include "LinkedList.h"
namespace Kylin {
template <typename T, size_t N>
class StaticLinkedList : public LinkedList<T> {
using Node = typename LinkedList<T>::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<Node *>(&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<StaticNode *>(m_space) + i;
ret = new (ret) StaticNode();
m_used[i] = true;
break;
}
return ret;
}
void destroy(Node *p) override {
auto del = dynamic_cast<StaticNode *>(p);
for (size_t i = 0; i < N; i++) {
if ((reinterpret_cast<StaticNode *>(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

View File

@ -0,0 +1,48 @@
#ifndef STATICQUEUE_H
#define STATICQUEUE_H
#include "Exception.h"
#include "Queue.h"
namespace Kylin {
template <typename T, size_t N>
class StaticQueue : public Queue<T> {
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

View File

@ -0,0 +1,40 @@
#ifndef STATICSTACK_H
#define STATICSTACK_H
#include "Exception.h"
#include "Stack.h"
namespace Kylin {
template <typename T, size_t N>
class StaticStack : public Stack<T> {
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

36
DataStructure/Tree.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef TREE_H
#define TREE_H
#include "Object.h"
namespace Kylin {
template <typename T>
class TreeNode {
public:
TreeNode(const T &value, TreeNode<T> *parent) : value(value), parent(parent) {}
T value;
TreeNode<T> *parent = nullptr;
virtual ~TreeNode() {}
};
template <typename T>
class Tree : public Object {
public:
virtual bool insert(TreeNode<T> *node) = 0;
virtual TreeNode<T> *find(const T &value) const = 0;
virtual bool find(TreeNode<T> *node) const = 0;
virtual TreeNode<T> *root() const = 0;
virtual int degree() const = 0;
virtual int count() const = 0;
virtual int height() const = 0;
virtual void clear() = 0;
protected:
TreeNode<T> *m_root = nullptr;
};
} // namespace Kylin
#endif // TREE_H

165
LICENSE Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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.

View File

@ -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
)

View File

@ -0,0 +1,69 @@
#include "BinarySearchTree.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class BinarySearchTreeTest {
public:
BinarySearchTreeTest() {
for (size_t i = 0; i < 11; i++) {
tree.insert(unsorted[i]);
}
}
BinarySearchTree<size_t> 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++]);
}
}

View File

@ -0,0 +1,273 @@
#include "BinaryTree.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class BinaryTreeTest {
public:
/*
1
2 3
4 5 6 7
8 9 10 11
*/
BinaryTreeTest() {
auto node1 = new BinaryTreeNode<size_t>(1);
tree.insert(node1);
auto node2 = new BinaryTreeNode<size_t>(2, node1);
node3 = new BinaryTreeNode<size_t>(3, node1);
tree.insert(node2);
tree.insert(node3);
auto node4 = new BinaryTreeNode<size_t>(4, node2);
node5 = new BinaryTreeNode<size_t>(5, node2);
tree.insert(node4);
tree.insert(node5);
node6 = new BinaryTreeNode<size_t>(6, node3);
auto node7 = new BinaryTreeNode<size_t>(7, node3);
tree.insert(node6);
tree.insert(node7);
auto node8 = new BinaryTreeNode<size_t>(8, node4);
auto node9 = new BinaryTreeNode<size_t>(9, node4);
tree.insert(node8);
tree.insert(node9);
auto node10 = new BinaryTreeNode<size_t>(10, node5);
tree.insert(node10);
auto node11 = new BinaryTreeNode<size_t>(11, node6);
tree.insert(node11);
initAddedTree();
}
/*
* 0
* 6 2
* 7 8
*/
void initAddedTree() {
auto node0 = new BinaryTreeNode<size_t>(0);
addedTree.insert(node0);
auto node6 = new BinaryTreeNode<size_t>(6, node0);
auto node2 = new BinaryTreeNode<size_t>(2, node0);
addedTree.insert(node6);
addedTree.insert(node2);
auto node7 = new BinaryTreeNode<size_t>(7, node2);
auto node8 = new BinaryTreeNode<size_t>(8, node2);
addedTree.insert(node7);
addedTree.insert(node8);
}
BinaryTreeNode<size_t> *node3 = nullptr;
BinaryTreeNode<size_t> *node5 = nullptr;
BinaryTreeNode<size_t> *node6 = nullptr;
BinaryTree<size_t> tree;
BinaryTree<size_t> 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<size_t>::Right);
BOOST_CHECK_EQUAL(status, true);
}
BOOST_FIXTURE_TEST_CASE(InsertWithNode, BinaryTreeTest) {
auto node12 = new BinaryTreeNode<size_t>(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<size_t>::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<size_t>::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<size_t>::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<size_t> tree2;
auto node1 = new BinaryTreeNode<size_t>(1);
tree2.insert(node1);
auto node2 = new BinaryTreeNode<size_t>(2, node1);
auto node3 = new BinaryTreeNode<size_t>(3, node1);
tree2.insert(node2);
tree2.insert(node3);
auto node4 = new BinaryTreeNode<size_t>(4, node2);
auto node5 = new BinaryTreeNode<size_t>(5, node2);
tree2.insert(node4);
tree2.insert(node5);
auto node6 = new BinaryTreeNode<size_t>(6, node3);
auto node7 = new BinaryTreeNode<size_t>(7, node3);
tree2.insert(node6);
tree2.insert(node7);
auto node8 = new BinaryTreeNode<size_t>(8, node4);
auto node9 = new BinaryTreeNode<size_t>(9, node4);
tree2.insert(node8);
tree2.insert(node9);
auto node10 = new BinaryTreeNode<size_t>(10, node5);
tree2.insert(node10);
auto node11 = new BinaryTreeNode<size_t>(11, node6);
tree2.insert(node11);
BOOST_TEST((tree2 == tree));
}
BOOST_FIXTURE_TEST_CASE(Add, BinaryTreeTest) {
BinaryTree<size_t> resultTree;
auto node1 = new BinaryTreeNode<size_t>(1);
resultTree.insert(node1);
auto node8from1 = new BinaryTreeNode<size_t>(8, node1);
auto node5from1 = new BinaryTreeNode<size_t>(5, node1);
resultTree.insert(node8from1);
resultTree.insert(node5from1);
auto node4 = new BinaryTreeNode<size_t>(4, node8from1);
auto node5from8 = new BinaryTreeNode<size_t>(5, node8from1);
resultTree.insert(node4);
resultTree.insert(node5from8);
auto node13 = new BinaryTreeNode<size_t>(13, node5from1);
auto node15 = new BinaryTreeNode<size_t>(15, node5from1);
resultTree.insert(node13);
resultTree.insert(node15);
auto node8from4 = new BinaryTreeNode<size_t>(8, node4);
auto node9 = new BinaryTreeNode<size_t>(9, node4);
resultTree.insert(node8from4);
resultTree.insert(node9);
auto node10 = new BinaryTreeNode<size_t>(10, node5from8);
resultTree.insert(node10);
auto node11 = new BinaryTreeNode<size_t>(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<size_t>::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<size_t>::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<size_t>::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<size_t>::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()

View File

@ -0,0 +1,108 @@
#include "CircularDoublyLinkedList.h"
#include <boost/test/unit_test.hpp>
#include <iostream>
using namespace Kylin;
class CircularDoublyLinkedListTest {
public:
CircularDoublyLinkedList<size_t> 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<size_t> 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<size_t> 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()

View File

@ -0,0 +1,103 @@
#include "CircularLinkedList.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class CircularListTest {
public:
CircularLinkedList<size_t> 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<size_t> 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<size_t> 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()

View File

@ -0,0 +1,101 @@
#include "DoublyLinkedList.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class DoublyLinkedListTest {
public:
DoublyLinkedList<size_t> 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<size_t> 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<size_t> 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()

View File

@ -0,0 +1,75 @@
#include "DynamicArrayList.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class DynamicArrayListTest {
public:
DynamicArrayList<size_t> 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()

View File

@ -0,0 +1,28 @@
#include "DynamicArray.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class DynamicArrayTest {
public:
DynamicArray<size_t> 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()

View File

@ -0,0 +1,84 @@
#include "GeneralTree.h"
#include <boost/test/unit_test.hpp>
#include <iostream>
using namespace Kylin;
class GeneralTreeTest {
public:
GeneralTreeTest() {
auto nodeA = new GeneralTreeNode<char>('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<char> tree;
GeneralTreeNode<char> *nodeE = nullptr;
GeneralTreeNode<char> *nodeC = nullptr;
GeneralTreeNode<char> *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<char>('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()

View File

@ -0,0 +1,101 @@
#include "LinkedList.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class LinkedListTest {
public:
LinkedList<size_t> 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<size_t> 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<size_t> 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()

View File

@ -0,0 +1,56 @@
#include "LinkedQueue.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class LinkedQueueTest {
public:
LinkedQueue<size_t> 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<size_t> 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()

View File

@ -0,0 +1,39 @@
#include "LinkedStack.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class LinkedStackTest {
public:
LinkedStack<size_t> 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()

View File

@ -0,0 +1,229 @@
#include "ListGraph.h"
#include <boost/test/unit_test.hpp>
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<char, int> graph{0};
ListGraph<size_t, size_t> complexGraph{9};
ListGraph<char, int> searchGraph{9};
ListGraph<size_t, size_t> 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<bool>(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<int, int> 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]);
}
}

View File

@ -0,0 +1,73 @@
#include "MatrixGraph.h"
#include <boost/test/unit_test.hpp>
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<bool>(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<bool>(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()

View File

@ -0,0 +1,33 @@
#include "QueueToStack.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class QueueToStackTest {
public:
QueueToStack<size_t> 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()

View File

@ -0,0 +1,64 @@
#include "KylinSmartPointer.h"
#include "SharedPointer.h"
#include <boost/test/unit_test.hpp>
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<TestObject> pointer(new TestObject(status)); }
BOOST_CHECK_EQUAL(status, false);
}
BOOST_FIXTURE_TEST_CASE(Move, SmartPointerTest) {
{
SmartPointer<TestObject> 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<TestObject> pointer(new TestObject(status)); }
BOOST_CHECK_EQUAL(status, false);
}
BOOST_FIXTURE_TEST_CASE(Count, SharedPointerTest) {
{
SharedPointer<TestObject> pointer(new TestObject(status));
{ auto p1 = pointer; }
BOOST_CHECK_EQUAL(status, true);
}
BOOST_CHECK_EQUAL(status, false);
}
BOOST_FIXTURE_TEST_CASE(Equal, SharedPointerTest) {
SharedPointer<TestObject> pointer(new TestObject(status));
auto p1 = pointer;
BOOST_TEST((pointer == p1));
}

View File

@ -0,0 +1,68 @@
#include "Sort.h"
#include "DynamicArray.h"
#include "SharedPointer.h"
#include <boost/test/unit_test.hpp>
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;
//}

View File

@ -0,0 +1,29 @@
#include <boost/test/unit_test.hpp>
#include "StackToQueue.h"
using namespace Kylin;
class StackToQueueTest {
public:
StackToQueue<size_t> 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);
}

View File

@ -0,0 +1,66 @@
#include <boost/test/unit_test.hpp>
#include "StaticArrayList.h"
using namespace Kylin;
class StaticArrayListTest {
public:
StaticArrayListTest() {
for (size_t i = 0; i < 8; i++) {
list.insert(list.length(), i);
}
}
StaticArrayList<size_t, 10> 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()

View File

@ -0,0 +1,38 @@
#include "StaticArray.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class StaticArrayTest {
public:
Kylin::StaticArray<size_t, 10> 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()

View File

@ -0,0 +1,80 @@
#include "StaticLinkedList.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class StaticLinkedListTest {
public:
StaticLinkedListTest() {
for (size_t i = 0; i < 8; i++) {
list.append(i);
}
}
StaticLinkedList<size_t, 10> 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<size_t, 10> 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<size_t, 10> 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()

View File

@ -0,0 +1,36 @@
#include "StaticQueue.h"
#include <boost/test/unit_test.hpp>
using namespace Kylin;
class StaticQueueTest {
public:
StaticQueue<size_t, 10> 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()

View File

@ -0,0 +1,38 @@
#include <boost/test/unit_test.hpp>
#include "StaticStack.h"
class StaticStackTest {
public:
Kylin::StaticStack<size_t, 10> 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()

View File

@ -0,0 +1,74 @@
#include "KylinString.h"
#include <boost/test/unit_test.hpp>
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()

View File

@ -0,0 +1,7 @@
#include "BoostLog.h"
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(BoostLogTest) {
boost::log::initialize();
LOG(info) << "this is a test output.";
}

View File

@ -17,7 +17,9 @@ BOOST_LOG_GLOBAL_LOGGER_INIT(location_logger, LocationLogger<boost::log::trivial
return lg;
}
void initBoostLog(const std::string &filename, const std::string &target, boost::log::trivial::severity_level filter) {
namespace boost {
namespace log {
void initialize(const std::string &filename, const std::string &target, boost::log::trivial::severity_level filter) {
static bool initialized = false;
using namespace boost::log;
if (!initialized) {
@ -38,6 +40,8 @@ void initBoostLog(const std::string &filename, const std::string &target, boost:
initialized = true;
}
}
} // namespace log
} // namespace boost
static void logFormatter(const boost::log::record_view &record, boost::log::formatting_ostream &ostream) {
using namespace boost::log;

View File

@ -52,6 +52,9 @@
#define LOG_FILTER_LEVEL (boost::log::trivial::info)
#endif
namespace boost {
namespace log {
/**
* @brief
*
@ -59,9 +62,10 @@
* @param target path for rotated log files
* @param filter
*/
void initBoostLog(
const std::string &filename = "logs/app", const std::string &target = "logs",
boost::log::trivial::severity_level filter = static_cast<boost::log::trivial::severity_level>(LOG_FILTER_LEVEL));
void initialize(const std::string &filename = "logs/app", const std::string &target = "logs",
trivial::severity_level filter = static_cast<trivial::severity_level>(LOG_FILTER_LEVEL));
} // namespace log
} // namespace boost
namespace AmassKeywords {