one-file-projects/bintree.h

464 lines
9.6 KiB
C
Raw Normal View History

2018-07-18 20:08:55 +02:00
#include <cassert>
#ifdef DUMP
#include <iostream>
using std::cout;
using std::endl;
#endif
typedef unsigned int Umword;
typedef int Mword;
template <typename Key>
class Bin_tree;
struct Bin_tree_node {
private:
2018-07-19 16:12:03 +02:00
template <typename E> friend class Bin_tree;
2018-07-18 20:08:55 +02:00
void recalc()
{
Umword leftHeight =
(left == nullptr) ? 0 : left->height + 1;
Umword rightHeight =
(right == nullptr) ? 0 : right->height + 1;
balance = leftHeight - rightHeight;
height = (leftHeight < rightHeight ? rightHeight : leftHeight);
}
2018-07-19 16:12:03 +02:00
void replaceChild(Bin_tree_node* child, Bin_tree_node* replace)
2018-07-19 14:48:32 +02:00
{
assert(child == left || child == right);
2018-07-18 20:08:55 +02:00
2018-07-19 14:48:32 +02:00
if(child == left)
left = replace;
else if(child == right)
right = replace;
if(replace)
replace->parent = this;
2018-07-18 20:08:55 +02:00
2018-07-19 14:48:32 +02:00
child->parent = nullptr;
recalc();
}
2018-07-19 16:12:03 +02:00
protected:
constexpr Bin_tree_node()
: parent(nullptr), left(nullptr),
2018-07-18 20:08:55 +02:00
right(nullptr), tree(nullptr),
balance(0), height(0)
{}
2018-07-19 16:12:03 +02:00
private:
Bin_tree_node* parent;
Bin_tree_node* left;
Bin_tree_node* right;
void* tree;
2018-07-18 20:08:55 +02:00
// AVL Tree
Mword balance;
Umword height;
2018-07-19 16:12:03 +02:00
};
2018-07-18 20:08:55 +02:00
2018-07-19 16:12:03 +02:00
template<typename Key>
class Bin_tree_node_t : public Bin_tree_node {
2018-07-18 20:08:55 +02:00
public:
2018-07-19 16:12:03 +02:00
class Key_trait {
public:
typedef Key Key_type;
static inline
Key_type get_key(Bin_tree_node* node)
{ return static_cast<Bin_tree_node_t<Key>* >(node)->key(); }
static inline
bool compare(Key_type a, Key_type b)
{ return (a < b); }
};
Bin_tree_node_t(Key k) : Bin_tree_node(), _key(k)
{}
inline
Key& key()
{ return _key; }
private:
Key _key;
2018-07-18 20:08:55 +02:00
};
2018-07-19 16:12:03 +02:00
template <typename Key_trait>
2018-07-18 20:08:55 +02:00
class Bin_tree {
protected:
2018-07-19 16:12:03 +02:00
typedef Bin_tree_node Node;
typedef typename Key_trait::Key_type Key_type;
2018-07-18 20:08:55 +02:00
private:
Node* root;
2018-07-19 16:12:03 +02:00
Node* findByKey(Key_type key) const
2018-07-18 20:08:55 +02:00
{
Node* iterparent = nullptr;
Node* iter = root;
while(iter != nullptr)
{
iterparent = iter;
2018-07-19 16:12:03 +02:00
if(Key_trait::compare(key, Key_trait::get_key(iter)))
2018-07-18 20:08:55 +02:00
iter = iter->left;
2018-07-19 16:12:03 +02:00
else if(Key_trait::compare(Key_trait::get_key(iter), key))
2018-07-18 20:08:55 +02:00
iter = iter->right;
2018-07-19 16:12:03 +02:00
else
2018-07-18 20:08:55 +02:00
break;
}
return iterparent;
}
Node* findLeft(Node* start) const
{
2018-07-19 14:48:32 +02:00
assert(start);
2018-07-18 20:08:55 +02:00
Node* iter = start;
while(iter->left != nullptr)
{
iter = iter->left;
}
return iter;
}
void leafRemove(Node* leaf)
{
2018-07-19 14:48:32 +02:00
assert(leaf);
2018-07-18 20:08:55 +02:00
assert(leaf->left == nullptr
|| leaf->right == nullptr);
2018-07-19 14:48:32 +02:00
Node* child;
2018-07-18 20:08:55 +02:00
if(leaf->left == nullptr && leaf->right == nullptr)
2018-07-19 14:48:32 +02:00
child = nullptr;
2018-07-18 20:08:55 +02:00
else if(leaf->left == nullptr)
2018-07-19 14:48:32 +02:00
child = leaf->right;
else if(leaf->right == nullptr)
child = leaf->left;
else
assert(false);
if(leaf->parent)
2018-07-18 20:08:55 +02:00
{
2018-07-19 14:48:32 +02:00
leaf->parent->replaceChild(leaf, child);
rebalance(leaf->parent, 1);
2018-07-18 20:08:55 +02:00
}
2018-07-19 14:48:32 +02:00
else
2018-07-18 20:08:55 +02:00
{
2018-07-19 14:48:32 +02:00
root = child;
if(child)
child->parent = nullptr;
2018-07-18 20:08:55 +02:00
}
leaf->parent = nullptr;
leaf->left = nullptr;
leaf->right = nullptr;
leaf->tree = nullptr;
leaf->recalc();
}
void
2018-07-19 14:48:32 +02:00
rebalance(Node* start, Mword abortCond)
2018-07-18 20:08:55 +02:00
{
for(Node* iter = start; iter != nullptr; iter = iter->parent)
{
iter->recalc();
Mword absBalance =
(iter->balance < 0) ? -(iter->balance) : iter->balance;
2018-07-19 14:48:32 +02:00
if(absBalance == 2) // needs rotation
2018-07-18 20:08:55 +02:00
{
// Left side is taller
if(iter->balance > 0)
{
// Left side's right side is taller
if(iter->left && iter->left->balance < 0)
{
rotateLeft(iter->left);
}
rotateRight(iter);
}
// Right side is taller
else
{
// Right side's left side is taller
if(iter->right && iter->right->balance > 0)
{
rotateRight(iter->right);
}
rotateLeft(iter);
}
// then abort
break;
}
2018-07-19 14:48:32 +02:00
else if(absBalance == abortCond) // can abort
break;
2018-07-18 20:08:55 +02:00
}
}
void rotateLeft(Node* node) {
assert(node);
assert(node->right);
Node* partner = node->right;
node->right = partner->left;
if(node->right)
node->right->parent = node;
// No parent, partner is the new root
if(node->parent == nullptr)
2018-07-19 14:48:32 +02:00
{
root = partner;
partner->parent = nullptr;
}
2018-07-18 20:08:55 +02:00
else
2018-07-19 14:48:32 +02:00
node->parent->replaceChild(node, partner);
2018-07-18 20:08:55 +02:00
node->parent = partner;
partner->left = node;
assert(node->parent == nullptr
|| node->parent->left == node
|| node->parent->right == node);
assert(partner->parent == nullptr
|| partner->parent->left == partner
|| partner->parent->right == partner);
assert(node->left == nullptr
|| node->left->parent == node);
assert(node->right == nullptr
|| node->right->parent == node);
assert(partner->left == nullptr
|| partner->left->parent == partner);
assert(partner->right == nullptr
|| partner->right->parent == partner);
node->recalc();
partner->recalc();
}
void rotateRight(Node* node) {
assert(node);
assert(node->left);
Node* partner = node->left;
node->left = partner->right;
if(node->left)
node->left->parent = node;
// No parent, partner is the new root
if(node->parent == nullptr)
2018-07-19 14:48:32 +02:00
{
root = partner;
partner->parent = nullptr;
}
2018-07-18 20:08:55 +02:00
else
2018-07-19 14:48:32 +02:00
node->parent->replaceChild(node,partner);
2018-07-18 20:08:55 +02:00
node->parent = partner;
partner->right = node;
assert(node->parent == nullptr
|| node->parent->left == node
|| node->parent->right == node);
assert(partner->parent == nullptr
|| partner->parent->left == partner
|| partner->parent->right == partner);
assert(node->left == nullptr
|| node->left->parent == node);
assert(node->right == nullptr
|| node->right->parent == node);
assert(partner->left == nullptr
|| partner->left->parent == partner);
assert(partner->right == nullptr
|| partner->right->parent == partner);
node->recalc();
partner->recalc();
}
#ifdef DUMP
void dump(Node* node, int indent = 0)
{
if(node == nullptr) return;
assert(node->tree == this);
assert(node->left == nullptr
|| node->left->parent == node);
dump(node->left, indent+1);
for(int i = 0; i < indent; i++)
cout << " ";
2018-07-19 16:12:03 +02:00
cout << Key_trait::get_key(node) << endl;
2018-07-18 20:08:55 +02:00
assert(node->right == nullptr
|| node->right->parent == node);
dump(node->right, indent+1);
}
#endif
public:
constexpr Bin_tree() : root(nullptr)
{}
bool insert(Node* node)
{
assert(node->tree == nullptr);
2018-07-19 14:48:32 +02:00
Node* parent = nullptr;
2018-07-18 20:08:55 +02:00
2018-07-19 14:48:32 +02:00
if(root == nullptr)
// Tree is empty, add node as root
root = node;
2018-07-18 20:08:55 +02:00
else
{
2018-07-19 14:48:32 +02:00
// else, find a suitable parent
2018-07-19 16:12:03 +02:00
parent = findByKey(Key_trait::get_key(node));
2018-07-19 14:48:32 +02:00
assert(parent);
2018-07-19 16:12:03 +02:00
if(Key_trait::compare(Key_trait::get_key(node),
Key_trait::get_key(parent)))
2018-07-19 14:48:32 +02:00
parent->left = node;
2018-07-19 16:12:03 +02:00
else if(Key_trait::compare(Key_trait::get_key(parent),
Key_trait::get_key(node)))
2018-07-19 14:48:32 +02:00
parent->right = node;
else // Node with same key exists
return false;
2018-07-18 20:08:55 +02:00
}
2018-07-19 14:48:32 +02:00
// setup node
2018-07-18 20:08:55 +02:00
node->parent = parent;
node->left = nullptr;
node->right = nullptr;
node->tree = this;
node->height = 0;
node->balance = 0;
2018-07-19 14:48:32 +02:00
// rebalance tree
if(parent)
rebalance(parent,0);
2018-07-18 20:08:55 +02:00
return true;
}
void remove(Node* node)
{
assert(node);
assert(node->tree == this);
if(node->left == nullptr || node->right == nullptr)
{
leafRemove(node);
return;
}
Node* replacement = findLeft(node->right);
leafRemove(replacement);
2018-07-19 14:48:32 +02:00
if(node->parent == nullptr)
2018-07-18 20:08:55 +02:00
{
root = replacement;
replacement->parent = nullptr;
}
else
2018-07-19 14:48:32 +02:00
node->parent->replaceChild(node, replacement);
2018-07-18 20:08:55 +02:00
replacement->left = node->left;
replacement->right = node->right;
replacement->tree = this;
if(node->left)
node->left->parent = replacement;
if(node->right)
node->right->parent = replacement;
replacement->recalc();
node->left = nullptr;
node->right = nullptr;
node->parent = nullptr;
node->tree = nullptr;
2018-07-19 14:48:32 +02:00
node->recalc();
2018-07-18 20:08:55 +02:00
}
2018-07-19 16:12:03 +02:00
Node* lookup(Key_type key) const
2018-07-19 14:48:32 +02:00
{
if(root == nullptr)
return nullptr;
2018-07-18 20:08:55 +02:00
Node* node = findByKey(key);
2018-07-19 14:48:32 +02:00
if(node == nullptr)
__builtin_unreachable();
2018-07-19 16:12:03 +02:00
if(Key_trait::compare(Key_trait::get_key(node),key)
|| Key_trait::compare(key, Key_trait::get_key(node)))
2018-07-18 20:08:55 +02:00
return nullptr;
return node;
}
#ifdef DUMP
void dump()
{
cout << "---------------------------------------------" << endl;
dump(root);
cout << "---------------------------------------------" << endl;
}
#endif
};
2018-07-19 16:12:03 +02:00
template<typename T, typename Key_trait = typename T::Key_trait>
class Bin_tree_t : Bin_tree<Key_trait> {
2018-07-18 20:08:55 +02:00
private:
2018-07-19 16:12:03 +02:00
typedef Bin_tree<Key_trait> Base;
typedef typename Key_trait::Key_type Key_type;
2018-07-18 20:08:55 +02:00
public:
inline
bool insert(T* node)
{ return Base::insert(static_cast<typename Base::Node*>(node)); }
inline
void remove(T* node)
{ Base::remove(static_cast<typename Base::Node*>(node)); }
inline
2018-07-19 16:12:03 +02:00
T* find(Key_type key)
2018-07-18 20:08:55 +02:00
{ return static_cast<T*>(Base::lookup(key)); }
#ifdef DUMP
inline
void dump()
{ Base::dump(); }
#endif
};