tree_algorithms.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 1,626 行 · 第 1/4 页

HPP
1,626
字号
                  y = x;                  x = NodeTraits::get_left(x);               }            }            while(xu){               if(comp(key, xu)){                  yu = xu;                  xu = NodeTraits::get_left(xu);               }               else {                  xu = NodeTraits::get_right(xu);               }            }            return std::pair<node_ptr,node_ptr> (y, yu);         }      }      return std::pair<node_ptr,node_ptr> (y, y);   }   //! <b>Requires</b>: "header" must be the header node of a tree.   //!   KeyNodePtrCompare is a function object that induces a strict weak   //!   ordering compatible with the strict weak ordering used to create the   //!   the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.   //!   //! <b>Effects</b>: Returns an node_ptr to the first element that is   //!   not less than "key" according to "comp" or "header" if that element does   //!   not exist.   //!   //! <b>Complexity</b>: Logarithmic.   //!    //! <b>Throws</b>: If "comp" throws.   template<class KeyType, class KeyNodePtrCompare>   static node_ptr lower_bound      (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp)   {      node_ptr y = uncast(header);      node_ptr x = NodeTraits::get_parent(header);      while(x){         if(comp(x, key)){            x = NodeTraits::get_right(x);         }         else {            y = x;            x = NodeTraits::get_left(x);         }      }      return y;   }   //! <b>Requires</b>: "header" must be the header node of a tree.   //!   KeyNodePtrCompare is a function object that induces a strict weak   //!   ordering compatible with the strict weak ordering used to create the   //!   the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.   //!   //! <b>Effects</b>: Returns an node_ptr to the first element that is greater   //!   than "key" according to "comp" or "header" if that element does not exist.   //!   //! <b>Complexity</b>: Logarithmic.   //!    //! <b>Throws</b>: If "comp" throws.   template<class KeyType, class KeyNodePtrCompare>   static node_ptr upper_bound      (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp)   {      node_ptr y = uncast(header);      node_ptr x = NodeTraits::get_parent(header);      while(x){         if(comp(key, x)){            y = x;            x = NodeTraits::get_left(x);         }         else {            x = NodeTraits::get_right(x);         }      }      return y;   }   //! <b>Requires</b>: "header" must be the header node of a tree.   //!   "commit_data" must have been obtained from a previous call to   //!   "insert_unique_check". No objects should have been inserted or erased   //!   from the set between the "insert_unique_check" that filled "commit_data"   //!   and the call to "insert_commit".    //!    //!    //! <b>Effects</b>: Inserts new_node in the set using the information obtained   //!   from the "commit_data" that a previous "insert_check" filled.   //!   //! <b>Complexity</b>: Constant time.   //!   //! <b>Throws</b>: Nothing.   //!    //! <b>Notes</b>: This function has only sense if a "insert_unique_check" has been   //!   previously executed to fill "commit_data". No value should be inserted or   //!   erased between the "insert_check" and "insert_commit" calls.   static void insert_unique_commit      (node_ptr header, node_ptr new_value, const insert_commit_data &commit_data)   {      //Check if commit_data has not been initialized by a insert_unique_check call.      BOOST_INTRUSIVE_INVARIANT_ASSERT(commit_data.node != 0);      link(header, new_value, commit_data.node, commit_data.link_left);   }   //! <b>Requires</b>: "header" must be the header node of a tree.   //!   KeyNodePtrCompare is a function object that induces a strict weak   //!   ordering compatible with the strict weak ordering used to create the   //!   the tree. NodePtrCompare compares KeyType with a node_ptr.   //!    //! <b>Effects</b>: Checks if there is an equivalent node to "key" in the   //!   tree according to "comp" and obtains the needed information to realize   //!   a constant-time node insertion if there is no equivalent node.   //!   //! <b>Returns</b>: If there is an equivalent value   //!   returns a pair containing a node_ptr to the already present node   //!   and false. If there is not equivalent key can be inserted returns true   //!   in the returned pair's boolean and fills "commit_data" that is meant to   //!   be used with the "insert_commit" function to achieve a constant-time   //!   insertion function.   //!    //! <b>Complexity</b>: Average complexity is at most logarithmic.   //!   //! <b>Throws</b>: If "comp" throws.   //!    //! <b>Notes</b>: This function is used to improve performance when constructing   //!   a node is expensive and the user does not want to have two equivalent nodes   //!   in the tree: if there is an equivalent value   //!   the constructed object must be discarded. Many times, the part of the   //!   node that is used to impose the order is much cheaper to construct   //!   than the node and this function offers the possibility to use that part   //!   to check if the insertion will be successful.   //!   //!   If the check is successful, the user can construct the node and use   //!   "insert_commit" to insert the node in constant-time. This gives a total   //!   logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).   //!   //!   "commit_data" remains valid for a subsequent "insert_unique_commit" only   //!   if no more objects are inserted or erased from the set.   template<class KeyType, class KeyNodePtrCompare>   static std::pair<node_ptr, bool> insert_unique_check      (const_node_ptr header,  const KeyType &key      ,KeyNodePtrCompare comp, insert_commit_data &commit_data, std::size_t *pdepth = 0)   {      std::size_t depth = 0;      node_ptr h(uncast(header));      node_ptr y(h);      node_ptr x(NodeTraits::get_parent(y));      node_ptr prev(0);      //Find the upper bound, cache the previous value and if we should      //store it in the left or right node      bool left_child = true;      while(x){         ++depth;         y = x;         x = (left_child = comp(key, x)) ?                NodeTraits::get_left(x) : (prev = y, NodeTraits::get_right(x));      }      if(pdepth)  *pdepth = depth;      //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)){         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);      }   }   template<class KeyType, class KeyNodePtrCompare>   static std::pair<node_ptr, bool> insert_unique_check      (const_node_ptr header,  node_ptr hint, const KeyType &key      ,KeyNodePtrCompare comp, insert_commit_data &commit_data, std::size_t *pdepth = 0)   {      //hint must be bigger than the key      if(hint == header || comp(key, hint)){         node_ptr prev = hint;         //The previous value should be less than the key         if(prev == NodeTraits::get_left(header) || comp((prev = prev_node(hint)), key)){            commit_data.link_left = unique(header) || !NodeTraits::get_left(hint);            commit_data.node      = commit_data.link_left ? hint : prev;            if(pdepth){               *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1;            }            return std::pair<node_ptr, bool>(node_ptr(), true);         }         else{            return insert_unique_check(header, key, comp, commit_data, pdepth);         }      }      //The hint was wrong, use hintless insert      else{         return insert_unique_check(header, key, comp, commit_data, pdepth);      }   }   //! <b>Requires</b>: "header" must be the header node of a tree.   //!   NodePtrCompare is a function object that induces a strict weak   //!   ordering compatible with the strict weak ordering used to create the   //!   the tree. NodePtrCompare compares two node_ptrs. "hint" is node from   //!   the "header"'s tree.   //!      //! <b>Effects</b>: Inserts new_node into the tree, using "hint" as a hint to   //!   where it will be inserted. If "hint" is the upper_bound   //!   the insertion takes constant time (two comparisons in the worst case).   //!   //! <b>Complexity</b>: Logarithmic in general, but it is amortized   //!   constant time if new_node is inserted immediately before "hint".   //!    //! <b>Throws</b>: If "comp" throws.   template<class NodePtrCompare>   static node_ptr insert_equal      (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0)   {      if(hint == header || !comp(hint, new_node)){         node_ptr prev(hint);         if(hint == NodeTraits::get_left(header) ||             !comp(new_node, (prev = prev_node(hint)))){            bool link_left = unique(header) || !NodeTraits::get_left(hint);            link(header, new_node, link_left ? hint : prev, link_left);            if(pdepth)  *pdepth = depth(new_node) + 1;            return new_node;         }         else{            return insert_equal_upper_bound(header, new_node, comp, pdepth);         }      }      else{         return insert_equal_lower_bound(header, new_node, comp, pdepth);      }   }   //! <b>Requires</b>: p can't be a header node.   //!    //! <b>Effects</b>: Calculates the depth of a node: the depth of a   //! node is the length (number of edges) of the path from the root   //! to that node. (The root node is at depth 0.)   //!    //! <b>Complexity</b>: Logarithmic to the number of nodes in the tree.    //!    //! <b>Throws</b>: Nothing.   static std::size_t depth(const_node_ptr p)   {      std::size_t depth = 0;      node_ptr p_parent;      while(p != NodeTraits::get_parent(p_parent = NodeTraits::get_parent(p))){         ++depth;         p = p_parent;      }      return depth;   }   template<class NodePtrCompare>   static node_ptr insert_equal_upper_bound      (node_ptr h, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0)   {      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);      }      bool link_left = (y == h) || comp(new_node, y);      link(h, new_node, y, link_left);      if(pdepth)  *pdepth = depth;      return new_node;   }   template<class NodePtrCompare>   static node_ptr insert_equal_lower_bound      (node_ptr h, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0)   {      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);      }      bool link_left = (y == h) || !comp(y, new_node);      link(h, new_node, y, link_left);      if(pdepth)  *pdepth = depth;      return new_node;   }   //! <b>Requires</b>: "cloner" must be a function   //!   object taking a node_ptr and returning a new cloned node of it. "disposer" must   //!   take a node_ptr and shouldn't throw.   //!   //! <b>Effects</b>: First empties target tree calling    //!   <tt>void disposer::operator()(node_ptr)</tt> for every node of the tree   //!    except the header.   //!       //!   Then, duplicates the entire tree pointed by "source_header" cloning each   //!   source node with <tt>node_ptr Cloner::operator()(node_ptr)</tt> to obtain    //!   the nodes of the target tree. If "cloner" throws, the cloned target nodes   //!   are disposed using <tt>void disposer(node_ptr)</tt>.   //!    //! <b>Complexity</b>: Linear to the number of element of the source tree plus the.   //!   number of elements of tree target tree when calling this function.   //!    //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.   template <class Cloner, class Disposer>   static void clone      (const_node_ptr source_header, node_ptr target_header, Cloner cloner, Disposer disposer)   {      if(!unique(target_header)){         clear_and_dispose(target_header, disposer);      }      node_ptr leftmost, rightmost;      node_ptr new_root = clone_subtree         (source_header, target_header, cloner, disposer, leftmost, rightmost);      //Now update header node      NodeTraits::set_parent(target_header, new_root);      NodeTraits::set_left  (target_header, leftmost);      NodeTraits::set_right (target_header, rightmost);   }   template <class Cloner, class Disposer>   static node_ptr clone_subtree      ( const_node_ptr source_parent,  node_ptr target_parent      , Cloner cloner,                 Disposer disposer      , node_ptr &leftmost_out,        node_ptr &rightmost_out      )   {      node_ptr target_sub_root = target_parent;      node_ptr source_root = NodeTraits::get_parent(source_parent);      if(!source_root){         leftmost_out = rightmost_out = source_root;      }      else{         //We'll calculate leftmost and rightmost nodes while iterating         node_ptr current = source_root;         node_ptr insertion_point = target_sub_root = cloner(current);         //We'll calculate leftmost and rightmost nodes while iterating         node_ptr leftmost  = target_sub_root;         node_ptr rightmost = target_sub_root;         //First set the subroot         NodeTraits::set_left(target_sub_root, node_ptr(0));         NodeTraits::set_right(target_sub_root, node_ptr(0));         NodeTraits::set_parent(target_sub_root, target_parent);         dispose_subtree_disposer<Disposer> rollback(disposer, target_sub_root);         while(true) {            //First clone left nodes            if( NodeTraits::get_left(current) &&               !NodeTraits::get_left(insertion_point)) {               current = NodeTraits::get_left(current);               node_ptr temp = insertion_point;               //Clone and mark as leaf               insertion_point = cloner(current);               NodeTraits::set_left  (insertion_point, node_ptr(0));               NodeTraits::set_right (insertion_point, node_ptr(0));               //Insert left               NodeTraits::set_parent(insertion_point, temp);               NodeTraits::set_left  (temp, insertion_point);               //Update leftmost               if(rightmost == target_sub_root)                  leftmost = insertion_point;            }            //Then clone right nodes            else if( NodeTraits::get_right(current) &&                      !NodeTraits::get_right(insertion_point)){               current = NodeTraits::get_right(current);               node_ptr temp = insertion_point;               //Clone and mark as leaf               insertion_point = cloner(current);               NodeTraits::set_left  (insertion_point, node_ptr(0));               NodeTraits::set_right (insertion_point, node_ptr(0));               //Insert right               NodeTraits::set_parent(insertion_point, temp);               NodeTraits::set_right (temp, insertion_point);               //Update rightmost               rightmost = insertion_point;            }            //If not, go up            else if(current == source_root){               break;            }            else{               //Branch completed, go up searching more nodes to clone               current = NodeTraits::get_parent(current);               insertion_point = NodeTraits::get_parent(insertion_point);            }         }         rollback.release();         leftmost_out   = leftmost;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?