Add unit test.
This commit is contained in:
parent
a7442cb0ca
commit
e68f8d5a3a
@ -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
50
DataStructure/Array.h
Normal 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
65
DataStructure/ArrayList.h
Normal 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
|
240
DataStructure/BinarySearchTree.h
Normal file
240
DataStructure/BinarySearchTree.h
Normal 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
412
DataStructure/BinaryTree.h
Normal 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
|
62
DataStructure/CMakeLists.txt
Normal file
62
DataStructure/CMakeLists.txt
Normal 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}
|
||||
)
|
141
DataStructure/CircularDoublyLinkedList.h
Normal file
141
DataStructure/CircularDoublyLinkedList.h
Normal 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
|
109
DataStructure/CircularLinkedList.h
Normal file
109
DataStructure/CircularLinkedList.h
Normal 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
|
207
DataStructure/DoublyLinkedList.h
Normal file
207
DataStructure/DoublyLinkedList.h
Normal 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
|
96
DataStructure/DynamicArray.h
Normal file
96
DataStructure/DynamicArray.h
Normal 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
|
81
DataStructure/DynamicArrayList.h
Normal file
81
DataStructure/DynamicArrayList.h
Normal 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
|
67
DataStructure/Exception.cpp
Normal file
67
DataStructure/Exception.cpp
Normal 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
107
DataStructure/Exception.h
Normal 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
212
DataStructure/GeneralTree.h
Normal 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
349
DataStructure/Graph.h
Normal 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
|
36
DataStructure/KylinSmartPointer.h
Normal file
36
DataStructure/KylinSmartPointer.h
Normal 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
|
294
DataStructure/KylinString.cpp
Normal file
294
DataStructure/KylinString.cpp
Normal 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
100
DataStructure/KylinString.h
Normal 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
194
DataStructure/LinkedList.h
Normal 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
|
48
DataStructure/LinkedQueue.h
Normal file
48
DataStructure/LinkedQueue.h
Normal 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
|
37
DataStructure/LinkedStack.h
Normal file
37
DataStructure/LinkedStack.h
Normal 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
672
DataStructure/LinuxList.h
Normal 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
42
DataStructure/List.h
Normal 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
186
DataStructure/ListGraph.h
Normal 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
145
DataStructure/MatrixGraph.h
Normal 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
16
DataStructure/Object.cpp
Normal 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
20
DataStructure/Object.h
Normal 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
38
DataStructure/Pointer.h
Normal 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
20
DataStructure/Queue.h
Normal 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
|
60
DataStructure/QueueToStack.h
Normal file
60
DataStructure/QueueToStack.h
Normal 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
|
25
DataStructure/RandomIterator.h
Normal file
25
DataStructure/RandomIterator.h
Normal 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
30
DataStructure/Readme.md
Normal 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
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
51
DataStructure/SharedPointer.h
Normal file
51
DataStructure/SharedPointer.h
Normal 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
151
DataStructure/Sort.h
Normal 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
18
DataStructure/Stack.h
Normal 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
|
52
DataStructure/StackToQueue.h
Normal file
52
DataStructure/StackToQueue.h
Normal 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
|
24
DataStructure/StaticArray.h
Normal file
24
DataStructure/StaticArray.h
Normal 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
|
26
DataStructure/StaticArrayList.h
Normal file
26
DataStructure/StaticArrayList.h
Normal 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
|
67
DataStructure/StaticLinkedList.h
Normal file
67
DataStructure/StaticLinkedList.h
Normal 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
|
48
DataStructure/StaticQueue.h
Normal file
48
DataStructure/StaticQueue.h
Normal 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
|
40
DataStructure/StaticStack.h
Normal file
40
DataStructure/StaticStack.h
Normal 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
36
DataStructure/Tree.h
Normal 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
165
LICENSE
Normal 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.
|
@ -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
|
||||
)
|
||||
|
69
UnitTest/DataStructure/BinarySearchTreeTest.cpp
Normal file
69
UnitTest/DataStructure/BinarySearchTreeTest.cpp
Normal 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++]);
|
||||
}
|
||||
}
|
273
UnitTest/DataStructure/BinaryTreeTest.cpp
Normal file
273
UnitTest/DataStructure/BinaryTreeTest.cpp
Normal 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()
|
108
UnitTest/DataStructure/CircularDoublyLinkedListTest.cpp
Normal file
108
UnitTest/DataStructure/CircularDoublyLinkedListTest.cpp
Normal 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()
|
103
UnitTest/DataStructure/CircularLinkedListTest.cpp
Normal file
103
UnitTest/DataStructure/CircularLinkedListTest.cpp
Normal 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()
|
101
UnitTest/DataStructure/DoublyLinkedListTest.cpp
Normal file
101
UnitTest/DataStructure/DoublyLinkedListTest.cpp
Normal 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()
|
75
UnitTest/DataStructure/DynamicArrayListTest.cpp
Normal file
75
UnitTest/DataStructure/DynamicArrayListTest.cpp
Normal 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()
|
28
UnitTest/DataStructure/DynamicArrayTest.cpp
Normal file
28
UnitTest/DataStructure/DynamicArrayTest.cpp
Normal 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()
|
84
UnitTest/DataStructure/GeneralTreeTest.cpp
Normal file
84
UnitTest/DataStructure/GeneralTreeTest.cpp
Normal 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()
|
101
UnitTest/DataStructure/LinkedListTest.cpp
Normal file
101
UnitTest/DataStructure/LinkedListTest.cpp
Normal 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()
|
56
UnitTest/DataStructure/LinkedQueueTest.cpp
Normal file
56
UnitTest/DataStructure/LinkedQueueTest.cpp
Normal 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()
|
39
UnitTest/DataStructure/LinkedStackTest.cpp
Normal file
39
UnitTest/DataStructure/LinkedStackTest.cpp
Normal 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()
|
229
UnitTest/DataStructure/ListGraphTest.cpp
Normal file
229
UnitTest/DataStructure/ListGraphTest.cpp
Normal 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]);
|
||||
}
|
||||
}
|
73
UnitTest/DataStructure/MatrixGraphTest.cpp
Normal file
73
UnitTest/DataStructure/MatrixGraphTest.cpp
Normal 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()
|
33
UnitTest/DataStructure/QueueToStackTest.cpp
Normal file
33
UnitTest/DataStructure/QueueToStackTest.cpp
Normal 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()
|
64
UnitTest/DataStructure/SmartPointerTest.cpp
Normal file
64
UnitTest/DataStructure/SmartPointerTest.cpp
Normal 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));
|
||||
}
|
68
UnitTest/DataStructure/SortTest.cpp
Normal file
68
UnitTest/DataStructure/SortTest.cpp
Normal 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;
|
||||
|
||||
//}
|
29
UnitTest/DataStructure/StackToQueueTest.cpp
Normal file
29
UnitTest/DataStructure/StackToQueueTest.cpp
Normal 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);
|
||||
}
|
66
UnitTest/DataStructure/StaticArrayListTest.cpp
Normal file
66
UnitTest/DataStructure/StaticArrayListTest.cpp
Normal 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()
|
38
UnitTest/DataStructure/StaticArrayTest.cpp
Normal file
38
UnitTest/DataStructure/StaticArrayTest.cpp
Normal 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()
|
80
UnitTest/DataStructure/StaticLinkedListTest.cpp
Normal file
80
UnitTest/DataStructure/StaticLinkedListTest.cpp
Normal 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()
|
36
UnitTest/DataStructure/StaticQueueTest.cpp
Normal file
36
UnitTest/DataStructure/StaticQueueTest.cpp
Normal 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()
|
38
UnitTest/DataStructure/StaticStackTest.cpp
Normal file
38
UnitTest/DataStructure/StaticStackTest.cpp
Normal 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()
|
74
UnitTest/DataStructure/StringTest.cpp
Normal file
74
UnitTest/DataStructure/StringTest.cpp
Normal 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()
|
7
UnitTest/Universal/BoostLogTest.cpp
Normal file
7
UnitTest/Universal/BoostLogTest.cpp
Normal 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.";
|
||||
}
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user