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;
|
|
|
|
}
|
|
|
|
|
2018-07-23 13:13:32 +02:00
|
|
|
inline
|
|
|
|
bool in_tree(Node* node)
|
|
|
|
{ return (node->tree == this); }
|
|
|
|
|
2018-07-18 20:08:55 +02:00
|
|
|
#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-23 13:13:32 +02:00
|
|
|
T* lookup(Key_type key)
|
2018-07-18 20:08:55 +02:00
|
|
|
{ return static_cast<T*>(Base::lookup(key)); }
|
|
|
|
|
2018-07-23 13:13:32 +02:00
|
|
|
inline
|
|
|
|
bool in_tree(T* node)
|
|
|
|
{ return Base::in_tree(static_cast<Base::Node*>(node)); }
|
|
|
|
|
2018-07-18 20:08:55 +02:00
|
|
|
#ifdef DUMP
|
|
|
|
inline
|
|
|
|
void dump()
|
|
|
|
{ Base::dump(); }
|
|
|
|
#endif
|
|
|
|
};
|