#ifndef GYM_BINARY_SEARCH_TREE_COMMON_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#define GYM_BINARY_SEARCH_TREE_COMMON_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#include <stdint.h>
#include <assert.h>
#include <boost/call_traits.hpp>
#include <vector>
#include <stack>
#include <queue>
namespace pratique
{
namespace details
{
enum child_position
{
left_child = 0,
right_child = 1,
child_position_limit = 2
};
enum search_result
{
empty_tree = 1,
found_node = 2,
should_insert_as_left = 4,
should_insert_as_right = 8
};
template <typename TreeNodeIndicator>
size_t height( TreeNodeIndicator root )
{
size_t h = 0;
if ( root.is_non_null( ) ) {
size_t lh = height<TreeNodeIndicator>( root.get_pointer( )->m_left ), rh = height<TreeNodeIndicator>( root.get_pointer( )->m_right );
h = ( lh < rh ? rh : lh ) + 1;
}
return h;
}
template <typename TreeNodeIndicator>
bool has_filiation(
TreeNodeIndicator parent,
TreeNodeIndicator child
)
{
return parent.get_pointer( )->m_left == child || parent.get_pointer( )->m_right == child;
}
template <typename TreeNodeIndicator>
TreeNodeIndicator * get_minimum_child(
TreeNodeIndicator * parent,
std::vector<TreeNodeIndicator *> & ancestors
)
{
assert( parent != NULL && parent->is_non_null( ) && parent->get_pointer( )->m_right.is_non_null( ) );
ancestors.push_back( parent );
TreeNodeIndicator * minimum_child = &parent->get_pointer( )->m_right;
while ( minimum_child->get_pointer( )->m_left.is_non_null( ) ) {
ancestors.push_back( minimum_child );
minimum_child = &minimum_child->get_pointer( )->m_left;
}
return minimum_child;
}
template <typename TreeNodeIndicator>
TreeNodeIndicator * get_other_child(
TreeNodeIndicator parent,
TreeNodeIndicator child
)
{
TreeNodeIndicator * another_child = &parent.get_pointer( )->m_left;
if ( *another_child == child ) {
another_child = &parent.get_pointer( )->m_right;
}
return another_child;
}
template <typename TreeNodeIndicator>
TreeNodeIndicator * get_other_child(
TreeNodeIndicator parent,
child_position this_child_position
)
{
return this_child_position == left_child ? &parent.get_pointer( )->m_right : &parent.get_pointer( )->m_left;
}
template <typename TreeNodeIndicator>
child_position get_child_position(
TreeNodeIndicator parent,
TreeNodeIndicator child
)
{
child_position cp = left_child;
if ( parent.get_pointer( )->m_right == child ) {
cp = right_child;
}
return cp;
}
template <typename TreeNodeIndicator>
bool in_the_same_branch(
TreeNodeIndicator grandparent,
TreeNodeIndicator parent,
TreeNodeIndicator child
)
{
return (
( grandparent.get_pointer( )->m_left == parent && parent.get_pointer( )->m_left == child ) ||
( grandparent.get_pointer( )->m_right == parent && parent.get_pointer( )->m_right == child )
);
}
template <typename TreeNodeIndicator>
TreeNodeIndicator * pop_without_doubt(
std::stack<TreeNodeIndicator *> & ancestors
)
{
assert( !ancestors.empty( ) );
TreeNodeIndicator * parent = ancestors.top( );
ancestors.pop( );
return parent;
}
template <typename TreeNodeIndicator>
TreeNodeIndicator * pop(
std::stack<TreeNodeIndicator *> & ancestors
)
{
TreeNodeIndicator * parent = NULL;
if ( !ancestors.empty( ) ) {
parent = pop_without_doubt( ancestors );
}
return parent;
}
template <typename T, typename TreeNodeIndicator>
search_result find(
TreeNodeIndicator const * const root,
typename boost::call_traits<T>::param_type t,
std::stack<TreeNodeIndicator *> * ancestors,
TreeNodeIndicator ** n
)
{
search_result sr = empty_tree;
if ( n != NULL && *n != NULL ) {
( *n )->pointer = NULL;
}
TreeNodeIndicator * node = const_cast<TreeNodeIndicator *>( root );
if ( node->is_non_null( ) ) {
if ( !node->value_equals( t ) ) {
for (
TreeNodeIndicator * p = node, *c = p;
c->is_non_null( );
ancestors != NULL ? ( ancestors->push( p ), 0 ) : 0
) {
p = c;
if ( c->value( ) > t ) {
c = &p->get_pointer( )->m_left;
sr = should_insert_as_left;
} else if ( c->value( ) < t ) {
c = &p->get_pointer( )->m_right;
sr = should_insert_as_right;
} else {
if ( n != NULL ) {
*n = c;
}
sr = found_node;
break;
}
}
} else {
if ( n != NULL ) {
*n = node;
}
sr = found_node;
}
}
return sr;
}
template <typename TreeNodeIndicator, typename Visitor>
void levelorder_visit( TreeNodeIndicator const root, Visitor visitor )
{
TreeNodeIndicator dummy;
if ( root.is_non_null( ) ) {
std::queue<TreeNodeIndicator const> q1, q2, *pq1 = &q1, *pq2 = &q2;
q1.push( root );
visitor( dummy );
while ( !pq1->empty( ) ) {
while ( !pq1->empty( ) ) {
TreeNodeIndicator n = pq1->front( );
visitor( n );
pq1->pop( );
if ( n.get_pointer( )->m_left.is_non_null( ) ) {
pq2->push( n.get_pointer( )->m_left );
}
if ( n.get_pointer( )->m_right.is_non_null( ) ) {
pq2->push( n.get_pointer( )->m_right );
}
}
visitor( dummy );
std::swap( pq1, pq2 );
}
}
}
}
}
#endif //GYM_BINARY_SEARCH_TREE_COMMON_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#ifndef GYM_AVL_TREE_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#define GYM_AVL_TREE_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#include "bst_common.h"
#include <algorithm>
namespace pratique
{
namespace details
{
template <typename T>
struct avl_tree_node
{
typedef union child {
avl_tree_node<T> * pointer;
intptr_t int_value;
child( avl_tree_node<T> * p = NULL, int balance = 0 ) : pointer( p )
{
set_balance( balance );
}
bool is_null() const { return pointer == NULL; }
bool is_non_null() const { return int_value > 1; }
int get_balance() const
{
int balance = int_value & 3;
assert( balance <= 2 );
if ( balance == 2 ) {
balance = -1;
}
return balance;
}
void set_balance( int balance )
{
assert( balance >= -1 && balance <= 1 );
if ( balance == -1 ) {
balance = 2;
}
int_value &= (~3);
int_value |= balance;
#if ( defined( DEBUG ) || defined( _DEBUG ) || defined( DBG ) )
if ( is_null() ) {
assert(balance == 0);
}
#endif
}
avl_tree_node<T> const * get_pointer() const
{
return const_cast<avl_tree_node<T> const *>(
reinterpret_cast<avl_tree_node<T> *>( int_value & (~3) )
);
}
avl_tree_node<T> * get_pointer()
{
return reinterpret_cast<avl_tree_node<T> *>( int_value & (~3) );
}
bool value_equals( typename boost::call_traits<T>::param_type t ) const
{
return is_non_null() && ( get_pointer()->m_data == t );
}
T const & value() const { assert( is_non_null() ); return get_pointer()->m_data; }
T & value() { assert( is_non_null() ); return get_pointer()->m_data; }
bool operator==( typename boost::call_traits<child>::param_type c ) const
{
return int_value == c.int_value;
}
bool operator!=( typename boost::call_traits<child>::param_type c ) const
{
return int_value != c.int_value;
}
} child_t;
struct hash
{
size_t operator()( child_t const c ) const
{
return std::hash<intptr_t>()( c.int_value );
}
};
T m_data;
child_t m_left, m_right;
avl_tree_node() : m_left{ NULL, false }, m_right{ NULL, false } {}
avl_tree_node( typename boost::call_traits<T>::param_type t ) : m_data{ t }, m_left{ NULL, false }, m_right{ NULL, false } {}
};
template <typename T>
bool check_balance_attributes( typename avl_tree_node<T>::child_t const root )
{
bool passed = true;
if ( root.is_non_null( ) ) {
auto left = root.get_pointer( )->m_left, right = root.get_pointer( )->m_right;
int diff = static_cast<int>( height( left ) ) - static_cast<int>( height( right ) );
passed = ( diff >= -1 && diff <= 1 ) && ( root.get_balance( ) == diff );
if ( passed ) {
passed = check_balance_attributes<T>( left ) && check_balance_attributes<T>( right );
}
}
return passed;
}
template <typename T>
bool is_avl_tree( typename avl_tree_node<T>::child_t const root )
{
return check_balance_attributes<T>( root );
}
}
template <typename T>
class avl_tree
{
typename details::avl_tree_node<T>::child_t m_root;
inline typename details::avl_tree_node<T>::child_t * reset_parent(
typename details::avl_tree_node<T>::child_t * grandparent,
typename details::avl_tree_node<T>::child_t new_parent,
details::child_position pcp
) {
typename details::avl_tree_node<T>::child_t * pointer_to_new_parent = NULL;
if ( grandparent != NULL ) {
if ( pcp == details::left_child ) {
grandparent->get_pointer()->m_left = new_parent;
pointer_to_new_parent = &grandparent->get_pointer()->m_left;
} else {
grandparent->get_pointer()->m_right = new_parent;
pointer_to_new_parent = &grandparent->get_pointer()->m_right;
}
} else {
m_root = new_parent;
pointer_to_new_parent = &m_root;
}
return pointer_to_new_parent;
}
inline typename details::avl_tree_node<T>::child_t * left_rotate(
typename details::avl_tree_node<T>::child_t * grandparent,
typename details::avl_tree_node<T>::child_t parent,
typename details::avl_tree_node<T>::child_t child,
int parent_balance = 0,
int child_balance = 0
)
{
assert( grandparent == NULL || details::has_filiation( *grandparent, parent ) );
assert( details::has_filiation( parent, child ) );
details::child_position pcp = details::left_child;
if ( grandparent != NULL ) {
pcp = details::get_child_position( *grandparent, parent );
}
parent.set_balance( parent_balance );
child.set_balance( child_balance );
parent.get_pointer()->m_left = child.get_pointer()->m_right;
child.get_pointer()->m_right = parent;
return reset_parent( grandparent, child, pcp );
}
inline typename details::avl_tree_node<T>::child_t * right_rotate(
typename details::avl_tree_node<T>::child_t * grandparent,
typename details::avl_tree_node<T>::child_t parent,
typename details::avl_tree_node<T>::child_t child,
int parent_balance = 0,
int child_balance = 0
)
{
assert( grandparent == NULL || details::has_filiation( *grandparent, parent ) );
assert( details::has_filiation( parent, child ) );
details::child_position pcp = details::left_child;
if ( grandparent != NULL ) {
pcp = details::get_child_position( *grandparent, parent );
}
parent.set_balance( parent_balance );
child.set_balance( child_balance );
parent.get_pointer()->m_right = child.get_pointer()->m_left;
child.get_pointer()->m_left = parent;
return reset_parent( grandparent, child, pcp );
}
inline typename details::avl_tree_node<T>::child_t * left_rotate(
typename details::avl_tree_node<T>::child_t * new_grandparent,
typename details::avl_tree_node<T>::child_t grandparent,
typename details::avl_tree_node<T>::child_t parent,
typename details::avl_tree_node<T>::child_t child
)
{
int child_balance = child.get_balance();
assert( new_grandparent == NULL || details::has_filiation( *new_grandparent, grandparent ) );
assert( details::has_filiation( grandparent, parent ) );
assert( details::has_filiation( parent, child ) );
details::child_position gcp = details::left_child;
if ( new_grandparent != NULL ) {
gcp = details::get_child_position( *new_grandparent, grandparent );
}
if ( child_balance == -1 ) {
grandparent.set_balance( 0 );
parent.set_balance( 1 );
}
else if ( child_balance == 1 ) {
grandparent.set_balance( -1 );
parent.set_balance( 0 );
}
else {
grandparent.set_balance( 0 );
parent.set_balance( 0 );
}
child.set_balance( 0 );
parent.get_pointer()->m_right = child.get_pointer()->m_left;
child.get_pointer()->m_left = parent;
grandparent.get_pointer()->m_left = child.get_pointer()->m_right;
child.get_pointer()->m_right = grandparent;
return reset_parent( new_grandparent, child, gcp );
}
inline typename details::avl_tree_node<T>::child_t * right_rotate(
typename details::avl_tree_node<T>::child_t * new_grandparent,
typename details::avl_tree_node<T>::child_t grandparent,
typename details::avl_tree_node<T>::child_t parent,
typename details::avl_tree_node<T>::child_t child
)
{
int child_balance = child.get_balance();
assert( new_grandparent == NULL || details::has_filiation( *new_grandparent, grandparent ) );
assert( details::has_filiation( grandparent, parent ) );
assert( details::has_filiation( parent, child ) );
details::child_position gcp = details::left_child;
if ( new_grandparent != NULL ) {
gcp = details::get_child_position( *new_grandparent, grandparent );
}
if ( child_balance == -1 ) {
grandparent.set_balance( 1 );
parent.set_balance( 0 );
}
else if ( child_balance == 1 ) {
grandparent.set_balance( 0 );
parent.set_balance( -1 );
}
else {
grandparent.set_balance( 0 );
parent.set_balance( 0 );
}
child.set_balance( 0 );
parent.get_pointer()->m_left = child.get_pointer()->m_right;
child.get_pointer()->m_right = parent;
grandparent.get_pointer()->m_right = child.get_pointer()->m_left;
child.get_pointer()->m_left = grandparent;
return reset_parent( new_grandparent, child, gcp );
}
void insertion_rebalance(
typename details::avl_tree_node<T>::child_t * child,
std::stack<typename details::avl_tree_node<T>::child_t *> & ancestors
)
{
assert( child != NULL && child->is_non_null() && !ancestors.empty() );
for (
typename details::avl_tree_node<T>::child_t * parent = details::pop_without_doubt( ancestors );
parent != NULL;
parent = details::pop( ancestors )
) {
assert( details::has_filiation( *parent, *child ) );
details::child_position ccp = details::get_child_position( *parent, *child );
int parent_balance = parent->get_balance();
assert( parent_balance >= -1 && parent_balance <= 1 );
if ( ccp == details::left_child ) {
if ( parent_balance == -1 ) {
parent->set_balance( 0 );
break;
}
else if ( parent_balance == 0 ) {
parent->set_balance( 1 );
child = parent;
}
else {
assert( parent_balance == 1 );
typename details::avl_tree_node<T>::child_t * grandparent = NULL;
if ( !ancestors.empty() ) {
grandparent = ancestors.top();
assert( details::has_filiation( *grandparent, *parent ) );
}
int child_balance = child->get_balance();
if ( child_balance == -1 ) {
left_rotate( grandparent, *parent, *child, child->get_pointer()->m_right );
break;
}
else if ( child_balance == 0 ) {
child = left_rotate( grandparent, *parent, *child, 1, -1 );
}
else {
assert( child_balance == 1 );
left_rotate( grandparent, *parent, *child );
break;
}
}
}
else {
if ( parent_balance == -1 ) {
typename details::avl_tree_node<T>::child_t * grandparent = NULL;
if ( !ancestors.empty() ) {
grandparent = ancestors.top();
assert( details::has_filiation( *grandparent, *parent ) );
}
int child_balance = child->get_balance();
if ( child_balance == -1 ) {
right_rotate( grandparent, *parent, *child );
break;
}
else if ( child_balance == 0 ) {
child = right_rotate( grandparent, *parent, *child, -1, 1 );
}
else {
assert( child_balance == 1 );
right_rotate( grandparent, *parent, *child, child->get_pointer()->m_left );
break;
}
}
else if ( parent_balance == 0 ) {
parent->set_balance( -1 );
child = parent;
}
else {
parent->set_balance( 0 );
break;
}
}
}
}
typename details::avl_tree_node<T>::child_t * transplant(
typename details::avl_tree_node<T>::child_t expellee_parent,
typename details::avl_tree_node<T>::child_t expellee,
typename details::avl_tree_node<T>::child_t replacer
)
{
assert( details::has_filiation( expellee_parent, expellee ) );
assert( !expellee.is_null() );
if ( !replacer.is_null() ) {
if ( !details::has_filiation( expellee, replacer ) ) {
replacer.get_pointer()->m_left = expellee.get_pointer()->m_left;
replacer.get_pointer()->m_right = expellee.get_pointer()->m_right;
replacer.set_balance( expellee.get_balance() );
}
else {
if ( expellee.get_pointer()->m_left == replacer ) {
replacer.get_pointer()->m_right = expellee.get_pointer()->m_right;
assert( replacer.get_pointer()->m_left.is_null() );
replacer.set_balance( expellee.get_balance() - 1 );
}
else {
replacer.get_pointer()->m_left = expellee.get_pointer()->m_left;
assert( replacer.get_pointer()->m_right.is_null() );
replacer.set_balance( expellee.get_balance() + 1 );
}
}
}
typename details::avl_tree_node<T>::child_t * new_child;
auto ecp = details::get_child_position( expellee_parent, expellee );
if ( ecp == details::left_child ) {
expellee_parent.get_pointer()->m_left = replacer;
new_child = &expellee_parent.get_pointer()->m_left;
}
else {
expellee_parent.get_pointer()->m_right = replacer;
new_child = &expellee_parent.get_pointer()->m_right;
}
if ( m_root == expellee ) {
m_root = *new_child;
}
return new_child;
}
void erasing_rebalance(
typename details::avl_tree_node<T>::child_t * replacement,
details::child_position rcp,
std::stack<typename details::avl_tree_node<T>::child_t *> & ancestors
)
{
while ( !ancestors.empty() ) {
typename details::avl_tree_node<T>::child_t * parent = details::pop_without_doubt( ancestors ), * grandparent = NULL;
assert( details::has_filiation( *parent, *replacement ) );
details::child_position pcp = details::left_child;
if ( !ancestors.empty() ) {
grandparent = ancestors.top();
pcp = details::get_child_position( *grandparent, *parent );
parent = &grandparent->get_pointer()->m_left;
if ( pcp == details::right_child ) {
parent = &grandparent->get_pointer()->m_right;
}
}
else {
parent = &m_root;
}
int parent_balance = parent->get_balance();
assert( parent_balance >= -1 && parent_balance <= 1 );
if ( rcp == details::left_child ) {
if ( parent_balance == -1 ) {
typename details::avl_tree_node<T>::child_t * sibling = details::get_other_child( *parent, rcp );
int sibling_balance = sibling->get_balance();
if ( sibling_balance == -1 ) {
right_rotate( grandparent, *parent, *sibling );
}
else if ( sibling_balance == 0 ) {
right_rotate( grandparent, *parent, *sibling, -1, 1 );
break;
}
else {
assert( sibling_balance == 1 );
right_rotate( grandparent, *parent, *sibling, sibling->get_pointer()->m_left );
}
if ( grandparent != NULL ) {
rcp = details::left_child;
replacement = &grandparent->get_pointer()->m_left;
if ( pcp == details::right_child ) {
rcp = details::right_child;
replacement = &grandparent->get_pointer()->m_right;
}
}
}
else if ( parent_balance == 0 ) {
parent->set_balance( -1 );
break;
}
else {
assert( parent_balance == 1 );
parent->set_balance( 0 );
replacement = parent;
if ( !ancestors.empty() ) {
rcp = details::get_child_position( *ancestors.top(), *replacement );
}
}
}
else {
if ( parent_balance == -1 ) {
parent->set_balance( 0 );
replacement = parent;
if ( !ancestors.empty() ) {
rcp = details::get_child_position( *ancestors.top(), *replacement );
}
}
else if ( parent_balance == 0 ) {
parent->set_balance( 1 );
break;
}
else {
assert( parent_balance == 1 );
typename details::avl_tree_node<T>::child_t * sibling = details::get_other_child( *parent, rcp );
int sibling_balance = sibling->get_balance();
if ( sibling_balance == -1 ) {
left_rotate( grandparent, *parent, *sibling, sibling->get_pointer()->m_right );
}
else if ( sibling_balance == 0 ) {
left_rotate( grandparent, *parent, *sibling, 1, -1 );
break;
}
else {
assert( sibling_balance == 1 );
left_rotate( grandparent, *parent, *sibling );
}
if ( grandparent != NULL ) {
rcp = details::left_child;
replacement = &grandparent->get_pointer()->m_left;
if ( pcp == details::right_child ) {
rcp = details::right_child;
replacement = &grandparent->get_pointer()->m_right;
}
}
}
}
}
}
public:
avl_tree() {}
avl_tree( avl_tree<T> const & );
avl_tree<T> & operator=( avl_tree<T> const & );
void insert( typename boost::call_traits<T>::param_type t )
{
assert( details::is_avl_tree<T>( m_root ) );
std::stack<typename details::avl_tree_node<T>::child_t *> ancestors;
typename details::avl_tree_node<T>::child_t * child = NULL;
details::search_result sr = details::find<T>( &m_root, t, &ancestors, &child );
if ( ( sr & ( details::empty_tree | details::should_insert_as_left | details::should_insert_as_right ) ) != 0 ) {
details::avl_tree_node<T> * new_node = new details::avl_tree_node<T>( t );
switch ( sr ) {
case details::empty_tree:
assert( m_root.is_null() );
m_root.pointer = new_node;
return;
case details::should_insert_as_left:
ancestors.top()->get_pointer()->m_left.pointer = new_node;
child = &ancestors.top()->get_pointer()->m_left;
break;
case details::should_insert_as_right:
ancestors.top()->get_pointer()->m_right.pointer = new_node;
child = &ancestors.top()->get_pointer()->m_right;
break;
default:
assert( false && "bug" );
}
insertion_rebalance( child, ancestors );
assert( details::is_avl_tree<T>( m_root ) );
}
}
void erase( typename boost::call_traits<T>::param_type t )
{
assert( details::is_avl_tree<T>( m_root ) );
std::stack<typename details::avl_tree_node<T>::child_t *> ancestors;
details::avl_tree_node<T> dummy_node;
typename details::avl_tree_node<T>::child_t * expellee = NULL, dummy;
auto result = details::find<T>( &m_root, t, &ancestors, &expellee );
if ( result == details::found_node ) {
details::child_position rcp;
typename details::avl_tree_node<T>::child_t expellee_ref;
typename details::avl_tree_node<T>::child_t * expellee_parent = NULL;
if ( !ancestors.empty() ) {
expellee_parent = ancestors.top();
}
if ( expellee_parent == NULL ) {
assert( m_root == *expellee );
dummy_node.m_left = m_root;
dummy.pointer = &dummy_node;
expellee_parent = &dummy;
}
expellee_ref = *expellee;
assert( expellee != NULL && expellee->is_non_null() );
typename details::avl_tree_node<T>::child_t * replacement;
if ( expellee->get_pointer()->m_right.is_non_null() ) {
std::vector<typename details::avl_tree_node<T>::child_t *> new_ancestors;
replacement = details::get_minimum_child( expellee, new_ancestors );
assert( replacement != NULL && replacement->is_non_null() );
assert( !new_ancestors.empty() );
assert( details::height( *replacement ) <= 2 );
auto replacement_ref = *replacement;
auto expellee_ref = *expellee;
rcp = details::get_child_position( *new_ancestors.back(), replacement_ref );
replacement = transplant( *new_ancestors.back(), replacement_ref, replacement_ref.get_pointer()->m_right );
expellee = transplant( *expellee_parent, expellee_ref, replacement_ref );
ancestors.push( expellee );
std::for_each(
new_ancestors.begin() + 1, new_ancestors.end(),
[ &ancestors ]( typename details::avl_tree_node<T>::child_t * node ) { ancestors.push( node ); }
);
} else {
assert( details::height( *expellee ) <= 2 );
rcp = details::get_child_position( *expellee_parent, *expellee );
replacement = transplant( *expellee_parent, *expellee, expellee->get_pointer()->m_left );
}
erasing_rebalance( replacement, rcp, ancestors );
delete expellee_ref.get_pointer();
assert( details::is_avl_tree<T>( m_root ) );
}
}
template <typename Visitor>
void levelorder_visit( Visitor visitor ) const
{
details::levelorder_visit( m_root, visitor );
}
bool is_valid( ) const { return details::is_avl_tree<T>( m_root ); }
};
}
#endif //GYM_AVL_TREE_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#ifndef GYM_RED_BLACK_TREE_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#define GYM_RED_BLACK_TREE_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4
#include "bst_common.h"
#include <algorithm>
#include <unordered_map>
namespace pratique
{
namespace details
{
template <typename T>
struct rbtree_node
{
typedef union child {
rbtree_node<T> * pointer;
intptr_t int_value;
child( rbtree_node<T> * p = NULL, bool red = false ) : pointer( p )
{
if ( red ) {
set_red();
}
}
bool is_null() const { return pointer == NULL; }
bool is_non_null() const { return int_value > 1; }
bool is_red() const { assert( is_non_null() ); return ( int_value & 1 ) != 0; }
bool is_black() const { return ( int_value & 1 ) == 0; }
void set_red() { assert( is_non_null() ); int_value |= 1; }
void set_black() { int_value &= ~1; }
void set_color( bool red )
{
if ( red ) { set_red(); } else { set_black(); }
}
rbtree_node<T> const * get_pointer() const
{
rbtree_node<T> const * p = pointer;
if ( is_red() ) {
p = reinterpret_cast<rbtree_node<T> const *>( int_value & ~1 );
}
return p;
}
rbtree_node<T> * get_pointer()
{
rbtree_node<T> * p = pointer;
if ( is_red() ) {
p = reinterpret_cast<rbtree_node<T> *>( int_value & ~1 );
}
return p;
}
bool value_equals( typename boost::call_traits<T>::param_type t ) const
{
return is_non_null() && ( get_pointer()->m_data == t );
}
T const & value() const { assert( is_non_null() ); return get_pointer()->m_data; }
T & value() { assert( is_non_null() ); return get_pointer()->m_data; }
bool operator==( typename boost::call_traits<child>::param_type c ) const
{
return int_value == c.int_value;
}
bool operator!=( typename boost::call_traits<child>::param_type c ) const
{
return int_value != c.int_value;
}
} child_t;
struct hash
{
size_t operator()( child_t const c ) const
{
return std::hash<intptr_t>()( c.int_value );
}
};
T m_data;
child_t m_left, m_right;
rbtree_node() : m_left{ NULL, false }, m_right{ NULL, false } {}
rbtree_node( typename boost::call_traits<T>::param_type t ) : m_data{ t }, m_left{ NULL, false }, m_right{ NULL, false } {}
};
template <typename T>
bool check_red_black_attributes( typename rbtree_node<T>::child_t const root )
{
bool passed = true;
if ( root.is_non_null() ) {
auto left = root.get_pointer()->m_left, right = root.get_pointer()->m_right;
if ( root.is_red() ) {
passed = left.is_black() && right.is_black();
}
if ( passed ) {
passed = check_red_black_attributes<T>( left ) && check_red_black_attributes<T>( right );
}
}
return passed;
}
template <typename T>
bool compute_black_height(
int starting_height,
typename rbtree_node<T>::child_t const node,
int & ending_height
)
{
bool successful = true;
ending_height = starting_height;
if ( node.is_non_null() ) {
if ( node.is_black() ) {
++starting_height;
}
if ( node.get_pointer()->m_left.is_non_null() || node.get_pointer()->m_right.is_non_null() ) {
int left_height, right_height;
successful = (
compute_black_height<T>( starting_height, node.get_pointer()->m_left, left_height ) &&
compute_black_height<T>( starting_height, node.get_pointer()->m_right, right_height ) &&
left_height == right_height
);
if ( successful ) {
ending_height = left_height;
}
}
else {
ending_height = starting_height;
}
}
return successful;
}
template <typename T>
bool is_rb_tree( typename rbtree_node<T>::child_t const root )
{
int height = 0;
return compute_black_height<T>( 0, root, height ) && root.is_black() && check_red_black_attributes<T>( root );
}
}
// In fact what I implement is the 2-3-4-tree
template <typename T>
class rbtree
{
typename details::rbtree_node<T>::child_t m_root;
void rebalance_nodes_in_the_different_branch(
std::stack<typename details::rbtree_node<T>::child_t *> & ancestors,
typename details::rbtree_node<T>::child_t ** parent,
typename details::rbtree_node<T>::child_t ** child,
details::child_position * ccp
)
{
assert( details::has_filiation( **parent, **child ) );
typename details::rbtree_node<T>::child_t * grandparent = ancestors.top();
details::child_position pcp = details::get_child_position( *grandparent, **parent );
*ccp = details::get_child_position( **parent, **child );
if ( pcp != *ccp ) {
typename details::rbtree_node<T>::child_t parent_ref = **parent;
typename details::rbtree_node<T>::child_t child_ref = **child;
if ( *ccp == details::left_child ) {
parent_ref.get_pointer()->m_left = child_ref.get_pointer()->m_right;
child_ref.get_pointer()->m_right = parent_ref;
grandparent->get_pointer()->m_right = child_ref;
*parent = &grandparent->get_pointer()->m_right;
*child = &( *parent )->get_pointer()->m_right;
*ccp = details::right_child;
}
else {
parent_ref.get_pointer()->m_right = child_ref.get_pointer()->m_left;
child_ref.get_pointer()->m_left = parent_ref;
grandparent->get_pointer()->m_left = child_ref;
*parent = &grandparent->get_pointer()->m_left;
*child = &( *parent )->get_pointer()->m_left;
*ccp = details::left_child;
}
}
}
void rebalance_nodes_in_the_same_branch(
std::stack<typename details::rbtree_node<T>::child_t *> & ancestors,
typename details::rbtree_node<T>::child_t * parent,
typename details::rbtree_node<T>::child_t ** child,
details::child_position ccp
)
{
assert( !ancestors.empty() && details::has_filiation( *parent, **child ) );
typename details::rbtree_node<T>::child_t * grandparent = details::pop_without_doubt( ancestors );
typename details::rbtree_node<T>::child_t * new_grandparent = NULL;
details::child_position gcp = details::left_child;
if ( !ancestors.empty() ) {
new_grandparent = ancestors.top();
gcp = details::get_child_position( *new_grandparent, *grandparent );
}
auto parent_ref = *parent;
if ( ccp == details::left_child ) {
grandparent->get_pointer()->m_left = parent_ref.get_pointer()->m_right;
parent_ref.get_pointer()->m_right = *grandparent;
}
else {
grandparent->get_pointer()->m_right = parent_ref.get_pointer()->m_left;
parent_ref.get_pointer()->m_left = *grandparent;
}
(*child)->set_black();
if ( new_grandparent != NULL && new_grandparent->is_non_null() ) {
if ( gcp == details::left_child ) {
new_grandparent->get_pointer()->m_left = parent_ref;
parent = &new_grandparent->get_pointer()->m_left;
}
else {
new_grandparent->get_pointer()->m_right = parent_ref;
parent = &new_grandparent->get_pointer()->m_right;
}
}
else {
m_root = parent_ref;
}
*child = parent;
}
void insertion_rebalance(
typename details::rbtree_node<T>::child_t * child,
std::stack<typename details::rbtree_node<T>::child_t *> & ancestors
)
{
assert( child != NULL && child->is_non_null() && !ancestors.empty() );
for ( typename details::rbtree_node<T>::child_t * parent = details::pop_without_doubt( ancestors ); parent != NULL; parent = details::pop( ancestors ) ) {
assert( details::has_filiation( *parent, *child ) );
typename details::rbtree_node<T>::child_t * sibling = details::get_other_child( *parent, *child );
if ( !sibling->is_black() ) { // cannot call is_red()
child->set_black();
sibling->set_black();
child = parent;
child->set_red();
}
else {
if ( parent->is_red() && !ancestors.empty() ) {
details::child_position ccp;
rebalance_nodes_in_the_different_branch( ancestors, &parent, &child, &ccp );
rebalance_nodes_in_the_same_branch( ancestors, parent, &child, ccp );
}
else {
if ( ancestors.empty() ) {
m_root = *parent;
}
break;
}
}
}
}
typename details::rbtree_node<T>::child_t * transplant(
typename details::rbtree_node<T>::child_t expellee_parent,
typename details::rbtree_node<T>::child_t expellee,
typename details::rbtree_node<T>::child_t replacer
)
{
assert( details::has_filiation( expellee_parent, expellee ) );
assert( !expellee.is_null() );
if ( !replacer.is_null() ) {
if ( !details::has_filiation( expellee, replacer ) ) {
replacer.get_pointer()->m_left = expellee.get_pointer()->m_left;
replacer.get_pointer()->m_right = expellee.get_pointer()->m_right;
}
else {
if ( expellee.get_pointer()->m_left == replacer ) {
replacer.get_pointer()->m_right = expellee.get_pointer()->m_right;
assert( replacer.get_pointer()->m_left.is_null() );
}
else {
replacer.get_pointer()->m_left = expellee.get_pointer()->m_left;
assert( replacer.get_pointer()->m_right.is_null() );
}
}
replacer.set_color( expellee.is_red() );
}
typename details::rbtree_node<T>::child_t * new_child;
auto ecp = details::get_child_position( expellee_parent, expellee );
if ( ecp == details::left_child ) {
expellee_parent.get_pointer()->m_left = replacer;
new_child = &expellee_parent.get_pointer()->m_left;
}
else {
expellee_parent.get_pointer()->m_right = replacer;
new_child = &expellee_parent.get_pointer()->m_right;
}
if ( m_root == expellee ) {
m_root = *new_child;
}
return new_child;
}
// After rotating, the child and the parent change their position
void rotate(
typename details::rbtree_node<T>::child_t * grandparent,
typename details::rbtree_node<T>::child_t parent,
typename details::rbtree_node<T>::child_t child,
typename details::rbtree_node<T>::child_t ** new_parent = NULL,
typename details::rbtree_node<T>::child_t ** new_child = NULL
)
{
assert( grandparent == NULL || details::has_filiation( *grandparent, parent ) );
assert( details::has_filiation( parent, child ) );
details::child_position ccp = details::get_child_position( parent, child );
details::child_position pcp = details::left_child;
if ( grandparent != NULL ) {
pcp = details::get_child_position( *grandparent, parent );
}
if ( ccp == details::left_child ) {
parent.get_pointer()->m_left = child.get_pointer()->m_right;
child.get_pointer()->m_right = parent;
if ( new_child != NULL ) {
*new_child = &child.get_pointer()->m_right;
}
} else {
parent.get_pointer()->m_right = child.get_pointer()->m_left;
child.get_pointer()->m_left = parent;
if ( new_child != NULL ) {
*new_child = &child.get_pointer()->m_left;
}
}
if ( grandparent != NULL ) {
if ( pcp == details::left_child ) {
grandparent->get_pointer()->m_left = child;
if ( new_parent != NULL ) {
*new_parent = &grandparent->get_pointer()->m_left;
}
} else {
grandparent->get_pointer()->m_right = child;
if ( new_parent != NULL ) {
*new_parent = &grandparent->get_pointer()->m_right;
}
}
} else {
m_root = child;
if ( new_parent != NULL ) {
*new_parent = &m_root;
}
}
}
void erasing_rebalance(
typename details::rbtree_node<T>::child_t * replacement,
details::child_position rcp,
std::stack<typename details::rbtree_node<T>::child_t *> & ancestors
)
{
assert( !ancestors.empty() );
for (
typename details::rbtree_node<T>::child_t * parent = details::pop_without_doubt( ancestors );
parent != NULL;
parent = details::pop( ancestors )
) {
assert( details::has_filiation( *parent, *replacement ) );
typename details::rbtree_node<T>::child_t * grandparent = NULL;
if ( !ancestors.empty() ) {
grandparent = ancestors.top();
assert(details::has_filiation(*grandparent, *parent));
if ( details::get_child_position(*grandparent, *parent) == details::left_child ) {
parent = &grandparent->get_pointer()->m_left;
}
else {
parent = &grandparent->get_pointer()->m_right;
}
}
else {
parent = &m_root;
}
typename details::rbtree_node<T>::child_t * sibling = details::get_other_child( *parent, rcp );
if ( sibling->is_non_null() && sibling->is_black() && sibling->get_pointer()->m_left.is_black() && sibling->get_pointer()->m_right.is_black() ) {
sibling->set_red();
if ( parent->is_black() ) {
replacement = parent;
if ( !ancestors.empty() ) {
rcp = details::get_child_position( *ancestors.top(), *replacement );
}
}
else {
parent->set_black();
break;
}
}
else {
if ( !sibling->is_black() ) {
// we cannot use the logical listed in CLRS, because our implementation is based on 2-3-4-tree
assert( details::has_filiation( *parent, *replacement ) );
assert( parent->is_black() );
if ( !ancestors.empty() ) {
grandparent = ancestors.top();
}
sibling->set_black();
if ( rcp == details::left_child ) {
if ( sibling->get_pointer()->m_left.is_non_null() ) {
sibling->get_pointer()->m_left.set_red();
}
}
else {
if ( sibling->get_pointer()->m_right.is_non_null() ) {
sibling->get_pointer()->m_right.set_red();
}
}
rotate( grandparent, *parent, *sibling, &grandparent, &parent );
if ( rcp == details::left_child ) {
sibling = &parent->get_pointer()->m_right;
} else {
sibling = &parent->get_pointer()->m_left;
}
assert( details::has_filiation( *grandparent, *parent ) );
assert( details::has_filiation( *parent, *replacement ) );
assert( details::has_filiation( *parent, *sibling ) );
if ( sibling->is_non_null() ) {
bool left_is_red = !sibling->get_pointer()->m_left.is_black(), right_is_red = !sibling->get_pointer()->m_right.is_black();
if ( left_is_red || right_is_red ) {
typename details::rbtree_node<T>::child_t * child = &sibling->get_pointer()->m_left;
if ( right_is_red ) {
child = &sibling->get_pointer()->m_right;
}
std::stack<typename details::rbtree_node<T>::child_t *> new_ancestors;
new_ancestors.push( grandparent );
new_ancestors.push( parent );
parent = sibling;
details::child_position ccp;
rebalance_nodes_in_the_different_branch(new_ancestors, &parent, &child, &ccp);
rebalance_nodes_in_the_same_branch(new_ancestors, parent, &child, ccp);
}
}
}
else {
if ( rcp == details::left_child ) {
if ( !sibling->get_pointer()->m_left.is_black() ) {
sibling->set_red();
sibling->get_pointer()->m_left.set_black();
rotate( parent, *sibling, sibling->get_pointer()->m_left );
sibling = &parent->get_pointer()->m_right;
}
sibling->set_color( parent->is_red() );
parent->set_black();
sibling->get_pointer()->m_right.set_black();
rotate( grandparent, *parent, *sibling );
} else {
if ( !sibling->get_pointer()->m_right.is_black() ) {
sibling->set_red();
sibling->get_pointer()->m_right.set_black();
rotate( parent, *sibling, sibling->get_pointer()->m_right );
sibling = &parent->get_pointer()->m_left;
}
sibling->set_color( parent->is_red() );
parent->set_black();
sibling->get_pointer()->m_left.set_black();
rotate( grandparent, *parent, *sibling );
}
}
break;
}
}
}
struct height_record
{
size_t height;
size_t width;
};
static void calculate_height(
typename details::rbtree_node<T>::child_t const node,
std::unordered_map<typename details::rbtree_node<T>::child_t const, height_record, typename details::rbtree_node<T>::hash> & cache
)
{
if ( cache.find( node ) == cache.end() && node.is_non_null() ) {
calculate_height( node.get_pointer()->m_left, cache );
height_record & left = cache[ node.get_pointer()->m_left ];
calculate_height( node.get_pointer()->m_right, cache );
height_record & right = cache[ node.get_pointer()->m_right ];
size_t width = left.height + right.height;
if ( width < left.width ) {
width = left.width;
}
if ( width < right.width ) {
width = right.width;
}
height_record self = { ( left.height < right.height ? right.height : left.height ) + 1, width };
cache[ node ] = std::move( self );
}
}
public:
rbtree() {}
rbtree( rbtree<T> const & );
rbtree<T> & operator=( rbtree<T> const & );
void insert( typename boost::call_traits<T>::param_type t )
{
assert( details::is_rb_tree<T>( m_root ) );
std::stack<typename details::rbtree_node<T>::child_t *> stack;
typename details::rbtree_node<T>::child_t * child = NULL;
details::search_result sr = details::find<T>( &m_root, t, &stack, &child );
if ( ( sr & ( details::empty_tree | details::should_insert_as_left | details::should_insert_as_right ) ) != 0 ) {
details::rbtree_node<T> * new_node = new details::rbtree_node<T>( t );
switch ( sr ) {
case details::empty_tree:
assert( m_root.is_null() );
m_root.pointer = new_node;
return;
case details::should_insert_as_left:
stack.top()->get_pointer()->m_left.pointer = new_node;
child = &stack.top()->get_pointer()->m_left;
break;
case details::should_insert_as_right:
stack.top()->get_pointer()->m_right.pointer = new_node;
child = &stack.top()->get_pointer()->m_right;
break;
default:
assert( false && "bug" );
}
child->set_red();
insertion_rebalance( child, stack );
m_root.set_black();
}
assert( details::is_rb_tree<T>( m_root ) );
}
size_t width() const
{
std::unordered_map<typename details::rbtree_node<T>::child_t const, height_record, typename details::rbtree_node<T>::hash> cache;
height_record hr = { 0, 0 };
cache[ typename details::rbtree_node<T>::child_t() ] = std::move( hr );
calculate_height( m_root, cache );
return cache[ m_root ].width;
}
void erase( typename boost::call_traits<T>::param_type t )
{
assert( details::is_rb_tree<T>( m_root ) );
bool need_to_reblance = false;
std::stack<typename details::rbtree_node<T>::child_t *> ancestors;
details::rbtree_node<T> dummy_node;
details::child_position rcp;
typename details::rbtree_node<T>::child_t * expellee = NULL, dummy;
auto result = details::find<T>( &m_root, t, &ancestors, &expellee );
if ( result == details::found_node ) {
typename details::rbtree_node<T>::child_t expellee_ref;
need_to_reblance = true;
typename details::rbtree_node<T>::child_t * expellee_parent = NULL;
if ( !ancestors.empty() ) {
expellee_parent = ancestors.top();
}
if ( expellee_parent == NULL ) {
assert( m_root == *expellee );
dummy_node.m_left = m_root;
dummy.pointer = &dummy_node;
expellee_parent = &dummy;
}
expellee_ref = *expellee;
assert( expellee != NULL && expellee->is_non_null() );
typename details::rbtree_node<T>::child_t * replacement;
if ( expellee->get_pointer()->m_right.is_non_null() ) {
std::vector<typename details::rbtree_node<T>::child_t *> new_ancestors;
replacement = details::get_minimum_child( expellee, new_ancestors );
assert( replacement != NULL && replacement->is_non_null() );
assert( !new_ancestors.empty() );
assert( details::height( *replacement ) <= 2 );
if ( replacement->get_pointer()->m_right.is_non_null() || replacement->is_red() ) {
//the replacement is a 3-node, we only need to change the 3-node to a 2-node
if ( replacement->get_pointer()->m_right.is_non_null() ) {
assert( replacement->get_pointer()->m_right.is_red() && replacement->is_black() );
replacement->get_pointer()->m_right.set_black();
}
need_to_reblance = false;
}
auto replacement_ref = *replacement;
auto expellee_ref = *expellee;
rcp = details::get_child_position( *new_ancestors.back(), replacement_ref );
replacement = transplant( *new_ancestors.back(), replacement_ref, replacement_ref.get_pointer()->m_right );
expellee = transplant( *expellee_parent, expellee_ref, replacement_ref );
if ( need_to_reblance ) {
ancestors.push( expellee );
std::for_each(
new_ancestors.begin() + 1, new_ancestors.end(),
[&ancestors]( typename details::rbtree_node<T>::child_t * node ) { ancestors.push( node ); }
);
}
}
else {
assert( details::height( *expellee ) <= 2 );
need_to_reblance = *expellee != m_root;
if ( expellee->get_pointer()->m_left.is_non_null() ) {
//it is a 3-node
assert( expellee->get_pointer()->m_left.is_red() );
need_to_reblance = false;
}
else if ( expellee->is_red() ) {
//it is a 3-node
assert( expellee->get_pointer()->m_left.is_null() && expellee->get_pointer()->m_right.is_null() );
need_to_reblance = false;
}
rcp = details::get_child_position( *expellee_parent, *expellee );
replacement = transplant( *expellee_parent, *expellee, expellee->get_pointer()->m_left );
}
if ( need_to_reblance ) {
assert( replacement->is_null() );
erasing_rebalance( replacement, rcp, ancestors );
}
delete expellee_ref.get_pointer();
assert( details::is_rb_tree<T>( m_root ) );
}
}
template <typename Visitor>
void levelorder_visit( Visitor visitor ) const
{
details::levelorder_visit( m_root, visitor );
}
bool is_valid( ) const { return details::is_rb_tree<T>( m_root ); }
};
}
#endif //GYM_RED_BLACK_TREE_H_6D4EBDB0_5B18_4FC1_A34A_CBBF36FE95E4