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: * Fixed bugs:
* [@https://svn.boost.org/trac/boost/ticket/9332 #9332: ['"has_member_function_callable_with.hpp compile error on msvc-12.0"]]. * [@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] [endsect]
[section:release_notes_boost_1_55_00 Boost 1.55 Release] [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 /// @endcond
//! avltree_algorithms is configured with a NodeTraits class, which encapsulates the //! 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) static node_ptr erase(const node_ptr & header, const node_ptr & z)
{ {
typename bstree_algo::data_for_rebalance info; 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 avltree
rebalance_after_erasure(header, info.x, info.x_parent); rebalance_after_erasure(header, info.x, info.x_parent);
return z; return z;
@@ -358,41 +352,92 @@ class avltree_algorithms
/// @cond /// @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: 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)) { 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); 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()){ if(x_parent_balance == NodeTraits::zero()){
NodeTraits::set_balance( x_parent NodeTraits::set_balance( x_parent, x == x_parent_right ? NodeTraits::negative() : NodeTraits::positive() );
, x == x_parent_left ? NodeTraits::positive() : NodeTraits::negative() );
break; // the height didn't change, let's stop here break; // the height didn't change, let's stop here
} }
else if(x_parent_balance == NodeTraits::negative()){ 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 NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
x = x_parent; x = x_parent;
x_parent = NodeTraits::get_parent(x_parent);
} }
else { else {
// x is right child // x is right child (x_parent_left is the left child)
// a is left child BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_left);
node_ptr a = x_parent_left; if (NodeTraits::get_balance(x_parent_left) == NodeTraits::positive()) {
BOOST_INTRUSIVE_INVARIANT_ASSERT(a); // x_parent_left MUST have a right child
if (NodeTraits::get_balance(a) == NodeTraits::positive()) { BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(x_parent_left));
// a MUST have a right child x = avl_rotate_left_right(x_parent, x_parent_left, header);
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);
} }
else { else {
rotate_right(x_parent, header); avl_rotate_right(x_parent, x_parent_left, header);
x = NodeTraits::get_parent(x_parent); x = x_parent_left;
x_parent = NodeTraits::get_parent(x);
} }
// if changed from negative to NodeTraits::positive(), no need to check above // 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()){ 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 NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
x = x_parent; x = x_parent;
x_parent = NodeTraits::get_parent(x_parent);
} }
else { else {
// x is left child // x is left child (x_parent_right is the right child)
// a is right child const node_ptr x_parent_right(NodeTraits::get_right(x_parent));
node_ptr a = NodeTraits::get_right(x_parent); BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_right);
BOOST_INTRUSIVE_INVARIANT_ASSERT(a); if (NodeTraits::get_balance(x_parent_right) == NodeTraits::negative()) {
if (NodeTraits::get_balance(a) == NodeTraits::negative()) { // x_parent_right MUST have then a left child
// a MUST have then a left child BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(x_parent_right));
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(a)); x = avl_rotate_right_left(x_parent, x_parent_right, header);
rotate_right_left(x_parent, header);
x = NodeTraits::get_parent(x_parent);
x_parent = NodeTraits::get_parent(x);
} }
else { else {
rotate_left(x_parent, header); avl_rotate_left(x_parent, x_parent_right, header);
x = NodeTraits::get_parent(x_parent); x = x_parent_right;
x_parent = NodeTraits::get_parent(x);
} }
// if changed from NodeTraits::positive() to negative, no need to check above // if changed from NodeTraits::positive() to negative, no need to check above
if (NodeTraits::get_balance(x) == NodeTraits::negative()){ if (NodeTraits::get_balance(x) == NodeTraits::negative()){
@@ -434,44 +473,44 @@ class avltree_algorithms
else{ else{
BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached 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()); NodeTraits::set_balance(x, NodeTraits::zero());
// Rebalance. // Rebalance.
for(node_ptr root = NodeTraits::get_parent(header); x != root; root = NodeTraits::get_parent(header)){ 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(NodeTraits::get_parent(x));
node_ptr const x_parent_left(NodeTraits::get_left(x_parent)); node_ptr const x_parent_left(NodeTraits::get_left(x_parent));
const balance x_parent_balance = NodeTraits::get_balance(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_parent_balance == NodeTraits::zero()){
// if x is left, parent will have parent->bal_factor = negative // if x is left, parent will have parent->bal_factor = negative
// else, parent->bal_factor = NodeTraits::positive() // else, parent->bal_factor = NodeTraits::positive()
NodeTraits::set_balance( x_parent, x == x_parent_left NodeTraits::set_balance( x_parent, x_is_leftchild ? NodeTraits::negative() : NodeTraits::positive() );
? NodeTraits::negative() : NodeTraits::positive() );
x = x_parent; x = x_parent;
} }
else if(x_parent_balance == NodeTraits::positive()){ else if(x_parent_balance == NodeTraits::positive()){
// if x is a left child, parent->bal_factor = zero // 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()); NodeTraits::set_balance(x_parent, NodeTraits::zero());
else{ // x is a right child, needs rebalancing else{ // x is a right child, needs rebalancing
if (NodeTraits::get_balance(x) == NodeTraits::negative()) if (NodeTraits::get_balance(x) == NodeTraits::negative())
rotate_right_left(x_parent, header); avl_rotate_right_left(x_parent, x, header);
else else
rotate_left(x_parent, header); avl_rotate_left(x_parent, x, header);
} }
break; break;
} }
else if(x_parent_balance == NodeTraits::negative()){ else if(x_parent_balance == NodeTraits::negative()){
// if x is a left child, needs rebalancing // if x is a left child, needs rebalancing
if (x == x_parent_left) { if (x_is_leftchild) {
if (NodeTraits::get_balance(x) == NodeTraits::positive()) if (NodeTraits::get_balance(x) == NodeTraits::positive())
rotate_left_right(x_parent, header); avl_rotate_left_right(x_parent, x, header);
else else
rotate_right(x_parent, header); avl_rotate_right(x_parent, x, header);
} }
else else
NodeTraits::set_balance(x_parent, NodeTraits::zero()); 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 // // a(-2) c //
// / \ / \ // // / \ / \ //
@@ -519,14 +558,17 @@ class avltree_algorithms
// [d] c [d] e f [g] // // [d] c [d] e f [g] //
// / \ // // / \ //
// e f // // e f //
node_ptr b = NodeTraits::get_left(a), c = NodeTraits::get_right(b); const node_ptr c = NodeTraits::get_right(a_oldleft);
bstree_algo::rotate_left(b, hdr); bstree_algo::rotate_left_no_parent_fix(a_oldleft, c);
bstree_algo::rotate_right(a, hdr); //No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_left(a, c)]
left_right_balancing(a, b, 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 // // a(pos) c //
// / \ / \ // // / \ / \ //
@@ -536,41 +578,42 @@ class avltree_algorithms
// c [g] [d] e f [g] // // c [g] [d] e f [g] //
// / \ // // / \ //
// e f // // e f //
node_ptr b = NodeTraits::get_right(a), c = NodeTraits::get_left(b); const node_ptr c (NodeTraits::get_left(a_oldright));
bstree_algo::rotate_right(b, hdr); bstree_algo::rotate_right_no_parent_fix(a_oldright, c);
bstree_algo::rotate_left(a, hdr); //No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_right(a, c)]
left_right_balancing(b, 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, x_oldright, NodeTraits::get_parent(x), hdr);
bstree_algo::rotate_left(x, hdr);
// reset the balancing factor // 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(x, NodeTraits::zero());
NodeTraits::set_balance(y, NodeTraits::zero()); NodeTraits::set_balance(x_oldright, NodeTraits::zero());
} }
else { // this doesn't happen during insertions else { // this doesn't happen during insertions
NodeTraits::set_balance(x, NodeTraits::positive()); 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, x_oldleft, NodeTraits::get_parent(x), hdr);
bstree_algo::rotate_right(x, hdr);
// reset the balancing factor // 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(x, NodeTraits::zero());
NodeTraits::set_balance(y, NodeTraits::zero()); NodeTraits::set_balance(x_oldleft, NodeTraits::zero());
} }
else { // this doesn't happen during insertions else { // this doesn't happen during insertions
NodeTraits::set_balance(x, NodeTraits::negative()); NodeTraits::set_balance(x, NodeTraits::negative());
NodeTraits::set_balance(y, NodeTraits::positive()); NodeTraits::set_balance(x_oldleft, NodeTraits::positive());
} }
} }

