Skip to content

Commit

Permalink
tree: avltree: add find/erase and test-case (#42)
Browse files Browse the repository at this point in the history
1.rename BinaryTree static-api
2.add erase/find (delete_by_target) api and test case
3.mv binary_search_tree.cpp -> tree dir

Signed-off-by: SPeak <speakshen@163.com>
  • Loading branch information
Sunrisepeak committed Dec 27, 2023
1 parent bf23a94 commit b2f0b73
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 59 deletions.
159 changes: 134 additions & 25 deletions core/ds/tree/AVLTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ class _AVLTreeIterator : public DStructIteratorTypeSpec<const T /* only-read */
return old;
}

public:
typename _Node::LinkType * __get_link_pointer() {
return _mIterator.__get_link_pointer();
}

private:
void __sync() {
if (nullptr == _mIterator.operator->())
Expand Down Expand Up @@ -104,6 +109,8 @@ class AVLTree : public tree::BinaryTree<_AVLData<T>, Alloc> {
}
}

public:

typename AVLTree::ConstIteratorType
find(const T &obj) const {
using CMPWrapper = _AVLDataCMP<T, CMP>; // TODO: optimize find(delete CMPWrapper?)
Expand All @@ -118,6 +125,23 @@ class AVLTree : public tree::BinaryTree<_AVLData<T>, Alloc> {
);
}

typename AVLTree::ConstIteratorType
erase(typename AVLTree::ConstIteratorType it) {
auto target = it.__get_link_pointer();
decltype(it) next = ++it;
typename RemoveConst<T>::Type nextData;
bool needUpdateNext = false;

if (next.__get_link_pointer() != nullptr) {
nextData = *next;
needUpdateNext = true;
}

_delete_by_target(target);

return needUpdateNext ? find(nextData) : next;
}

