AVL Tree refactor

This commit is contained in:
IlyaShurupov 2024-04-08 16:16:37 +03:00
parent be6b821a40
commit aafecb8359
8 changed files with 511 additions and 376 deletions

View file

@ -5,6 +5,7 @@ file(GLOB SOURCES "./private/*.cpp")
file(GLOB HEADERS "./public/*.hpp") file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/) target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_include_directories(${PROJECT_NAME} PUBLIC ./private/)
target_link_libraries(${PROJECT_NAME} PUBLIC Modules) target_link_libraries(${PROJECT_NAME} PUBLIC Modules)
### -------------------------- Tests -------------------------- ### ### -------------------------- Tests -------------------------- ###

View file

@ -0,0 +1,407 @@
// #pragma once
// #include "Tree.hpp"
template <typename Key, typename Data, class Allocator>
tp::AvlTree<Key, Data, Allocator>::~AvlTree() {
removeAll();
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::deleteNode(Node* node) {
node->~Node();
mAlloc.deallocate(node);
mSize--;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::newNode(KeyArg key, DataArg data) -> Node* {
mSize++;
auto node = new (mAlloc.allocate(sizeof(Node))) Node(key, data);
node->mLeft = &gNullNode;
node->mRight = &gNullNode;
return node;
}
template <typename Key, typename Data, class Allocator>
[[nodiscard]] tp::ualni tp::AvlTree<Key, Data, Allocator>::size() const {
return mSize;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::head() const -> Node* {
return this->mRoot;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::insert(KeyArg key, DataArg data) {
if (!mRoot) {
mRoot = newNode(key, data);
return;
}
if (auto parent = findInsertParent(mRoot, key)) {
restoreInvariants(insertNode(parent, key, data));
}
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::remove(KeyArg key) {
auto node = findSubTree(mRoot, key);
if (!node) return;
if (node->mRight != &gNullNode && node->mLeft != &gNullNode) {
Node* min = minNode(node->mRight);
injectNodeInstead(node, min);
std::swap(node, min);
// auto const& newKey = min->key.getFindKey(head->mRight);
node = findSubTree(node->mRight, key);
DEBUG_ASSERT(node);
}
if (node->mRight != &gNullNode) {
if (node->mParent) {
if (node->mParent->mLeft == node) node->mParent->mLeft = node->mRight;
else node->mParent->mRight = node->mRight;
}
node->mRight->mParent = node->mParent;
auto delNode = node;
node = node->mRight;
deleteNode(delNode);
} else if (node->mLeft != &gNullNode) {
if (node->mParent) {
if (node->mParent->mLeft == node) node->mParent->mLeft = node->mLeft;
else node->mParent->mRight = node->mLeft;
}
node->mLeft->mParent = node->mParent;
auto delNode = node;
node = node->mLeft;
deleteNode(delNode);
} else {
if (node->mParent) {
if (node->mParent->mLeft == node) node->mParent->mLeft = &gNullNode;
else node->mParent->mRight = &gNullNode;
}
auto delNode = node;
node = node->mParent;
deleteNode(delNode);
}
restoreInvariants(node);
if (mRoot) mRoot->mParent = nullptr;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::maxNode(Node* head) const -> Node* {
if (!head) return nullptr;
while (head->mRight != &gNullNode) {
head = head->mRight;
}
return head;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::minNode(Node* head) const -> Node* {
if (!head) return nullptr;
while (head->mLeft != &gNullNode) {
head = head->mLeft;
}
return head;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::find(KeyArg key) const -> Node* {
return findSubTree(mRoot, key);
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findSubTree(Node* iter, KeyArg key) const -> Node* {
while (true) {
if (iter == &gNullNode) return nullptr;
if (iter->key.exactNode(key)) return iter;
if (iter->key.descentRight(key)) {
// key = iter->key.keyInRightSubtree(key);
iter = iter->mRight;
} else {
// key = iter->key.keyInLeftSubtree(key);
iter = iter->mLeft;
}
}
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findLessOrEq(KeyArg key) const -> Node* {
Node* iter = mRoot;
while (true) {
if (iter == &gNullNode) return nullptr;
if (iter->key.exactNode(key)) return iter;
if (iter->key.descentRight(key)) {
if (iter->mRight) {
// key = iter->key.keyInRightSubtree(key);
iter = iter->mRight;
} else {
return iter;
}
} else {
if (iter->mLeft) {
// key = iter->key.keyInLeftSubtree(key);
iter = iter->mLeft;
} else {
return iter;
}
}
}
}
template <typename Key, typename Data, class Allocator>
bool tp::AvlTree<Key, Data, Allocator>::isValid() {
return findInvalidNode(head()) == nullptr;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::removeAll() {
if (!mRoot) return;
removeAllUtil(mRoot);
mRoot = nullptr;
mSize = 0;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::removeAllUtil(Node* node) {
if (node->mLeft != &gNullNode) removeAllUtil(node->mLeft);
if (node->mRight != &gNullNode) removeAllUtil(node->mRight);
deleteNode(node);
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findInvalidNode(const Node* head) const -> const Node* {
// checks invariants of AVL tree
// returns first invalid node
if (!head || head == &gNullNode) return nullptr;
if (head->mLeft != &gNullNode) {
// TODO: incomplete test
if (head->key.descentRight(head->mLeft->key.getFindKey(head))) {
return head;
}
if (head->mLeft->mParent != head) {
return head;
}
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) {
return head;
}
}
if (head->mRight != &gNullNode) {
if (!head->key.descentRight(head->mRight->key.getFindKey(head))) {
return head;
}
if (head->mRight->mParent != head) {
return head;
}
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) {
return head;
}
}
if (head->mLeft != &gNullNode && head->mRight != &gNullNode) {
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) {
return head;
}
}
int balance = head->mRight->mHeight - head->mLeft->mHeight;
if (balance > 1 || balance < -1) {
return head;
}
const Node* ret = findInvalidNode(head->mRight);
if (ret) {
return ret;
}
return findInvalidNode(head->mLeft);
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::rotateLeft(Node* pivot) -> Node* {
// returns new head
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const right = pivot->mRight;
Node* const right_left = right->mLeft;
Node* const parent = pivot->mParent;
// parents
if (right_left != &gNullNode) right_left->mParent = head;
head->mParent = right;
right->mParent = parent;
// children
head->mRight = right_left;
right->mLeft = head;
// heights
head->mHeight = 1 + max(head->mLeft->mHeight, head->mRight->mHeight);
right->mHeight = 1 + max(right->mLeft->mHeight, right->mRight->mHeight);
// cache
head->key.updateNodeCache(head);
right->key.updateNodeCache(right);
return right;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::rotateRight(Node* pivot) -> Node* {
// returns new head
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const left = pivot->mLeft;
Node* const left_right = left->mRight;
Node* const parent = pivot->mParent;
// parents
if (left_right != &gNullNode) left_right->mParent = head;
head->mParent = left;
left->mParent = parent;
// children
head->mLeft = left_right;
left->mRight = head;
// heights
head->mHeight = 1 + max(head->mLeft->mHeight, head->mRight->mHeight);
left->mHeight = 1 + max(left->mLeft->mHeight, left->mRight->mHeight);
// cache
head->key.updateNodeCache(head);
left->key.updateNodeCache(left);
return left;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::restoreInvariants(Node* head) {
if (!head) mRoot = nullptr;
while (head) {
Node* headParent = head->mParent;
Node** parentHeadLink = nullptr;
if (headParent) parentHeadLink = headParent->mLeft == head ? &headParent->mLeft : &headParent->mRight;
head->mHeight = 1 + max(head->mRight->mHeight, head->mLeft->mHeight);
const alni balance = head->mRight->mHeight - head->mLeft->mHeight;
if (balance < -1) {
if (head->mLeft->mLeft->mHeight >= head->mLeft->mRight->mHeight) {
head = rotateRight(head);
} else {
head->mLeft = rotateLeft(head->mLeft);
head = rotateRight(head);
}
} else if (balance > 1) {
if (head->mRight->mRight->mHeight >= head->mRight->mLeft->mHeight) {
head = rotateLeft(head);
} else {
head->mRight = rotateRight(head->mRight);
head = rotateLeft(head);
}
}
head->key.updateNodeCache(head);
if (headParent) *parentHeadLink = head;
mRoot = head;
head = headParent;
}
if (mRoot) mRoot->mParent = nullptr;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::insertNode(Node* head, KeyArg key, DataArg data) -> Node* {
Node* insertedNode = newNode(key, data);
if (head->key.descentRight(key)) {
head->mRight = insertedNode;
} else {
head->mLeft = insertedNode;
}
insertedNode->mParent = head;
return insertedNode;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findInsertParent(Node* head, KeyArg key) -> Node* {
while (true) {
if (head->key.exactNode(key)) {
return nullptr;
}
if (head->key.descentRight(key)) {
if (head->mRight == &gNullNode) {
return head;
}
head = head->mRight;
} else {
if (head->mLeft == &gNullNode) {
return head;
}
head = head->mLeft;
}
}
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::injectNodeInstead(Node* target, Node* from) {
// swaps pointers of two nodes to preserve data location in the memory instead of swapping data directly
// 'target' always has two nodes
// 'from' has only one child on the right on no child at all
// 'from' can be right child of the 'target'
// 'target' can or can not have parent
// 'target' can be left or right child of parent
// from is not a child of target
Node* targetParent = target->mParent;
Node* targetLeft = target->mLeft;
Node* targetRight = target->mRight;
bool special = target->mRight == from;
// update parent
if (targetParent) {
if (targetParent->mRight == target) targetParent->mRight = from;
else targetParent->mLeft = from;
}
// clone 'from' to 'target'
target->mParent = special ? from : from->mParent;
target->mLeft = &gNullNode;
target->mRight = from->mRight;
if (!special) target->mParent->mLeft = target;
// if (target->mLeft) target->mLeft->mParent = target;
if (target->mRight) target->mRight->mParent = target;
// clone 'target' to 'from'
from->mParent = targetParent;
from->mLeft = targetLeft;
from->mRight = special ? target : targetRight;
from->mLeft->mParent = from;
from->mRight->mParent = from;
std::swap(from->mHeight, target->mHeight);
}

View file

@ -4,8 +4,6 @@
#include <cstdlib> #include <cstdlib>
namespace tp { namespace tp {
void* DefaultAllocator::allocate(ualni size) { return malloc(size); } void* DefaultAllocator::allocate(ualni size) { return malloc(size); }
void DefaultAllocator::deallocate(void* p) { free(p); } void DefaultAllocator::deallocate(void* p) { free(p); }
} }

View file

@ -60,7 +60,7 @@ namespace tp {
private: private:
template <typename tFunctor> template <typename tFunctor>
void forEachIntersectionUtil(const Node* node, tType start, tType end, tFunctor functor, ualni& debug) const { void forEachIntersectionUtil(const Node* node, tType start, tType end, tFunctor functor, ualni& debug) const {
if (node == nullptr) return; if (node->mHeight == -1) return; // sentinel node (null node)
debug++; debug++;

View file

@ -38,145 +38,42 @@ namespace tp {
class Node { class Node {
friend AvlTree; friend AvlTree;
public:
Node() = default;
private: private:
Node(KeyArg aKey, DataArg aData) : Node(KeyArg aKey, DataArg aData) :
key(aKey), key(aKey),
data(aData) {} data(aData) {}
public: public:
Data data; alni mHeight = -1;
Key key;
Node* mLeft = nullptr; Node* mLeft = nullptr;
Node* mRight = nullptr; Node* mRight = nullptr;
Node* mParent = nullptr; Node* mParent = nullptr;
ualni mHeight = 0;
Data data;
Key key;
}; };
public: public:
AvlTree() = default; AvlTree() = default;
~AvlTree() { removeAll(); } ~AvlTree();
[[nodiscard]] ualni size() const { return mSize; } ualni size() const;
Node* head() const;
Node* head() const { return this->mRoot; } void insert(KeyArg key, DataArg data);
void remove(KeyArg key);
void removeAll();
void insert(KeyArg key, DataArg data) { Node* maxNode(Node* head) const;
mRoot = insertUtil(mRoot, key, data); Node* minNode(Node* head) const;
mRoot->mParent = nullptr;
}
void remove(KeyArg key) { Node* find(KeyArg key) const;
mRoot = removeUtil(mRoot, key); Node* findSubTree(Node* iter, KeyArg key) const;
if (mRoot) mRoot->mParent = nullptr; Node* findLessOrEq(KeyArg key) const;
}
Node* maxNode(Node* head) const {
if (!head) return nullptr;
while (head->mRight != nullptr) {
head = head->mRight;
}
return head;
}
Node* minNode(Node* head) const {
if (!head) return nullptr;
while (head->mLeft != nullptr) {
head = head->mLeft;
}
return head;
}
Node* find(KeyArg key) const {
Node* iter = mRoot;
while (true) {
if (!iter) return nullptr;
if (iter->key.exactNode(key)) return iter;
if (iter->key.descentRight(key)) {
key = iter->key.keyInRightSubtree(key);
iter = iter->mRight;
} else {
key = iter->key.keyInLeftSubtree(key);
iter = iter->mLeft;
}
}
}
Node* findLessOrEq(KeyArg key) const {
Node* iter = mRoot;
while (true) {
if (!iter) return nullptr;
if (iter->key.exactNode(key)) return iter;
if (iter->key.descentRight(key)) {
if (iter->mRight) {
key = iter->key.keyInRightSubtree(key);
iter = iter->mRight;
} else {
return iter;
}
} else {
if (iter->mLeft) {
key = iter->key.keyInLeftSubtree(key);
iter = iter->mLeft;
} else {
return iter;
}
}
}
}
// checks invariants of AVL tree
// returns first invalid node
const Node* findInvalidNode(const Node* head) const {
if (head == nullptr) return nullptr;
if (head->mLeft) {
// TODO: incomplete test
if (head->key.descentRight(head->mLeft->key.getFindKey(head))) {
return head;
}
if (head->mLeft->mParent != head) {
return head;
}
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) {
return head;
}
}
if (head->mRight) {
if (!head->key.descentRight(head->mRight->key.getFindKey(head))) {
return head;
}
if (head->mRight->mParent != head) {
return head;
}
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) {
return head;
}
}
if (head->mLeft && head->mRight) {
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) {
return head;
}
}
int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
if (balance > 1 || balance < -1) {
return head;
}
const Node* ret = findInvalidNode(head->mRight);
if (ret) {
return ret;
}
return findInvalidNode(head->mLeft);
}
bool isValid() { return findInvalidNode(head()) == nullptr; }
template <typename tFunctor> template <typename tFunctor>
void traverse(Node* node, bool after, tFunctor functor) { void traverse(Node* node, bool after, tFunctor functor) {
@ -186,259 +83,35 @@ namespace tp {
if (after) functor(node); if (after) functor(node);
} }
void removeAll() { auto findInvalidNode(const Node* head) const -> const Node*;
if (!mRoot) return; bool isValid();
removeUtil(mRoot);
mRoot = nullptr;
mSize = 0;
}
void removeUtil(Node* node) {
if (node->mLeft) removeUtil(node->mLeft);
if (node->mRight) removeUtil(node->mRight);
deleteNode(node);
}
public:
template <class tArchiver>
void archiveWrite(tArchiver& file) const {
FAIL("not implemented")
}
template <class tArchiver>
void archiveRead(tArchiver&) {
FAIL("not implemented")
}
private: private:
inline void deleteNode(Node* node) { inline void deleteNode(Node* node);
node->~Node(); inline auto newNode(KeyArg key, DataArg data) -> Node*;
mAlloc.deallocate(node);
mSize--;
}
inline Node* newNode(KeyArg key, DataArg data) { return new (mAlloc.allocate(sizeof(Node))) Node(key, data); } inline auto rotateLeft(Node* pivot) -> Node*;
inline auto rotateRight(Node* pivot) -> Node*;
// swaps pointers of two nodes to preserve data location in the memory instead of swapping data directly inline void restoreInvariants(Node* head);
inline void injectNodeInstead(Node* target, Node* from) {
// 'target' always has two nodes
// 'from' has only one child on the right on no child at all
// 'from' can be right child of the 'target'
// 'target' can or can not have parent
// 'target' can be left or right child of parent
// from is not a child of target inline auto insertNode(Node* head, KeyArg key, DataArg data) -> Node*;
Node* targetParent = target->mParent; inline auto findInsertParent(Node* head, KeyArg key) -> Node*;
Node* targetLeft = target->mLeft;
Node* targetRight = target->mRight;
bool special = target->mRight == from; inline void injectNodeInstead(Node* target, Node* from);
// update parent void removeAllUtil(Node* node);
if (targetParent) {
if (targetParent->mRight == target) targetParent->mRight = from;
else targetParent->mLeft = from;
}
// clone 'from' to 'target'
target->mParent = special ? from : from->mParent;
target->mLeft = nullptr;
target->mRight = from->mRight;
if (!special) target->mParent->mLeft = target;
// if (target->mLeft) target->mLeft->mParent = target;
if (target->mRight) target->mRight->mParent = target;
// clone 'target' to 'from'
from->mParent = targetParent;
from->mLeft = targetLeft;
from->mRight = special ? target : targetRight;
from->mLeft->mParent = from;
from->mRight->mParent = from;
std::swap(from->mHeight, target->mHeight);
}
inline alni getNodeHeight(const Node* node) const { return node ? node->mHeight : -1; }
// returns new head
inline Node* rotateLeft(Node* pivot) {
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const right = pivot->mRight;
Node* const right_left = right->mLeft;
Node* const parent = pivot->mParent;
// parents
if (right_left) right_left->mParent = head;
head->mParent = right;
right->mParent = parent;
// children
head->mRight = right_left;
right->mLeft = head;
// heights
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
right->mHeight = 1 + max(getNodeHeight(right->mLeft), getNodeHeight(right->mRight));
// cache
head->key.updateNodeCache(head);
right->key.updateNodeCache(right);
return right;
}
inline Node* rotateRight(Node* pivot) {
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const left = pivot->mLeft;
Node* const left_right = left->mRight;
Node* const parent = pivot->mParent;
// parents
if (left_right) left_right->mParent = head;
head->mParent = left;
left->mParent = parent;
// children
head->mLeft = left_right;
left->mRight = head;
// heights
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
left->mHeight = 1 + max(getNodeHeight(left->mLeft), getNodeHeight(left->mRight));
// cache
head->key.updateNodeCache(head);
left->key.updateNodeCache(left);
return left;
}
// recursively returns valid isLeft or isRight child or root
Node* insertUtil(Node* head, KeyArg key, DataArg data) {
Node* insertedNode;
if (head == nullptr) {
mSize++;
Node* out = newNode(key, data);
out->key.updateNodeCache(out);
return out;
} else if (head->key.exactNode(key)) {
return head;
} else if (head->key.descentRight(key)) {
insertedNode = insertUtil(head->mRight, head->key.keyInRightSubtree(key), data);
head->mRight = insertedNode;
insertedNode->mParent = head;
} else {
insertedNode = insertUtil(head->mLeft, head->key.keyInLeftSubtree(key), data);
head->mLeft = insertedNode;
insertedNode->mParent = head;
}
// update height
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
alni balance = alni(getNodeHeight(head->mRight) - getNodeHeight(head->mLeft));
if (balance > 1) {
if (head->mRight->key.descentRight(head->key.keyInRightSubtree(key))) {
return rotateLeft(head);
} else {
head->mRight = rotateRight(head->mRight);
return rotateLeft(head);
}
} else if (balance < -1) {
if (!head->mLeft->key.descentRight(head->key.keyInLeftSubtree(key))) {
return rotateRight(head);
} else {
head->mLeft = rotateLeft(head->mLeft);
return rotateRight(head);
}
}
head->key.updateNodeCache(head);
return head;
}
Node* removeUtil(Node* head, KeyArg key) {
if (head == nullptr) return head;
if (head->key.exactNode(key)) {
if (head->mRight && head->mLeft) {
Node* min = minNode(head->mRight);
injectNodeInstead(head, min);
std::swap(head, min);
// auto const& newKey = min->key.getFindKey(head->mRight);
head->mRight = removeUtil(head->mRight, key);
} else if (head->mRight) {
if (head->mParent) {
if (head->mParent->mLeft == head) head->mParent->mLeft = head->mRight;
else head->mParent->mRight = head->mRight;
}
head->mRight->mParent = head->mParent;
auto delNode = head;
head = head->mRight;
deleteNode(delNode);
} else if (head->mLeft) {
if (head->mParent) {
if (head->mParent->mLeft == head) head->mParent->mLeft = head->mLeft;
else head->mParent->mRight = head->mLeft;
}
head->mLeft->mParent = head->mParent;
auto delNode = head;
head = head->mLeft;
deleteNode(delNode);
} else {
deleteNode(head);
head = nullptr;
}
} else if (head->key.descentRight(key)) {
head->mRight = removeUtil(head->mRight, head->key.keyInRightSubtree(key));
} else {
head->mLeft = removeUtil(head->mLeft, head->key.keyInLeftSubtree(key));
}
if (head == nullptr) return head;
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
alni balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
if (balance < -1) {
if (getNodeHeight(head->mLeft->mLeft) >= getNodeHeight(head->mLeft->mRight)) {
return rotateRight(head);
} else {
head->mLeft = rotateLeft(head->mLeft);
return rotateRight(head);
}
} else if (balance > 1) {
if (getNodeHeight(head->mRight->mRight) >= getNodeHeight(head->mRight->mLeft)) {
return rotateLeft(head);
} else {
head->mRight = rotateRight(head->mRight);
return rotateLeft(head);
}
}
head->key.updateNodeCache(head);
return head;
}
private: private:
Node* mRoot = nullptr; Node* mRoot = nullptr;
ualni mSize = 0; ualni mSize = 0;
Allocator mAlloc; Allocator mAlloc;
static Node gNullNode;
}; };
}
template <typename Key, typename Data, class Allocator>
AvlTree<Key, Data, Allocator>::Node AvlTree<Key, Data, Allocator>::gNullNode;
}
#include "AVLTree.ipp"

View file

@ -51,7 +51,7 @@ SUITE(IntervalTree) {
TEST(FunctionalityScale) { TEST(FunctionalityScale) {
const int NUM_TEST_INTERVALS = 1000; const int NUM_TEST_INTERVALS = 1000;
const halnf SPAN = 100; const halnf SPAN = 1000;
Buffer<Interval> pool; Buffer<Interval> pool;
IntervalTree<halnf, ualni> intervalTree; IntervalTree<halnf, ualni> intervalTree;
@ -72,9 +72,9 @@ SUITE(IntervalTree) {
idx++; idx++;
} }
intervalTree.forEachIntersection(testInterval->start, testInterval->end, [&](alni start, ualni end, ualni data) { intervalTree.forEachIntersection(
result.append(data); testInterval->start, testInterval->end, [&](alni start, ualni end, ualni data) { result.append(data); }
}); );
CHECK(correct.size() == result.size()); CHECK(correct.size() == result.size());
@ -270,5 +270,4 @@ SUITE(IntervalTree) {
CHECK(makeQuery(0, 1).found(2)); CHECK(makeQuery(0, 1).found(2));
} }
} }

View file

@ -1,5 +1,7 @@
#include <iostream>
#include "Tests.hpp" #include "Tests.hpp"
#include "Tree.hpp" #include "Tree.hpp"
#include "Timing.hpp"
using namespace tp; using namespace tp;
@ -24,7 +26,7 @@ SUITE(AvlTree) {
TEST(Persistance) { TEST(Persistance) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree; AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
const auto size = 10; const auto size = 1000;
struct Item { struct Item {
Item() : Item() :
@ -122,4 +124,62 @@ SUITE(AvlTree) {
CHECK(tree.maxNode(tree.head()) == nullptr); CHECK(tree.maxNode(tree.head()) == nullptr);
CHECK(tree.minNode(tree.head()) == nullptr); CHECK(tree.minNode(tree.head()) == nullptr);
} }
TEST(Speed) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
const auto size = 1000000;
struct Item {
Item() :
data(0) {}
bool presents = false;
TestClass data;
};
Item* buff = new Item[size];
for (auto i : Range(size)) {
buff[i].data.setVal(i);
}
Timer insertTime;
ualni loadSize = 0;
while (loadSize < size / 2) {
auto idx = ualni(randomFloat() * (size - 1));
if (!buff[idx].presents) {
tree.insert((alni) buff[idx].data.getVal(), buff[idx].data);
loadSize++;
buff[idx].presents = true;
}
}
std::cout << "AVL Tree Insert Speed " << (double) loadSize / (double) insertTime.timePassed() << "\n";
Timer removeTime;
ualni unloadSize = 0;
while (unloadSize < size / 2) {
auto idx = ualni(randomFloat() * (size - 1));
if (buff[idx].presents) {
tree.remove((alni) buff[idx].data.getVal());
unloadSize++;
buff[idx].presents = false;
}
}
for (auto idx = 0; idx < size; idx++) {
auto& item = buff[idx];
if (item.presents) {
tree.remove((alni) item.data.getVal());
unloadSize++;
item.presents = false;
}
}
std::cout << "AVL Tree Remove Speed " << (double) unloadSize / (double) removeTime.timePassed() << "\n";
delete[] buff;
}
} }

3
TODO
View file

@ -13,13 +13,10 @@ Modules:
Remove all static variable into module's data Remove all static variable into module's data
Containers: Containers:
Avl tree add sentenels
Add variant size buffer Add variant size buffer
Buffer add resize function Buffer add resize function
Buffer improvements Buffer improvements
Write Traverse Avl test
Add check copy times Add check copy times
AVL dont copy data just swap
Storage: Storage:
Reconsider Reconsider