View File

@@ -1062,16 +1062,12 @@ class bstree_algorithms
//Since we've found the upper bound there is no other value with the same key if: //Since we've found the upper bound there is no other value with the same key if:
// - There is no previous node // - There is no previous node
// - The previous node is less than the key // - 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.link_left = left_child;
commit_data.node = y; 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. //! <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) static void erase(const node_ptr & header, const node_ptr & z)
{ {
data_for_rebalance ignored; 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. //! <b>Requires</b>: node is a tree node but not the header.
@@ -1447,6 +1443,88 @@ class bstree_algorithms
} }
protected: 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>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. //! <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) static bool is_right_child(const node_ptr & p)
{ return NodeTraits::get_right(NodeTraits::get_parent(p)) == 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 static void insert_before_check
(const node_ptr &header, const node_ptr & pos (const node_ptr &header, const node_ptr & pos
, insert_commit_data &commit_data , insert_commit_data &commit_data
@@ -1668,12 +1669,40 @@ class bstree_algorithms
template<class NodePtrCompare> template<class NodePtrCompare>
static void insert_equal_upper_bound_check 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) (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> template<class NodePtrCompare>
static void insert_equal_lower_bound_check 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) (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 static void insert_commit
(const node_ptr & header, const node_ptr & new_node, const insert_commit_data &commit_data) (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()); 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: private:
static void subtree_to_vine(node_ptr vine_tail, std::size_t &size) static void subtree_to_vine(node_ptr vine_tail, std::size_t &size)
{ {
//Inspired by LibAVL: //Inspired by LibAVL:
@@ -1913,98 +1996,6 @@ class bstree_algorithms
} }
return y; 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 /// @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 #endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! rbtree_algorithms provides basic algorithms to manipulate //! 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) static node_ptr erase(const node_ptr & header, const node_ptr & z)
{ {
typename bstree_algo::data_for_rebalance info; 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 color new_z_color;
if(NodeTraits::get_color(z) != NodeTraits::red()){ 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); rebalance_after_erasure(header, info.x, info.x_parent);
} }
return z; 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) 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())){ while(1){
if(x == NodeTraits::get_left(x_parent)){ 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); node_ptr w = NodeTraits::get_right(x_parent);
BOOST_ASSERT(w); BOOST_ASSERT(w);
if(NodeTraits::get_color(w) == NodeTraits::red()){ if(NodeTraits::get_color(w) == NodeTraits::red()){
NodeTraits::set_color(w, NodeTraits::black()); NodeTraits::set_color(w, NodeTraits::black());
NodeTraits::set_color(x_parent, NodeTraits::red()); 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); w = NodeTraits::get_right(x_parent);
} }
node_ptr const w_left (NodeTraits::get_left(w)); node_ptr const w_left (NodeTraits::get_left(w));
@@ -407,26 +406,27 @@ class rbtree_algorithms
} }
else { else {
if(!w_right || NodeTraits::get_color(w_right) == NodeTraits::black()){ 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()); 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); w = NodeTraits::get_right(x_parent);
} }
NodeTraits::set_color(w, NodeTraits::get_color(x_parent)); NodeTraits::set_color(w, NodeTraits::get_color(x_parent));
NodeTraits::set_color(x_parent, NodeTraits::black()); NodeTraits::set_color(x_parent, NodeTraits::black());
if(NodeTraits::get_right(w)) const node_ptr new_wright(NodeTraits::get_right(w));
NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black()); if(new_wright)
bstree_algo::rotate_left(x_parent, header); 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; break;
} }
} }
else { else {
// same as above, with right_ <-> left_. // 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()){ if(NodeTraits::get_color(w) == NodeTraits::red()){
NodeTraits::set_color(w, NodeTraits::black()); NodeTraits::set_color(w, NodeTraits::black());
NodeTraits::set_color(x_parent, NodeTraits::red()); 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); w = NodeTraits::get_left(x_parent);
} }
node_ptr const w_left (NodeTraits::get_left(w)); node_ptr const w_left (NodeTraits::get_left(w));
@@ -439,16 +439,17 @@ class rbtree_algorithms
} }
else { else {
if(!w_left || NodeTraits::get_color(w_left) == NodeTraits::black()){ 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()); 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); w = NodeTraits::get_left(x_parent);
} }
NodeTraits::set_color(w, NodeTraits::get_color(x_parent)); NodeTraits::set_color(w, NodeTraits::get_color(x_parent));
NodeTraits::set_color(x_parent, NodeTraits::black()); NodeTraits::set_color(x_parent, NodeTraits::black());
if(NodeTraits::get_left(w)) const node_ptr new_wleft(NodeTraits::get_left(w));
NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black()); if(new_wleft)
bstree_algo::rotate_right(x_parent, header); 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; break;
} }
} }
@@ -460,48 +461,49 @@ class rbtree_algorithms
static void rebalance_after_insertion(const node_ptr & header, node_ptr p) static void rebalance_after_insertion(const node_ptr & header, node_ptr p)
{ {
NodeTraits::set_color(p, NodeTraits::red()); 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(NodeTraits::get_parent(p));
node_ptr p_parent_parent(NodeTraits::get_parent(p_parent)); const node_ptr p_grandparent(NodeTraits::get_parent(p_parent));
if(bstree_algo::is_left_child(p_parent)){ if(p_parent == header || NodeTraits::get_color(p_parent) == NodeTraits::black() || p_grandparent == header){
node_ptr x = NodeTraits::get_right(p_parent_parent); break;
}
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()){ 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()); 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);
}
}
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, NodeTraits::black());
NodeTraits::set_color(p_parent_parent, NodeTraits::red()); p = p_grandparent;
NodeTraits::set_color(x, NodeTraits::black());
p = p_parent_parent;
} }
else{ else{ //Final step
if(bstree_algo::is_left_child(p)){ const bool p_is_left_child(NodeTraits::get_left(p_parent) == p);
p = p_parent; if(p_parent_is_left_child){ //p_parent is left child
bstree_algo::rotate_right(p, header); 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)); bstree_algo::rotate_right(p_grandparent, p_parent, NodeTraits::get_parent(p_grandparent), header);
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);
} }
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()); NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black());