int height() const {
return __BinaryTree::_mRootPtr ? __BinaryTree::_mRootPtr->data.height : 0;
}
Expand All @@ -137,16 +161,6 @@ class AVLTree : public tree::BinaryTree<_AVLData<T>, Alloc> {
protected:
CMP _mCmp;

int _height(typename _Node::LinkType *root) {
if (root == nullptr)
return 0;
return _Node::to_node(root)->data.height;
}

int _balance_factor(typename _Node::LinkType *root) {
return root == nullptr ? 0 : _height(root->left) - _height(root->right);
}

typename _Node::LinkType * _check_and_balance(typename _Node::LinkType *root) {
int balance = _balance_factor(root);
if (balance > 1) { // need r-rotate
Expand All @@ -163,24 +177,47 @@ class AVLTree : public tree::BinaryTree<_AVLData<T>, Alloc> {
return root;
}

typename _Node::LinkType * _insert(typename _Node::LinkType *root, const T &element) {
void _rebalance_after_delete(typename _Node::LinkType *subTree) {
while (subTree != nullptr) {
// bottom-up balance
auto parent = subTree->parent;
auto newSubTree = _check_and_balance(subTree);

if (parent != nullptr) {
if (parent->left == subTree) {
parent->left = newSubTree;
} else {
parent->right = newSubTree;
}
_update_height(parent);
} else if (newSubTree != subTree) {
__BinaryTree::_update_root(newSubTree);
}

subTree = parent;
}
}

typename _Node::LinkType *
_insert(typename _Node::LinkType *root, const T &element, typename _Node::LinkType *parent = nullptr) {
_Node *rootNode = nullptr;
if (root == nullptr) { // create node
rootNode = _AllocNode::allocate();
dstruct::construct(rootNode, _Node(_AVLData<T>(element)));
root = _Node::to_link(rootNode);
root->parent = parent;
} else {
rootNode = _Node::to_node(root);
if (_mCmp(element, rootNode->data.val)) {
root->left = _insert(root->left, element);
root->left = _insert(root->left, element, root);
if (_height(root->left) - _height(root->right) == 2) {
if (_mCmp(_Node::to_node(root->left)->data.val, element)) { // LR: double-rotate
root->left = _left_rotate(root->left);
}
root = _right_rotate(root);
}
} else if (_mCmp(rootNode->data.val, element)) {
root->right = _insert(root->right, element);
root->right = _insert(root->right, element, root);
if (_height(root->right) - _height(root->left) == 2) {
if (_mCmp(element, _Node::to_node(root->right)->data.val)) { // RL: double-rotate
root->right = _right_rotate(root->right);
Expand All @@ -193,12 +230,64 @@ class AVLTree : public tree::BinaryTree<_AVLData<T>, Alloc> {
}
}

rootNode = _Node::to_node(root); // update, if root changed
rootNode->data.height = dstruct::max(_height(rootNode->link.left), _height(rootNode->link.right)) + 1;
_update_height(root); // update when root changed

return root;
}

typename _Node::LinkType * _delete_by_target(typename _Node::LinkType *target) {
if (target == nullptr) {
return nullptr;
}

auto parent = target->parent;
auto leftChild = target->left;
auto rightChild = target->right;

if (leftChild == nullptr && rightChild == nullptr) {
// Case 1: Node has no children
if (parent != nullptr) {
if (parent->left == target) {
parent->left = nullptr;
} else {
parent->right = nullptr;
}
_update_height(parent);
_rebalance_after_delete(parent);
}

_real_delete(target);

return nullptr;
} else if (leftChild != nullptr && rightChild != nullptr) {
// Case 3: Node has two children
auto successor = __BinaryTree::first_node(rightChild);
// TODO: optimize -> workaround by remove const
// data by dynamic-alloc, isn't Const-Data-Area so not lead to UB
using NoConstTPtr = typename RemoveConst<decltype(_Node::to_node(target)->data.val)>::Type *;
NoConstTPtr valPtr = const_cast<NoConstTPtr>(&(_Node::to_node(target)->data.val));
*valPtr = _Node::to_node(successor)->data.val;
return _delete_by_target(successor);
} else {
// Case 2: Node has one child
auto child = (leftChild != nullptr) ? leftChild : rightChild;
child->parent = parent;
if (parent != nullptr) {
if (parent->left == target) {
parent->left = child;
} else {
parent->right = child;
}
_update_height(parent);
_rebalance_after_delete(parent);
}

_real_delete(target);

return child;
}
}

typename _Node::LinkType * _delete(typename _Node::LinkType *root, const T &obj) {
auto nPtr = _Node::to_node(root);
if (_mCmp(obj, nPtr->data.val)) {
Expand All @@ -210,10 +299,7 @@ class AVLTree : public tree::BinaryTree<_AVLData<T>, Alloc> {
// l and r isn't nullptr, need to find leaf-node(r-side)
if (nullptr != root->left && nullptr != root->right) {
// step1: find right-bot
typename _Node::LinkType *tmp = root->right;
while (nullptr == tmp->left) {
tmp = tmp->left;
}
auto tmp = __BinaryTree::first_node(root->right);
// step2: move val, and del obj from nPtr->data change to tmpPtr->data
_Node *tmpPtr = _Node::to_node(tmp);
nPtr->data = tmpPtr->data;
Expand All @@ -227,21 +313,44 @@ class AVLTree : public tree::BinaryTree<_AVLData<T>, Alloc> {
subTree = root->left;
}

if (subTree) subTree->parent = root->parent;
if (subTree) {
subTree->parent = root->parent;
}

_real_delete(root);

// real delete
dstruct::destroy(nPtr);
_AllocNode::deallocate(nPtr);
__BinaryTree::_mSize--;
return subTree; // Note: only need return sub-tree directly
}
}

nPtr->data.height = dstruct::max(_height(nPtr->link.left), _height(nPtr->link.right)) + 1;
_update_height(root);

return _check_and_balance(root);
}

protected: // helper
int _height(typename _Node::LinkType *root) {
if (root == nullptr)
return 0;
return _Node::to_node(root)->data.height;
}

void _update_height(typename _Node::LinkType *node) {
int height = dstruct::max(_height(node->left), _height(node->right)) + 1;
_Node::to_node(node)->data.height = height;
}

int _balance_factor(typename _Node::LinkType *root) {
return root == nullptr ? 0 : _height(root->left) - _height(root->right);
}

void _real_delete(typename _Node::LinkType *linkPtr) {
auto nodePtr = _Node::to_node(linkPtr);
dstruct::destroy(nodePtr);
_AllocNode::deallocate(nodePtr);
__BinaryTree::_mSize--;
}

typename _Node::LinkType * _left_rotate(typename _Node::LinkType *root) {
root = tree::left_rotate(root);
auto rootNode = _Node::to_node(root);
Expand Down
24 changes: 12 additions & 12 deletions core/ds/tree/BinarySearchTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class BinarySearchTree : public BinaryTree<T, Alloc> {

DSTRUCT_COPY_SEMANTICS(BinarySearchTree) {
__BinaryTree::clear();
__BinaryTree::_mRootPtr = __BinaryTree::copy_tree(ds._mRootPtr);
__BinaryTree::_mRootPtr = __BinaryTree::copy(ds._mRootPtr);
__BinaryTree::_mSize = ds._mSize;
_mCmp = ds._mCmp;
return *this;
Expand All @@ -64,18 +64,8 @@ class BinarySearchTree : public BinaryTree<T, Alloc> {

~BinarySearchTree() = default;

public:

typename BinarySearchTree::ConstIteratorType
find(const T &obj) const {
auto target = BinarySearchTreeBase<T, CMP>::_find(_Node::to_link(__BinaryTree::_mRootPtr), obj, _mCmp);
return typename BinarySearchTree::ConstIteratorType(
_create_iterator(target, TraversalType::InOrder),
true
);
}
public: // push/pop

// push/pop
void push(const T &obj) {
auto tree = _insert(obj);
if (__BinaryTree::_mRootPtr == nullptr)
Expand All @@ -92,6 +82,16 @@ class BinarySearchTree : public BinaryTree<T, Alloc> {
// _mSize--; in _try_to_delete
}

public:
typename BinarySearchTree::ConstIteratorType
find(const T &obj) const {
auto target = BinarySearchTreeBase<T, CMP>::_find(_Node::to_link(__BinaryTree::_mRootPtr), obj, _mCmp);
return typename BinarySearchTree::ConstIteratorType(
_create_iterator(target, TraversalType::InOrder),
true
);
}

typename BinarySearchTree::ConstIteratorType
erase(typename BinarySearchTree::ConstIteratorType it) {

Expand Down
1 change: 0 additions & 1 deletion core/ds/tree/BinarySearchTreeBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#define __BINARY_SEARCH_TREE_BASE_HPP__DSTRUCT

#include <core/ds/tree/EmbeddedBinaryTree.hpp>
#include <stdio.h>

namespace dstruct {

Expand Down
17 changes: 11 additions & 6 deletions core/ds/tree/BinaryTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ class _BinaryTreeIterator : public DStructIteratorTypeSpec<T> {
return old;
}

public:
typename _Node::LinkType * __get_link_pointer() {
return _mTreeNodeLinkPtr;
}

private:
void __sync() {
__Self::_mPointer = &(_Node::to_node(_mTreeNodeLinkPtr)->data);
Expand Down Expand Up @@ -111,7 +116,7 @@ class BinaryTree : public _DStructTypeSpec<T, Alloc, _BinaryTreeIterator> {
(Note: impl by subclass)
*/
virtual ~BinaryTree() {
release_tree(_mRootPtr);
clear(_mRootPtr);
_mSize = 0;
}

Expand All @@ -125,7 +130,7 @@ class BinaryTree : public _DStructTypeSpec<T, Alloc, _BinaryTreeIterator> {
}

void clear() {
release_tree(_mRootPtr);
clear(_mRootPtr);
_mSize = 0;
}

Expand Down Expand Up @@ -174,26 +179,26 @@ class BinaryTree : public _DStructTypeSpec<T, Alloc, _BinaryTreeIterator> {
}

public:
static _Node * copy_tree(_Node *root) {
static _Node * copy(_Node *root) {
if (!root)
return nullptr;

_Node *newRoot = _AllocNode::allocate();
newRoot->data = root->data;
newRoot->parent = nullptr;

newRoot->left = copy_tree(root->left);
newRoot->left = copy(root->left);
if (newRoot->left)
newRoot->left->parent = newRoot;

newRoot->right = copy_tree(root->right);
newRoot->right = copy(root->right);
if (newRoot->right)
newRoot->right->parent = newRoot;

return newRoot;
}

static void release_tree(_Node *root) {
static void clear(_Node * &root) {
if (root) {
tree::postorder_traversal(&(root->link), [](typename _Node::LinkType *linkPtr) {
_Node *nPtr = _Node::to_node(linkPtr);
Expand Down
Loading

0 comments on commit b2f0b73

Please sign in to comment.