Optimized tree-rebalancing code to avoid redundant pointer updates.

This commit is contained in:
Ion Gaztañaga
2014-02-06 11:10:47 +01:00
parent 2ffe6b2f82
commit c1fdae5eb4
6 changed files with 389 additions and 366 deletions

View File

@@ -57,21 +57,6 @@ struct rbtree_node_cloner
}
};
template<class NodeTraits>
struct rbtree_erase_fixup
{
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::color color;
void operator()(const node_ptr & to_erase, const node_ptr & successor)
{
//Swap color of y and z
color tmp(NodeTraits::get_color(successor));
NodeTraits::set_color(successor, NodeTraits::get_color(to_erase));
NodeTraits::set_color(to_erase, tmp);
}
};
#endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! rbtree_algorithms provides basic algorithms to manipulate
@@ -245,10 +230,18 @@ class rbtree_algorithms
static node_ptr erase(const node_ptr & header, const node_ptr & z)
{
typename bstree_algo::data_for_rebalance info;
bstree_algo::erase(header, z, rbtree_erase_fixup<NodeTraits>(), info);
bstree_algo::erase(header, z, info);
//Rebalance rbtree
if(NodeTraits::get_color(z) != NodeTraits::red()){
color new_z_color;
if(info.y != z){
new_z_color = NodeTraits::get_color(info.y);
NodeTraits::set_color(info.y, NodeTraits::get_color(z));
}
else{
new_z_color = NodeTraits::get_color(z);
}
//Rebalance rbtree if needed
if(new_z_color != NodeTraits::red()){
rebalance_after_erasure(header, info.x, info.x_parent);
}
return z;
@@ -387,14 +380,20 @@ class rbtree_algorithms
static void rebalance_after_erasure(const node_ptr & header, node_ptr x, node_ptr x_parent)
{
while(x != NodeTraits::get_parent(header) && (!x || NodeTraits::get_color(x) == NodeTraits::black())){
if(x == NodeTraits::get_left(x_parent)){
while(1){
if(x_parent == header || (x && NodeTraits::get_color(x) != NodeTraits::black())){
break;
}
//Don't cache x_is_leftchild or similar because x can be null and
//equal to both x_parent_left and x_parent_right
const node_ptr x_parent_left(NodeTraits::get_left(x_parent));
if(x == x_parent_left){ //x is left child
node_ptr w = NodeTraits::get_right(x_parent);
BOOST_ASSERT(w);
if(NodeTraits::get_color(w) == NodeTraits::red()){
NodeTraits::set_color(w, NodeTraits::black());
NodeTraits::set_color(x_parent, NodeTraits::red());
bstree_algo::rotate_left(x_parent, header);
bstree_algo::rotate_left(x_parent, w, NodeTraits::get_parent(x_parent), header);
w = NodeTraits::get_right(x_parent);
}
node_ptr const w_left (NodeTraits::get_left(w));
@@ -407,26 +406,27 @@ class rbtree_algorithms
}
else {
if(!w_right || NodeTraits::get_color(w_right) == NodeTraits::black()){
NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black());
NodeTraits::set_color(w_left, NodeTraits::black());
NodeTraits::set_color(w, NodeTraits::red());
bstree_algo::rotate_right(w, header);
bstree_algo::rotate_right(w, w_left, NodeTraits::get_parent(w), header);
w = NodeTraits::get_right(x_parent);
}
NodeTraits::set_color(w, NodeTraits::get_color(x_parent));
NodeTraits::set_color(x_parent, NodeTraits::black());
if(NodeTraits::get_right(w))
NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black());
bstree_algo::rotate_left(x_parent, header);
const node_ptr new_wright(NodeTraits::get_right(w));
if(new_wright)
NodeTraits::set_color(new_wright, NodeTraits::black());
bstree_algo::rotate_left(x_parent, NodeTraits::get_right(x_parent), NodeTraits::get_parent(x_parent), header);
break;
}
}
else {
// same as above, with right_ <-> left_.
node_ptr w = NodeTraits::get_left(x_parent);
node_ptr w = x_parent_left;
if(NodeTraits::get_color(w) == NodeTraits::red()){
NodeTraits::set_color(w, NodeTraits::black());
NodeTraits::set_color(x_parent, NodeTraits::red());
bstree_algo::rotate_right(x_parent, header);
bstree_algo::rotate_right(x_parent, w, NodeTraits::get_parent(x_parent), header);
w = NodeTraits::get_left(x_parent);
}
node_ptr const w_left (NodeTraits::get_left(w));
@@ -439,16 +439,17 @@ class rbtree_algorithms
}
else {
if(!w_left || NodeTraits::get_color(w_left) == NodeTraits::black()){
NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black());
NodeTraits::set_color(w_right, NodeTraits::black());
NodeTraits::set_color(w, NodeTraits::red());
bstree_algo::rotate_left(w, header);
bstree_algo::rotate_left(w, w_right, NodeTraits::get_parent(w), header);
w = NodeTraits::get_left(x_parent);
}
NodeTraits::set_color(w, NodeTraits::get_color(x_parent));
NodeTraits::set_color(x_parent, NodeTraits::black());
if(NodeTraits::get_left(w))
NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black());
bstree_algo::rotate_right(x_parent, header);
const node_ptr new_wleft(NodeTraits::get_left(w));
if(new_wleft)
NodeTraits::set_color(new_wleft, NodeTraits::black());
bstree_algo::rotate_right(x_parent, NodeTraits::get_left(x_parent), NodeTraits::get_parent(x_parent), header);
break;
}
}
@@ -460,48 +461,49 @@ class rbtree_algorithms
static void rebalance_after_insertion(const node_ptr & header, node_ptr p)
{
NodeTraits::set_color(p, NodeTraits::red());
while(p != NodeTraits::get_parent(header) && NodeTraits::get_color(NodeTraits::get_parent(p)) == NodeTraits::red()){
while(1){
node_ptr p_parent(NodeTraits::get_parent(p));
node_ptr p_parent_parent(NodeTraits::get_parent(p_parent));
if(bstree_algo::is_left_child(p_parent)){
node_ptr x = NodeTraits::get_right(p_parent_parent);
if(x && NodeTraits::get_color(x) == NodeTraits::red()){
NodeTraits::set_color(p_parent, NodeTraits::black());
NodeTraits::set_color(p_parent_parent, NodeTraits::red());
NodeTraits::set_color(x, NodeTraits::black());
p = p_parent_parent;
}
else {
if(!bstree_algo::is_left_child(p)){
p = p_parent;
bstree_algo::rotate_left(p, header);
}
node_ptr new_p_parent(NodeTraits::get_parent(p));
node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent));
NodeTraits::set_color(new_p_parent, NodeTraits::black());
NodeTraits::set_color(new_p_parent_parent, NodeTraits::red());
bstree_algo::rotate_right(new_p_parent_parent, header);
}
const node_ptr p_grandparent(NodeTraits::get_parent(p_parent));
if(p_parent == header || NodeTraits::get_color(p_parent) == NodeTraits::black() || p_grandparent == header){
break;
}
else{
node_ptr x = NodeTraits::get_left(p_parent_parent);
if(x && NodeTraits::get_color(x) == NodeTraits::red()){
NodeTraits::set_color(p_parent, NodeTraits::black());
NodeTraits::set_color(p_parent_parent, NodeTraits::red());
NodeTraits::set_color(x, NodeTraits::black());
p = p_parent_parent;
}
else{
if(bstree_algo::is_left_child(p)){
p = p_parent;
bstree_algo::rotate_right(p, header);
NodeTraits::set_color(p_grandparent, NodeTraits::red());
node_ptr const p_grandparent_left (NodeTraits::get_left (p_grandparent));
bool const p_parent_is_left_child = p_parent == p_grandparent_left;
node_ptr const x(p_parent_is_left_child ? NodeTraits::get_right(p_grandparent) : p_grandparent_left);
if(x && NodeTraits::get_color(x) == NodeTraits::red()){
NodeTraits::set_color(x, NodeTraits::black());
NodeTraits::set_color(p_parent, NodeTraits::black());
p = p_grandparent;
}
else{ //Final step
const bool p_is_left_child(NodeTraits::get_left(p_parent) == p);
if(p_parent_is_left_child){ //p_parent is left child
if(!p_is_left_child){ //p is right child
bstree_algo::rotate_left_no_parent_fix(p_parent, p);
//No need to link p and p_grandparent:
// [NodeTraits::set_parent(p, p_grandparent) + NodeTraits::set_left(p_grandparent, p)]
//as p_grandparent is not the header, another rotation is coming and p_parent
//will be the left child of p_grandparent
p_parent = p;
}
node_ptr new_p_parent(NodeTraits::get_parent(p));
node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent));
NodeTraits::set_color(new_p_parent, NodeTraits::black());
NodeTraits::set_color(new_p_parent_parent, NodeTraits::red());
bstree_algo::rotate_left(new_p_parent_parent, header);
bstree_algo::rotate_right(p_grandparent, p_parent, NodeTraits::get_parent(p_grandparent), header);
}
else{ //p_parent is right child
if(p_is_left_child){ //p is left child
bstree_algo::rotate_right_no_parent_fix(p_parent, p);
//No need to link p and p_grandparent:
// [NodeTraits::set_parent(p, p_grandparent) + NodeTraits::set_right(p_grandparent, p)]
//as p_grandparent is not the header, another rotation is coming and p_parent
//will be the right child of p_grandparent
p_parent = p;
}
bstree_algo::rotate_left(p_grandparent, p_parent, NodeTraits::get_parent(p_grandparent), header);
}
NodeTraits::set_color(p_parent, NodeTraits::black());
break;
}
}
NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black());