View File

@@ -576,8 +576,8 @@ class splaytree_algorithms
if(!t_left) if(!t_left)
break; break;
if(comp(key, t_left)){ 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_) ) if( !NodeTraits::get_left(commit.t_) )
break; break;
link_right(commit.t_, commit.r_); link_right(commit.t_, commit.r_);
@@ -597,8 +597,8 @@ class splaytree_algorithms
break; break;
if(comp(t_right, key)){ 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_) ) if( !NodeTraits::get_right(commit.t_) )
break; break;
link_left(commit.t_, commit.l_); 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) 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) node_ptr p_parent(NodeTraits::get_parent(p));
; n-- node_ptr p_grandparent(NodeTraits::get_parent(p_parent));
; p_parent = NodeTraits::get_parent(p)){ while(n--){
//Check if left child if(p == NodeTraits::get_left(p_parent)){ //p is left child
if(p == NodeTraits::get_left(p_parent)){ bstree_algo::rotate_right(p_parent, p, p_grandparent, header);
bstree_algo::rotate_right(p_parent, header);
} }
else{ //Right child else{ //p is right child
bstree_algo::rotate_left(p_parent, header); 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) (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); 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 #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
@@ -547,11 +548,12 @@ class treap_algorithms
node_ptr z_left = NodeTraits::get_left(z); node_ptr z_left = NodeTraits::get_left(z);
node_ptr z_right = NodeTraits::get_right(z); node_ptr z_right = NodeTraits::get_right(z);
while(z_left || z_right){ while(z_left || z_right){
const node_ptr z_parent(NodeTraits::get_parent(z));
if(!z_right || (z_left && pcomp(z_left, z_right))){ 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{ else{
bstree_algo::rotate_left(z, header); bstree_algo::rotate_left(z, z_right, z_parent, header);
} }
++n; ++n;
z_left = NodeTraits::get_left(z); 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); rebalance_after_insertion_check(h, commit_data.node, new_node, pcomp, commit_data.rotations);
//No-throw //No-throw
bstree_algo::insert_unique_commit(h, new_node, commit_data); 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> template<class Key, class KeyNodePriorityCompare>
static void rebalance_after_insertion_check static void rebalance_after_insertion_check
(const const_node_ptr &header, const const_node_ptr & up, const Key &k (const const_node_ptr &header, const const_node_ptr & up, const Key &k
@@ -587,22 +588,6 @@ class treap_algorithms
num_rotations = n; 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> template<class NodePtrPriorityCompare>
static bool check_invariant(const const_node_ptr & header, NodePtrPriorityCompare pcomp) static bool check_invariant(const const_node_ptr & header, NodePtrPriorityCompare pcomp)
{ {