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 + -
显示快捷键?