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

@@ -3797,6 +3797,8 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std
* Fixed bugs:
* [@https://svn.boost.org/trac/boost/ticket/9332 #9332: ['"has_member_function_callable_with.hpp compile error on msvc-12.0"]].
* Optimized tree rebalancing code to avoid redundant assignments.
[endsect]
[section:release_notes_boost_1_55_00 Boost 1.55 Release]

View File

@@ -49,15 +49,6 @@ struct avltree_node_cloner
}
};
template<class NodeTraits>
struct avltree_erase_fixup
{
typedef typename NodeTraits::node_ptr node_ptr;
void operator()(const node_ptr & to_erase, const node_ptr & successor)
{ NodeTraits::set_balance(successor, NodeTraits::get_balance(to_erase)); }
};
/// @endcond
//! avltree_algorithms is configured with a NodeTraits class, which encapsulates the
@@ -225,7 +216,10 @@ class avltree_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, avltree_erase_fixup<NodeTraits>(), info);
bstree_algo::erase(header, z, info);
if(info.y != z){
NodeTraits::set_balance(info.y, NodeTraits::get_balance(z));
}
//Rebalance avltree
rebalance_after_erasure(header, info.x, info.x_parent);
return z;
@@ -358,41 +352,92 @@ class avltree_algorithms
/// @cond
static bool verify(const node_ptr &header)
{
std::size_t height;
std::size_t count;
return verify_recursion(NodeTraits::get_parent(header), count, height);
}
private:
static void rebalance_after_erasure(const node_ptr & header, const node_ptr & xnode, const node_ptr & xnode_parent)
static bool verify_recursion(node_ptr n, std::size_t &count, std::size_t &height)
{
if (!n){
count = 0;
height = 0;
return true;
}
std::size_t leftcount, rightcount;
std::size_t leftheight, rightheight;
if(!verify_recursion(NodeTraits::get_left (n), leftcount, leftheight) ||
!verify_recursion(NodeTraits::get_right(n), rightcount, rightheight) ){
return false;
}
count = 1u + leftcount + rightcount;
height = 1u + (leftheight > rightheight ? leftheight : rightheight);
//If equal height, balance must be zero
if(rightheight == leftheight){
if(NodeTraits::get_balance(n) != NodeTraits::zero()){
BOOST_ASSERT(0);
return false;
}
}
//If right is taller than left, then the difference must be at least 1 and the balance positive
else if(rightheight > leftheight){
if(rightheight - leftheight > 1 ){
BOOST_ASSERT(0);
return false;
}
else if(NodeTraits::get_balance(n) != NodeTraits::positive()){
BOOST_ASSERT(0);
return false;
}
}
//If left is taller than right, then the difference must be at least 1 and the balance negative
else{
if(leftheight - rightheight > 1 ){
BOOST_ASSERT(0);
return false;
}
else if(NodeTraits::get_balance(n) != NodeTraits::negative()){
BOOST_ASSERT(0);
return false;
}
}
return true;
}
static void rebalance_after_erasure(const node_ptr & header, node_ptr x, node_ptr x_parent)
{
node_ptr x(xnode), x_parent(xnode_parent);
for (node_ptr root = NodeTraits::get_parent(header); x != root; root = NodeTraits::get_parent(header)) {
const balance x_parent_balance = NodeTraits::get_balance(x_parent);
node_ptr const x_parent_left(NodeTraits::get_left(x_parent));
//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));
const node_ptr x_parent_right(NodeTraits::get_right(x_parent));
if(x_parent_balance == NodeTraits::zero()){
NodeTraits::set_balance( x_parent
, x == x_parent_left ? NodeTraits::positive() : NodeTraits::negative() );
NodeTraits::set_balance( x_parent, x == x_parent_right ? NodeTraits::negative() : NodeTraits::positive() );
break; // the height didn't change, let's stop here
}
else if(x_parent_balance == NodeTraits::negative()){
if (x == x_parent_left) {
if (x == x_parent_left) { ////x is left child or x and sibling are null
NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
x = x_parent;
x_parent = NodeTraits::get_parent(x_parent);
}
else {
// x is right child
// a is left child
node_ptr a = x_parent_left;
BOOST_INTRUSIVE_INVARIANT_ASSERT(a);
if (NodeTraits::get_balance(a) == NodeTraits::positive()) {
// a MUST have a right child
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(a));
rotate_left_right(x_parent, header);
x = NodeTraits::get_parent(x_parent);
x_parent = NodeTraits::get_parent(x);
// x is right child (x_parent_left is the left child)
BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_left);
if (NodeTraits::get_balance(x_parent_left) == NodeTraits::positive()) {
// x_parent_left MUST have a right child
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(x_parent_left));
x = avl_rotate_left_right(x_parent, x_parent_left, header);
}
else {
rotate_right(x_parent, header);
x = NodeTraits::get_parent(x_parent);
x_parent = NodeTraits::get_parent(x);
avl_rotate_right(x_parent, x_parent_left, header);
x = x_parent_left;
}
// if changed from negative to NodeTraits::positive(), no need to check above
@@ -402,28 +447,22 @@ class avltree_algorithms
}
}
else if(x_parent_balance == NodeTraits::positive()){
if (x == NodeTraits::get_right(x_parent)) {
if (x == x_parent_right) { //x is right child or x and sibling are null
NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
x = x_parent;
x_parent = NodeTraits::get_parent(x_parent);
}
else {
// x is left child
// a is right child
node_ptr a = NodeTraits::get_right(x_parent);
BOOST_INTRUSIVE_INVARIANT_ASSERT(a);
if (NodeTraits::get_balance(a) == NodeTraits::negative()) {
// a MUST have then a left child
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(a));
rotate_right_left(x_parent, header);
x = NodeTraits::get_parent(x_parent);
x_parent = NodeTraits::get_parent(x);
// x is left child (x_parent_right is the right child)
const node_ptr x_parent_right(NodeTraits::get_right(x_parent));
BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_right);
if (NodeTraits::get_balance(x_parent_right) == NodeTraits::negative()) {
// x_parent_right MUST have then a left child
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(x_parent_right));
x = avl_rotate_right_left(x_parent, x_parent_right, header);
}
else {
rotate_left(x_parent, header);
x = NodeTraits::get_parent(x_parent);
x_parent = NodeTraits::get_parent(x);
avl_rotate_left(x_parent, x_parent_right, header);
x = x_parent_right;
}
// if changed from NodeTraits::positive() to negative, no need to check above
if (NodeTraits::get_balance(x) == NodeTraits::negative()){
@@ -434,44 +473,44 @@ class avltree_algorithms
else{
BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
}
x_parent = NodeTraits::get_parent(x);
}
}
static void rebalance_after_insertion(const node_ptr & header, const node_ptr & xnode)
static void rebalance_after_insertion(const node_ptr & header, node_ptr x)
{
node_ptr x(xnode);
NodeTraits::set_balance(x, NodeTraits::zero());
// Rebalance.
for(node_ptr root = NodeTraits::get_parent(header); x != root; root = NodeTraits::get_parent(header)){
node_ptr const x_parent(NodeTraits::get_parent(x));
node_ptr const x_parent_left(NodeTraits::get_left(x_parent));
const balance x_parent_balance = NodeTraits::get_balance(x_parent);
const bool x_is_leftchild(x == x_parent_left);
if(x_parent_balance == NodeTraits::zero()){
// if x is left, parent will have parent->bal_factor = negative
// else, parent->bal_factor = NodeTraits::positive()
NodeTraits::set_balance( x_parent, x == x_parent_left
? NodeTraits::negative() : NodeTraits::positive() );
NodeTraits::set_balance( x_parent, x_is_leftchild ? NodeTraits::negative() : NodeTraits::positive() );
x = x_parent;
}
else if(x_parent_balance == NodeTraits::positive()){
// if x is a left child, parent->bal_factor = zero
if (x == x_parent_left)
if (x_is_leftchild)
NodeTraits::set_balance(x_parent, NodeTraits::zero());
else{ // x is a right child, needs rebalancing
if (NodeTraits::get_balance(x) == NodeTraits::negative())
rotate_right_left(x_parent, header);
avl_rotate_right_left(x_parent, x, header);
else
rotate_left(x_parent, header);
avl_rotate_left(x_parent, x, header);
}
break;
}
else if(x_parent_balance == NodeTraits::negative()){
// if x is a left child, needs rebalancing
if (x == x_parent_left) {
if (x_is_leftchild) {
if (NodeTraits::get_balance(x) == NodeTraits::positive())
rotate_left_right(x_parent, header);
avl_rotate_left_right(x_parent, x, header);
else
rotate_right(x_parent, header);
avl_rotate_right(x_parent, x, header);
}
else
NodeTraits::set_balance(x_parent, NodeTraits::zero());
@@ -508,8 +547,8 @@ class avltree_algorithms
}
}
static void rotate_left_right(const node_ptr a, const node_ptr & hdr)
{
static node_ptr avl_rotate_left_right(const node_ptr a, const node_ptr a_oldleft, const node_ptr & hdr)
{ // [note: 'a_oldleft' is 'b']
// | | //
// a(-2) c //
// / \ / \ //
@@ -517,16 +556,19 @@ class avltree_algorithms
// (pos)b [g] b a //
// / \ / \ / \ //
// [d] c [d] e f [g] //
// / \ //
// e f //
node_ptr b = NodeTraits::get_left(a), c = NodeTraits::get_right(b);
bstree_algo::rotate_left(b, hdr);
bstree_algo::rotate_right(a, hdr);
left_right_balancing(a, b, c);
// / \ //
// e f //
const node_ptr c = NodeTraits::get_right(a_oldleft);
bstree_algo::rotate_left_no_parent_fix(a_oldleft, c);
//No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_left(a, c)]
//as c is not root and another rotation is coming
bstree_algo::rotate_right(a, c, NodeTraits::get_parent(a), hdr);
left_right_balancing(a, a_oldleft, c);
return c;
}
static void rotate_right_left(const node_ptr a, const node_ptr & hdr)
{
static node_ptr avl_rotate_right_left(const node_ptr a, const node_ptr a_oldright, const node_ptr & hdr)
{ // [note: 'a_oldright' is 'b']
// | | //
// a(pos) c //
// / \ / \ //
@@ -536,41 +578,42 @@ class avltree_algorithms
// c [g] [d] e f [g] //
// / \ //
// e f //
node_ptr b = NodeTraits::get_right(a), c = NodeTraits::get_left(b);
bstree_algo::rotate_right(b, hdr);
bstree_algo::rotate_left(a, hdr);
left_right_balancing(b, a, c);
const node_ptr c (NodeTraits::get_left(a_oldright));
bstree_algo::rotate_right_no_parent_fix(a_oldright, c);
//No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_right(a, c)]
//as c is not root and another rotation is coming.
bstree_algo::rotate_left(a, c, NodeTraits::get_parent(a), hdr);
left_right_balancing(a_oldright, a, c);
return c;
}
static void rotate_left(const node_ptr x, const node_ptr & hdr)
static void avl_rotate_left(const node_ptr &x, const node_ptr &x_oldright, const node_ptr & hdr)
{
const node_ptr y = NodeTraits::get_right(x);
bstree_algo::rotate_left(x, hdr);
bstree_algo::rotate_left(x, x_oldright, NodeTraits::get_parent(x), hdr);
// reset the balancing factor
if (NodeTraits::get_balance(y) == NodeTraits::positive()) {
if (NodeTraits::get_balance(x_oldright) == NodeTraits::positive()) {
NodeTraits::set_balance(x, NodeTraits::zero());
NodeTraits::set_balance(y, NodeTraits::zero());
NodeTraits::set_balance(x_oldright, NodeTraits::zero());
}
else { // this doesn't happen during insertions
NodeTraits::set_balance(x, NodeTraits::positive());
NodeTraits::set_balance(y, NodeTraits::negative());
NodeTraits::set_balance(x_oldright, NodeTraits::negative());
}
}
static void rotate_right(const node_ptr x, const node_ptr & hdr)
static void avl_rotate_right(const node_ptr &x, const node_ptr &x_oldleft, const node_ptr & hdr)
{
const node_ptr y = NodeTraits::get_left(x);
bstree_algo::rotate_right(x, hdr);
bstree_algo::rotate_right(x, x_oldleft, NodeTraits::get_parent(x), hdr);
// reset the balancing factor
if (NodeTraits::get_balance(y) == NodeTraits::negative()) {
if (NodeTraits::get_balance(x_oldleft) == NodeTraits::negative()) {
NodeTraits::set_balance(x, NodeTraits::zero());
NodeTraits::set_balance(y, NodeTraits::zero());
NodeTraits::set_balance(x_oldleft, NodeTraits::zero());
}
else { // this doesn't happen during insertions
NodeTraits::set_balance(x, NodeTraits::negative());
NodeTraits::set_balance(y, NodeTraits::positive());
NodeTraits::set_balance(x_oldleft, NodeTraits::positive());
}
}

View File

@@ -549,7 +549,7 @@ class bstree_algorithms
//! <b>Complexity</b>: Logarithmic to the size of the subtree.
//!
//! <b>Throws</b>: Nothing.
static node_ptr minimum (node_ptr node)
static node_ptr minimum(node_ptr node)
{
for(node_ptr p_left = NodeTraits::get_left(node)
;p_left
@@ -1062,16 +1062,12 @@ class bstree_algorithms
//Since we've found the upper bound there is no other value with the same key if:
// - There is no previous node
// - The previous node is less than the key
if(!prev || comp(prev, key)){
const bool not_present = !prev || comp(prev, key);
if(not_present){
commit_data.link_left = left_child;
commit_data.node = y;
return std::pair<node_ptr, bool>(node_ptr(), true);
}
//If the previous value was not less than key, it means that it's equal
//(because we've checked the upper bound)
else{
return std::pair<node_ptr, bool>(prev, false);
}
return std::pair<node_ptr, bool>(prev, not_present);
}
//! <b>Requires</b>: "header" must be the header node of a tree.
@@ -1362,7 +1358,7 @@ class bstree_algorithms
static void erase(const node_ptr & header, const node_ptr & z)
{
data_for_rebalance ignored;
erase_impl(header, z, ignored);
erase(header, z, ignored);
}
//! <b>Requires</b>: node is a tree node but not the header.
@@ -1447,6 +1443,88 @@ class bstree_algorithms
}
protected:
static void erase(const node_ptr & header, const node_ptr & z, data_for_rebalance &info)
{
node_ptr y(z);
node_ptr x;
const node_ptr z_left(NodeTraits::get_left(z));
const node_ptr z_right(NodeTraits::get_right(z));
if(!z_left){
x = z_right; // x might be null.
}
else if(!z_right){ // z has exactly one non-null child. y == z.
x = z_left; // x is not null.
BOOST_ASSERT(x);
}
else{ //make y != z
// y = find z's successor
y = bstree_algorithms::minimum(z_right);
x = NodeTraits::get_right(y); // x might be null.
}
node_ptr x_parent;
const node_ptr z_parent(NodeTraits::get_parent(z));
const bool z_is_leftchild(NodeTraits::get_left(z_parent) == z);
if(y != z){ //has two children and y is the minimum of z
//y is z's successor and it has a null left child.
//x is the right child of y (it can be null)
//Relink y in place of z and link x with y's old parent
NodeTraits::set_parent(z_left, y);
NodeTraits::set_left(y, z_left);
if(y != z_right){
//Link y with the right tree of z
NodeTraits::set_right(y, z_right);
NodeTraits::set_parent(z_right, y);
//Link x with y's old parent (y must be a left child)
x_parent = NodeTraits::get_parent(y);
BOOST_ASSERT(NodeTraits::get_left(x_parent) == y);
if(x)
NodeTraits::set_parent(x, x_parent);
//Since y was the successor and not the right child of z, it must be a left child
NodeTraits::set_left(x_parent, x);
}
else{ //y was the right child of y so no need to fix x's position
x_parent = y;
}
NodeTraits::set_parent(y, z_parent);
bstree_algorithms::set_child(header, y, z_parent, z_is_leftchild);
}
else { // z has zero or one child, x is one child (it can be null)
//Just link x to z's parent
x_parent = z_parent;
if(x)
NodeTraits::set_parent(x, z_parent);
bstree_algorithms::set_child(header, x, z_parent, z_is_leftchild);
//Now update leftmost/rightmost in case z was one of them
if(NodeTraits::get_left(header) == z){
//z_left must be null because z is the leftmost
BOOST_ASSERT(!z_left);
NodeTraits::set_left(header, !z_right ?
z_parent : // makes leftmost == header if z == root
bstree_algorithms::minimum(z_right));
}
if(NodeTraits::get_right(header) == z){
//z_right must be null because z is the rightmost
BOOST_ASSERT(!z_right);
NodeTraits::set_right(header, !z_left ?
z_parent : // makes rightmost == header if z == root
bstree_algorithms::maximum(z_left));
}
}
//If z had 0/1 child, y == z and one of its children (and maybe null)
//If z had 2 children, y is the successor of z and x is the right child of y
info.x = x;
info.y = y;
//If z had 0/1 child, x_parent is the new parent of the old right child of y (z's successor)
//If z had 2 children, x_parent is the new parent of y (z_parent)
BOOST_ASSERT(!x || NodeTraits::get_parent(x) == x_parent);
info.x_parent = x_parent;
}
//! <b>Requires</b>: node is a node of the tree but it's not the header.
//!
//! <b>Effects</b>: Returns the number of nodes of the subtree.
@@ -1510,83 +1588,6 @@ class bstree_algorithms
static bool is_right_child(const node_ptr & p)
{ return NodeTraits::get_right(NodeTraits::get_parent(p)) == p; }
template<class F>
static void erase(const node_ptr & header, const node_ptr & z, F z_and_successor_fixup, data_for_rebalance &info)
{
erase_impl(header, z, info);
if(info.y != z){
z_and_successor_fixup(z, info.y);
}
}
//Fix header and own's parent data when replacing x with own, providing own's old data with parent
static void replace_own_impl(const node_ptr & own, const node_ptr & x, const node_ptr & header, const node_ptr & own_parent, bool own_was_left)
{
if(NodeTraits::get_parent(header) == own)
NodeTraits::set_parent(header, x);
else if(own_was_left)
NodeTraits::set_left(own_parent, x);
else
NodeTraits::set_right(own_parent, x);
}
//Fix header and own's parent data when replacing x with own, supposing own
//links with its parent are still ok
static void replace_own(const node_ptr & own, const node_ptr & x, const node_ptr & header)
{
node_ptr own_parent(NodeTraits::get_parent(own));
bool own_is_left(NodeTraits::get_left(own_parent) == own);
replace_own_impl(own, x, header, own_parent, own_is_left);
}
// rotate parent p to left (no header and p's parent fixup)
static node_ptr rotate_left(const node_ptr & p)
{
node_ptr x(NodeTraits::get_right(p));
node_ptr x_left(NodeTraits::get_left(x));
NodeTraits::set_right(p, x_left);
if(x_left){
NodeTraits::set_parent(x_left, p);
}
NodeTraits::set_left(x, p);
NodeTraits::set_parent(p, x);
return x;
}
// rotate parent p to left (with header and p's parent fixup)
static void rotate_left(const node_ptr & p, const node_ptr & header)
{
bool p_was_left(is_left_child(p));
node_ptr p_old_parent(NodeTraits::get_parent(p));
node_ptr x(rotate_left(p));
NodeTraits::set_parent(x, p_old_parent);
replace_own_impl(p, x, header, p_old_parent, p_was_left);
}
// rotate parent p to right (no header and p's parent fixup)
static node_ptr rotate_right(const node_ptr & p)
{
node_ptr x(NodeTraits::get_left(p));
node_ptr x_right(NodeTraits::get_right(x));
NodeTraits::set_left(p, x_right);
if(x_right){
NodeTraits::set_parent(x_right, p);
}
NodeTraits::set_right(x, p);
NodeTraits::set_parent(p, x);
return x;
}
// rotate parent p to right (with header and p's parent fixup)
static void rotate_right(const node_ptr & p, const node_ptr & header)
{
bool p_was_left(is_left_child(p));
node_ptr p_old_parent(NodeTraits::get_parent(p));
node_ptr x(rotate_right(p));
NodeTraits::set_parent(x, p_old_parent);
replace_own_impl(p, x, header, p_old_parent, p_was_left);
}
static void insert_before_check
(const node_ptr &header, const node_ptr & pos
, insert_commit_data &commit_data
@@ -1668,12 +1669,40 @@ class bstree_algorithms
template<class NodePtrCompare>
static void insert_equal_upper_bound_check
(const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0)
{ insert_equal_check_impl(true, h, new_node, comp, commit_data, pdepth); }
{
std::size_t depth = 0;
node_ptr y(h);
node_ptr x(NodeTraits::get_parent(y));
while(x){
++depth;
y = x;
x = comp(new_node, x) ?
NodeTraits::get_left(x) : NodeTraits::get_right(x);
}
if(pdepth) *pdepth = depth;
commit_data.link_left = (y == h) || comp(new_node, y);
commit_data.node = y;
}
template<class NodePtrCompare>
static void insert_equal_lower_bound_check
(const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0)
{ insert_equal_check_impl(false, h, new_node, comp, commit_data, pdepth); }
{
std::size_t depth = 0;
node_ptr y(h);
node_ptr x(NodeTraits::get_parent(y));
while(x){
++depth;
y = x;
x = !comp(x, new_node) ?
NodeTraits::get_left(x) : NodeTraits::get_right(x);
}
if(pdepth) *pdepth = depth;
commit_data.link_left = (y == h) || !comp(y, new_node);
commit_data.node = y;
}
static void insert_commit
(const node_ptr & header, const node_ptr & new_node, const insert_commit_data &commit_data)
@@ -1701,7 +1730,61 @@ class bstree_algorithms
NodeTraits::set_left(new_node, node_ptr());
}
//Fix header and own's parent data when replacing x with own, providing own's old data with parent
static void set_child(const node_ptr & header, const node_ptr & new_child, const node_ptr & new_parent, const bool link_left)
{
if(new_parent == header)
NodeTraits::set_parent(header, new_child);
else if(link_left)
NodeTraits::set_left(new_parent, new_child);
else
NodeTraits::set_right(new_parent, new_child);
}
// rotate p to left (no header and p's parent fixup)
static void rotate_left_no_parent_fix(const node_ptr & p, const node_ptr &p_right)
{
node_ptr p_right_left(NodeTraits::get_left(p_right));
NodeTraits::set_right(p, p_right_left);
if(p_right_left){
NodeTraits::set_parent(p_right_left, p);
}
NodeTraits::set_left(p_right, p);
NodeTraits::set_parent(p, p_right);
}
// rotate p to left (with header and p's parent fixup)
static void rotate_left(const node_ptr & p, const node_ptr & p_right, const node_ptr & p_parent, const node_ptr & header)
{
const bool p_was_left(NodeTraits::get_left(p_parent) == p);
rotate_left_no_parent_fix(p, p_right);
NodeTraits::set_parent(p_right, p_parent);
set_child(header, p_right, p_parent, p_was_left);
}
// rotate p to right (no header and p's parent fixup)
static void rotate_right_no_parent_fix(const node_ptr & p, const node_ptr &p_left)
{
node_ptr p_left_right(NodeTraits::get_right(p_left));
NodeTraits::set_left(p, p_left_right);
if(p_left_right){
NodeTraits::set_parent(p_left_right, p);
}
NodeTraits::set_right(p_left, p);
NodeTraits::set_parent(p, p_left);
}
// rotate p to right (with header and p's parent fixup)
static void rotate_right(const node_ptr & p, const node_ptr & p_left, const node_ptr & p_parent, const node_ptr & header)
{
const bool p_was_left(NodeTraits::get_left(p_parent) == p);
rotate_right_no_parent_fix(p, p_left);
NodeTraits::set_parent(p_left, p_parent);
set_child(header, p_left, p_parent, p_was_left);
}
private:
static void subtree_to_vine(node_ptr vine_tail, std::size_t &size)
{
//Inspired by LibAVL:
@@ -1913,98 +1996,6 @@ class bstree_algorithms
}
return y;
}
template<class NodePtrCompare>
static void insert_equal_check_impl
(bool upper, const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0)
{
std::size_t depth = 0;
node_ptr y(h);
node_ptr x(NodeTraits::get_parent(y));
bool link_left;
if(upper){
while(x){
++depth;
y = x;
x = comp(new_node, x) ?
NodeTraits::get_left(x) : NodeTraits::get_right(x);
}
link_left = (y == h) || comp(new_node, y);
}
else{
while(x){
++depth;
y = x;
x = !comp(x, new_node) ?
NodeTraits::get_left(x) : NodeTraits::get_right(x);
}
link_left = (y == h) || !comp(y, new_node);
}
commit_data.link_left = link_left;
commit_data.node = y;
if(pdepth) *pdepth = depth;
}
static void erase_impl(const node_ptr & header, const node_ptr & z, data_for_rebalance &info)
{
node_ptr y(z);
node_ptr x;
node_ptr x_parent = node_ptr();
node_ptr z_left(NodeTraits::get_left(z));
node_ptr z_right(NodeTraits::get_right(z));
if(!z_left){
x = z_right; // x might be null.
}
else if(!z_right){ // z has exactly one non-null child. y == z.
x = z_left; // x is not null.
}
else{
// find z's successor
y = bstree_algorithms::minimum (z_right);
x = NodeTraits::get_right(y); // x might be null.
}
if(y != z){
// relink y in place of z. y is z's successor
NodeTraits::set_parent(NodeTraits::get_left(z), y);
NodeTraits::set_left(y, NodeTraits::get_left(z));
if(y != NodeTraits::get_right(z)){
x_parent = NodeTraits::get_parent(y);
if(x)
NodeTraits::set_parent(x, x_parent);
NodeTraits::set_left(x_parent, x); // y must be a child of left_
NodeTraits::set_right(y, NodeTraits::get_right(z));
NodeTraits::set_parent(NodeTraits::get_right(z), y);
}
else
x_parent = y;
bstree_algorithms::replace_own (z, y, header);
NodeTraits::set_parent(y, NodeTraits::get_parent(z));
}
else { // y == z --> z has only one child, or void
x_parent = NodeTraits::get_parent(z);
if(x)
NodeTraits::set_parent(x, x_parent);
bstree_algorithms::replace_own (z, x, header);
if(NodeTraits::get_left(header) == z){
NodeTraits::set_left(header, !NodeTraits::get_right(z) ? // z->get_left() must be null also
NodeTraits::get_parent(z) : // makes leftmost == header if z == root
bstree_algorithms::minimum (x));
}
if(NodeTraits::get_right(header) == z){
NodeTraits::set_right(header, !NodeTraits::get_left(z) ? // z->get_right() must be null also
NodeTraits::get_parent(z) : // makes rightmost == header if z == root
bstree_algorithms::maximum(x));
}
}
info.x = x;
info.x_parent = x_parent;
info.y = y;
}
};
/// @cond

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());

View File

@@ -576,8 +576,8 @@ class splaytree_algorithms
if(!t_left)
break;
if(comp(key, t_left)){
commit.t_ = bstree_algo::rotate_right(commit.t_);
bstree_algo::rotate_right_no_parent_fix(commit.t_, t_left);
commit.t_ = t_left;
if( !NodeTraits::get_left(commit.t_) )
break;
link_right(commit.t_, commit.r_);
@@ -597,8 +597,8 @@ class splaytree_algorithms
break;
if(comp(t_right, key)){
commit.t_ = bstree_algo::rotate_left( commit.t_ );
bstree_algo::rotate_left_no_parent_fix(commit.t_, t_right);
commit.t_ = t_right;
if( !NodeTraits::get_right(commit.t_) )
break;
link_left(commit.t_, commit.l_);

View File

@@ -110,16 +110,17 @@ class treap_algorithms
static void rotate_up_n(const node_ptr header, const node_ptr p, std::size_t n)
{
for( node_ptr p_parent = NodeTraits::get_parent(p)
; n--
; p_parent = NodeTraits::get_parent(p)){
//Check if left child
if(p == NodeTraits::get_left(p_parent)){
bstree_algo::rotate_right(p_parent, header);
node_ptr p_parent(NodeTraits::get_parent(p));
node_ptr p_grandparent(NodeTraits::get_parent(p_parent));
while(n--){
if(p == NodeTraits::get_left(p_parent)){ //p is left child
bstree_algo::rotate_right(p_parent, p, p_grandparent, header);
}
else{ //Right child
bstree_algo::rotate_left(p_parent, header);
else{ //p is right child
bstree_algo::rotate_left(p_parent, p, p_grandparent, header);
}
p_parent = p_grandparent;
p_grandparent = NodeTraits::get_parent(p_parent);
}
}
@@ -526,7 +527,7 @@ class treap_algorithms
(const node_ptr & header, const node_ptr & new_node, const insert_commit_data &commit_data)
{
bstree_algo::insert_unique_commit(header, new_node, commit_data);
rebalance_after_insertion_commit(header, new_node, commit_data.rotations);
rotate_up_n(header, new_node, commit_data.rotations);
}
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
@@ -547,11 +548,12 @@ class treap_algorithms
node_ptr z_left = NodeTraits::get_left(z);
node_ptr z_right = NodeTraits::get_right(z);
while(z_left || z_right){
const node_ptr z_parent(NodeTraits::get_parent(z));
if(!z_right || (z_left && pcomp(z_left, z_right))){
bstree_algo::rotate_right(z, header);
bstree_algo::rotate_right(z, z_left, z_parent, header);
}
else{
bstree_algo::rotate_left(z, header);
bstree_algo::rotate_left(z, z_right, z_parent, header);
}
++n;
z_left = NodeTraits::get_left(z);
@@ -567,10 +569,9 @@ class treap_algorithms
rebalance_after_insertion_check(h, commit_data.node, new_node, pcomp, commit_data.rotations);
//No-throw
bstree_algo::insert_unique_commit(h, new_node, commit_data);
rebalance_after_insertion_commit(h, new_node, commit_data.rotations);
rotate_up_n(h, new_node, commit_data.rotations);
}
template<class Key, class KeyNodePriorityCompare>
static void rebalance_after_insertion_check
(const const_node_ptr &header, const const_node_ptr & up, const Key &k
@@ -587,22 +588,6 @@ class treap_algorithms
num_rotations = n;
}
static void rebalance_after_insertion_commit(const node_ptr & header, const node_ptr & p, std::size_t n)
{
// Now execute n rotations
for( node_ptr p_parent = NodeTraits::get_parent(p)
; n--
; p_parent = NodeTraits::get_parent(p)){
//Check if left child
if(p == NodeTraits::get_left(p_parent)){
bstree_algo::rotate_right(p_parent, header);
}
else{ //Right child
bstree_algo::rotate_left(p_parent, header);
}
}
}
template<class NodePtrPriorityCompare>
static bool check_invariant(const const_node_ptr & header, NodePtrPriorityCompare pcomp)
{