/** * Links two trees. The parent node is assumed to have lesser key than the * child. The child is made the leftmost node of the parent. * * @param queue Queue in which to operate * @param parent Parent node * @param child New child node */ static void link( strict_fibonacci_heap *queue, strict_fibonacci_node *parent, strict_fibonacci_node *child ) { if( parent == child->parent ) return; if( child == queue->root ) remove_from_siblings( queue, parent ); else remove_from_siblings( queue, child ); strict_fibonacci_node *next = parent->left_child; strict_fibonacci_node *prev; if( parent->left_child == NULL ) parent->left_child = child; else { prev = next->left; child->right = next; child->left = prev; prev->right = child; next->left = child; if( is_active( queue, child ) ) parent->left_child = child; } child->parent = parent; }
key_type pq_delete_min( strict_fibonacci_heap *queue ) { if( pq_empty( queue ) ) return 0; key_type key = queue->root->key; strict_fibonacci_node *current, *new_root, *old_root; int i, j; old_root = queue->root; if( old_root->left_child == NULL ) { old_root = queue->root; if( is_active( queue, old_root ) ) convert_to_passive( queue, old_root ); queue->root = NULL; } else { new_root = select_new_root( queue ); remove_from_siblings( queue, new_root ); dequeue_node( queue, new_root ); queue->root = new_root; if( is_active( queue, new_root ) ) convert_to_passive( queue, new_root ); if( is_active( queue, old_root ) ) convert_to_passive( queue, old_root ); while( old_root->left_child != NULL ) link( queue, new_root, old_root->left_child ); for( i = 0; i < 2; i++ ) { current = consume_node( queue ); if( current != NULL ) { for( j = 0; j < 2; j++ ) { if( current->left_child != NULL && !is_active( queue, current->left_child->left ) ) link( queue, new_root, current->left_child->left ); else break; } } } } pq_free_node( queue->map, STRICT_NODE_FIB, old_root ); post_delete_min_reduction( queue ); garbage_collection( queue ); queue->size--; return key; }
void Patricia::Node::remove_self(allocator<Node*> &a) { if (root()) { //rootノードは除去できない. return; } //兄弟ノード NodeList &siblings = parent_->children_; //マージするケース: size_t sz = children_.size(); //std::printf("node: remove: %lu %s ", sz, terminal() ? "t" : "-"); dump(); if (sz == 0) { remove_from_siblings(); //terminal() == trueであるはず. //- このノードが子供を持たない場合は単純に除去される。結果兄弟ノードの数が1になってしまった場合には, //そのノードと親とのマージを試みる(親がrootないし終端ノードの場合マージされない) /* eg) +ab +ac +abc +abd -ac => __root__ ab c d */ if (siblings.size() == 1) { //merge this child node with parent. //parent_とsiblings[0]はこの中で解放される. parent_->merge(a, siblings[0]); } destroy(a); } else if (terminal()) { //子供を持つ場合で終端ノードの場合. param_ = nullptr; //終端ノードではなくなるだけ.(子供があるため削除できない). if (sz == 1) { //- このノードが1つの子供を持つ場合で、終端ノードだった => このノードと子供をマージしてparent_に追加する. // eg) +ab +abc +abcd -ab => abc // thisとchildren_[0]はこのmergeの中で解放される.従ってthisにはこれ以降触らないこと. merge(a, children_[0]); } } else { //実用上、このケースは発生しない(remove_sliceで終端ノードが見つかり、かつ対象スライスを被覆していることをチェックしているため). //エラーにしても良いが、ライブラリ内部での利用で便利な可能性があるため残す。このノード以下のすべてのノードを削除する. remove_from_siblings(); destroy(a); } }
//Patricia::Node void Patricia::Node::merge(allocator<Node*> &a, Node *n) { if (terminal() || root()) { return; } //create merged node (マージされる時、必ず終端ノードとなる) Node *merged = Node::new_node(a, parent_, bytes_, len_ + n->len_, n->param_); std::memcpy(merged->bytes_ + len_, n->bytes_, n->len_); //nに子供があればmergedに付け直す. if (n->children_.size() > 0) { for (Node *c : n->children_) { c->parent_ = merged; } merged->children_ = std::move(n->children_); //moveしてくれるのでcopy発生しないはず. } //replace self with merged node in siblings remove_from_siblings(); parent_->children_.push_back(merged); parent_->sort_children(); //マージ元になったオブジェクトは破棄される n->free(a); //nのchildはすでにmergedに引き渡されている free(a); //thisはchildをn以外に持たないはず. }