1
0
forked from 0ad/0ad
0ad/source/dcdt/se/sr_tree.cpp
janwas 5bf9bca9ef fix/disable warnings.
there are too many W4 and "potentially uninitialized", so those are
disabled by 0ad_warning_disable.h.

the silly "int x = strlen" and very dangerous "int x = (void*)p" (and
vice versa) problems are fixed.

This was SVN commit r5526.
2007-12-23 12:18:57 +00:00

461 lines
12 KiB
C++

#include "precompiled.h"
#include "0ad_warning_disable.h"
# include "sr_tree.h"
//# define SR_USE_TRACE1
# include "sr_trace.h"
# define BLACK(x) ((x)->color==SrTreeNode::Black)
# define RED(x) ((x)->color==SrTreeNode::Red)
# define NIL SrTreeNode::null
/*==========================================================================
Note:
A binary search tree is a red-black tree if it satisfies :
1. Every node is either red or black
2. Every null leaf is black
3. If a node is red then both its children are black
4. Every simple path from a node to a descendant leaf contains the
same number of black nodes
============================================================================*/
//=============================== SrTreeNode ====================================
static SrTreeNode static_null(SrTreeNode::Black);
SrTreeNode* SrTreeNode::null = &static_null;
//=============================== SrTreeBase ====================================
//----------------------------- private methods ------------------------------
/*! Returns 0 and leaves _cur pointing to the found matching node if there is one.
Returns >0 if the key is to be inserted under _cur->right.
Returns <0 if the key is to be inserted under _cur->left.
If the tree is empty, _cur will be null and the integer returned is 1. */
int SrTreeBase::_search_node ( const SrTreeNode *key )
{
int cmp;
_cur = _root;
if ( _cur==NIL ) return 1;
while ( true )
{
cmp = _man->compare(key,_cur);
if ( cmp>0 )
{ if ( _cur->right!=NIL ) _cur=_cur->right; else return cmp;
}
else if ( cmp<0 )
{ if ( _cur->left!=NIL ) _cur=_cur->left; else return cmp;
}
else return cmp;
}
}
/*! Method for right rotation of the tree about a given node. */
void SrTreeBase::_rotate_right ( SrTreeNode *x )
{
SR_TRACE1("Rotate Right");
SrTreeNode *y = x->left;
x->left = y->right;
if ( y->right!=NIL ) y->right->parent=x;
y->parent = x->parent;
if ( x->parent!=NIL )
{ if ( x==x->parent->right ) x->parent->right=y;
else x->parent->left=y;
}
else _root = y;
y->right = x;
x->parent = y;
}
/*! Method for left rotation of the tree about a given node. */
void SrTreeBase::_rotate_left ( SrTreeNode *x )
{
SR_TRACE1("Rotate Left");
SrTreeNode *y = x->right;
x->right = y->left;
if ( y->left!=NIL ) y->left->parent=x;
y->parent = x->parent;
if ( x->parent!=NIL )
{ if ( x==x->parent->left ) x->parent->left=y;
else x->parent->right=y;
}
else _root = y;
y->left = x;
x->parent = y;
}
/*! Rebalance the tree after insertion of a node. */
void SrTreeBase::_rebalance ( SrTreeNode *x )
{
SR_TRACE1("Rebalance");
SrTreeNode *y;
while ( x!=_root && RED(x->parent) )
{ // if ( !x->parent->parent ) REPORT_ERROR
if ( x->parent==x->parent->parent->left )
{ y = x->parent->parent->right;
if ( RED(y) )
{ // handle case 1 (see CLR book, pp. 269)
x->parent->color = SrTreeNode::Black;
y->color = SrTreeNode::Black;
x->parent->parent->color = SrTreeNode::Red;
x = x->parent->parent;
}
else
{ if ( x==x->parent->right )
{ // transform case 2 into case 3 (see CLR book, pp. 269)
x = x->parent;
_rotate_left ( x );
}
// handle case 3 (see CLR book, pp. 269)
x->parent->color = SrTreeNode::Black;
x->parent->parent->color = SrTreeNode::Red;
_rotate_right ( x->parent->parent );
}
}
else
{ y = x->parent->parent->left;
if ( RED(y) )
{ // handle case 1 (see CLR book, pp. 269)
x->parent->color = SrTreeNode::Black;
y->color = SrTreeNode::Black;
x->parent->parent->color = SrTreeNode::Red;
x = x->parent->parent;
}
else
{ if ( x==x->parent->left )
{ // transform case 2 into case 3 (see CLR book, pp. 269)
x = x->parent;
_rotate_right ( x );
}
// handle case 3 (see CLR book, pp. 269)
x->parent->color = SrTreeNode::Black;
x->parent->parent->color = SrTreeNode::Red;
_rotate_left ( x->parent->parent );
}
}
}
}
/*! Method for restoring red-black properties after deletion. */
void SrTreeBase::_fix_remove ( SrTreeNode *x )
{
SR_TRACE1("Fix Remove");
while ( x!=_root && BLACK(x) )
{
if ( x==x->parent->left )
{ SrTreeNode *w = x->parent->right;
if ( RED(w) )
{ w->color = SrTreeNode::Black;
x->parent->color = SrTreeNode::Red;
_rotate_left ( x->parent );
w = x->parent->right;
}
if ( BLACK(w->left) && BLACK(w->right) )
{ w->color = SrTreeNode::Red;
x = x->parent;
}
else
{ if ( BLACK(w->right) )
{ w->left->color = SrTreeNode::Black;
w->color = SrTreeNode::Red;
_rotate_right ( w );
w = x->parent->right;
}
w->color = x->parent->color;
x->parent->color = SrTreeNode::Black;
w->right->color = SrTreeNode::Black;
_rotate_left ( x->parent );
x = _root;
}
}
else
{ SrTreeNode *w = x->parent->left;
if ( RED(w) )
{ w->color = SrTreeNode::Black;
x->parent->color = SrTreeNode::Red;
_rotate_right ( x->parent );
w = x->parent->left;
}
if ( BLACK(w->left) && BLACK(w->right) )
{ w->color = SrTreeNode::Red;
x = x->parent;
}
else
{ if ( BLACK(w->left) )
{ w->right->color = SrTreeNode::Black;
w->color = SrTreeNode::Red;
_rotate_left ( w );
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = SrTreeNode::Black;
w->left->color = SrTreeNode::Black;
_rotate_right ( x->parent );
x = _root;
}
}
}
x->color = SrTreeNode::Black;
}
//----------------------------- constructors ------------------------------
SrTreeBase::SrTreeBase ( SrClassManagerBase* m )
{
_root = _cur = NIL;
_elements = 0;
_man = m;
_man->ref();
}
SrTreeBase::SrTreeBase ( const SrTreeBase& t )
{
_root = _cur = NIL;
_elements = 0;
_man = t._man;
_man->ref();
insert_tree ( t );
}
SrTreeBase::~SrTreeBase ()
{
init ();
_man->unref();
}
void SrTreeBase::init ()
{
_cur = _root;
SrTreeNode *curp;
while ( _cur!=NIL )
{ // 1. descend _cur to a leaf
while ( _cur->left!=NIL || _cur->right!=NIL ) // while cur is not a leaf
_cur = _cur->left!=NIL? _cur->left:_cur->right;
// 2. unlink _cur
curp = _cur->parent;
if ( _cur!=_root )
{ if ( curp->left==_cur ) curp->left=NIL;
else curp->right=NIL;
}
// 3. delete and update _cur
_man->free ( _cur );
_cur = curp;
}
_elements = 0;
_root = _cur = SrTreeNode::null;
}
SrTreeNode *SrTreeBase::get_min ( SrTreeNode *x ) const
{
if ( x==NIL ) return x;
while ( x->left!=NIL ) x=x->left;
return x;
}
SrTreeNode *SrTreeBase::get_max ( SrTreeNode *x ) const
{
if ( x==NIL ) return x;
while ( x->right!=NIL ) x=x->right;
return x;
}
SrTreeNode *SrTreeBase::get_next ( SrTreeNode *x ) const
{
if ( x->right!=NIL ) return get_min ( x->right );
SrTreeNode *y = x->parent;
while ( y!=NIL && x==y->right )
{ x = y;
y = y->parent;
}
return y;
}
SrTreeNode *SrTreeBase::get_prior ( SrTreeNode *x ) const
{
if ( x->left!=NIL ) return get_max ( x->left );
SrTreeNode *y = x->parent;
while ( y!=NIL && x==y->left )
{ x = y;
y = y->parent;
}
return y;
}
SrTreeNode *SrTreeBase::search ( const SrTreeNode *key )
{
if ( _root==NIL ) return 0;
return _search_node(key)==0? _cur:0;
}
SrTreeNode *SrTreeBase::insert ( SrTreeNode *key )
{
int cmp = _search_node ( key );
if ( _cur!=NIL )
{ if ( cmp>0 ) // key>_cur
{ // if (_cur->right) REPORT_ERROR;
_cur->right = key;
key->parent = _cur;
_rebalance ( key );
_root->color = SrTreeNode::Black;
_elements++;
return key;
}
else if ( cmp<0 ) // key<_cur
{ // if (_cur->left) REPORT_ERROR
_cur->left = key;
key->parent = _cur;
_rebalance ( key );
_root->color = SrTreeNode::Black;
_elements++;
return key;
}
else return 0; // not inserted, already in the tree
}
else // tree empty
{ _root = key;
_root->init ();
_root->color = SrTreeNode::Black;
_elements++;
return key;
}
}
SrTreeNode *SrTreeBase::insert_or_del ( SrTreeNode *key )
{
if ( !insert(key) )
{ _man->free ( key );
return 0;
}
return key;
}
void SrTreeBase::insert_tree ( const SrTreeBase& t )
{
if ( this==&t ) return;
SrTreeIteratorBase it(t);
for ( it.first(); it.inrange(); it.next() )
{ insert_or_del ( (SrTreeNode*)_man->alloc(it.get()) );
}
}
SrTreeNode *SrTreeBase::extract ( SrTreeNode *z )
{
SrTreeNode *x, *y;
y = ( z->left==NIL || z->right==NIL )? z : get_next(z);
x = ( y->left!=NIL )? y->left : y->right;
x->parent = y->parent;
if ( y->parent!=NIL )
{ if ( y==y->parent->left ) y->parent->left=x;
else y->parent->right=x;
}
else _root = x;
SrTreeNode::Color ycolor = y->color;
if ( y!=z ) // make y be z
{ y->left=z->left; y->right=z->right; y->parent=z->parent; y->color=z->color;
if ( z->left ) z->left->parent=y;
if ( z->right ) z->right->parent=y;
if ( z->parent )
{ if ( z->parent->left==z ) z->parent->left=y;
else z->parent->right=y;
}
if ( _root==z ) _root=y;
}
if ( ycolor==SrTreeNode::Black ) _fix_remove ( x );
_elements--;
_cur = z;
z->init();
return z;
}
void SrTreeBase::remove ( SrTreeNode* z )
{
extract ( z );
_man->free ( z );
}
SrTreeNode* SrTreeBase::search_and_extract ( const SrTreeNode* key )
{
int cmp = _search_node ( key );
if ( cmp!=0 ) return 0; // not found
return extract ( _cur );
}
bool SrTreeBase::search_and_remove ( const SrTreeNode* key )
{
int cmp = _search_node ( key );
if ( cmp==0 ) { remove ( _cur ); return true; }
return false;
}
void SrTreeBase::take_data ( SrTreeBase& t )
{
_root = t._root; t._root = 0;
_cur = t._cur; t._cur = 0;
_elements = t._elements; t._elements = 0;
}
void SrTreeBase::operator= ( const SrTreeBase& t )
{
init ();
insert_tree ( t ); // need to write a copy routine instead of inserting all nodes...
}
SrOutput& operator<< ( SrOutput& o, const SrTreeBase& t )
{
o<<'[';
SrTreeIteratorBase it(t);
for ( it.first(); it.inrange(); it.next() )
{ t._man->output ( o, it.cur() );
if ( !it.inlast() ) o << ' ';
}
return o<<']';
}
//=========================== SrTreeIteratorBase ================================
SrTreeIteratorBase::SrTreeIteratorBase ( const SrTreeBase& t ) : _tree(t)
{
reset ();
}
void SrTreeIteratorBase::reset ()
{
_first = _cur = _tree.first();
_last = _tree.last();
}
//============================ End of File =================================