**Topic**

The 2-3-4 tree is a special case of B-trees and is a B-tree with a degree of 2. In the B-tree blog, we implement the B-tree is a template, so to get the 2-3-4 tree, that is, the degree of 2 B-tree is very easy, as long as the declaration can be--btree<int,2> BT, where int is the type of the elements stored.

In the subject, to achieve is the 2-3-4 Tree link and division. See red and black tree connection operation we are not difficult to get the 2-3-4 tree link method. Now, our link to the 2-3-4 tree is also promoted, that is, to achieve the link and division of any degree of B-tree.

(a)

B-Tree height changes only two ways: first, when inserting keywords, the root node is full, then it wants to split, the tree length is high, and the second is to delete the keyword, the keyword is not in the node, the root node only a keyword, and left and right children have reached the minimum key words, then will merge the root of the only key words and The tree height will be reduced by 1.

Therefore, after the node increases the height field. When the tree height in the insert, set the height of the new tree roots to the old root height plus 1 (root->height = p->height + 1;) code See B-Tree implementation, the same as; in the Erase_aux function, the code is not changed because the old root is released, pointing directly to the child, The child will become the new root.

(b) Assuming that the tree T ' is linked to the tree T, the link keyword is k and satisfies the condition any key[t] < K < key[t '],key[t] > K > key[t '] are similar.

For the sake of discussion, the name of the relevant function is first thrown.

- Nodeatrightofheight (size_t h): Find the father of the rightmost node in the tree T with height h;
- Nodeatleftofheight (size_t h): Finds the father of the leftmost node of h in the tree T;
- Linkatright (k,t '): Connect t ' and K on the right side of the tree t;
- Linkatleft (k,t '): Link T ' and K on the left side of the tree T.

If the tree T is higher than t ',

1. Call Nodeatrightofheight on the right side of the tree T to find the same node as the tree T ';

2, in the search process, for the full node, that is, the number of keywords has reached 2*degree-1 node, it calls split function to split;

3, find the father of the node, and then directly insert K into the parent node, as the last keyword, the tree T ' whole as K's right child, complete the merger. As long as the full node is split, the parent node cannot be full.

If the tree T and T ' heights are the same,

1, constructs the new root, inserts the keyword K, will t,t ' respectively as this node's right and left child, updates the related domain, merges completes.

The above two cases call linkatright;

If the tree T is shorter than t ',

1, exchange two trees;

2. Call Linkatleft to link the swapped tree T ' and K from the left to the switched tree T, which is symmetric with the first case.

Time Complexity Analysis:

obviously, for the 2-3-4 tree, the tree height is O (LGN), so the number of times to search for each descent is O (LGN). for each time, even if there is a split condition to call the Split function, because the key word count is up to 3, the for loop iteration count in the split function will not exceed 1, which is equivalent to No loop, while at insert, if the right side is connected, the two related fields are updated directly, if the left link , a maximum of two keywords will be moved without affecting the progressive time, so each time is O (1), so the total time is O (LGN).

The above procedure will post the code later.

(c) In the process of finding a keyword K, the Find path divides the entire tree into two sets and some keywords, and we discuss it with a solution to find the keyword K as an example, **each time we find the first keyword not less than k in the current node, Or when the node's keyword gets the maximum one keyword than the K-hour. **

Original 2-3-4 tree structure:

First time:

1, get the keyword D, index is 0;

2, divide the tree at D, because D is smaller than K, then continue to the right to find, get set S ' of a tree. The result diagram is as follows:

Graphic meaning:

1, Curr indicates the node currently being inspected;

2, the blue represents the split out of the set S ' element, is the key word is smaller than the sub-2-3-4 tree, Small_link_key represents the division of the keyword set;

3. Red arrows indicate the next direction to be inspected (node);

Second time:

1, get the keyword m, index is 1;

2, in the M division of the subtree, because m than k large, then to the left, to get a set of S "of a tree. The results are as follows:

Graphic meaning:

1, the red arrow refers to this node, indicating to continue to check the node;

2, gray-green means that the division of the collection of "s" tree, is the key word is larger than the tree, big_link_key the keyword set to get the word;

Third time:

1, get the keyword F, index is 0;

2, the Sub-tree division in the F, because F than k small, then to the right to find, get a set of S ' tree, similar to the first time. The result diagram is as follows:

Graphic meaning:

1, S ' has already had two elements, the keyword set has already had two elements;

Fourth time:

1, get the keyword K, index of 1;

2, the sub-tree from the K division, find the required keywords, and get two trees, sub-belong to s ' and S '. The result diagram is as follows:

Graphic meaning:

1, to the end of this division, set S ' has three elements, the keyword set has two elements;

2. There are two elements in the set S ', and the keyword set has an element.

**Note** : You do not need to update curr after the second split, and you need to update Curr to search right. This is my understanding, only in this way can guarantee the right division, do not know that friends have no other way.

According to the above analysis it is not difficult to obtain (c) Ask the answer:

1, height[ti-1 '] >= height[ti '];

2, as above. For any y belonging to Ti-1 ' and Z belong to Ti ', there are y > Ki > Z.

(d)

1, about how to realize the division no longer repeat, the above diagram is very clear, the code is given later;

2, in the next implementation, for the continuous division, each generation set S ' or S ' of a tree we will combine it with the corresponding keyword, always ensure that there is only one tree in each set, also on the side of the division, the side of the merger, the process is splittree, return two trees T ' and t '.

**The implementation code is as follows, with the following conventions:**

1, all posted too much, only paste the relevant code, other please refer to the B-tree. In addition to increasing height domain height and its maintenance, the B-tree implementation has the following three minor modifications;

2, B-tree implementation of the split function slightly modified, increase the return value, return to the new node New_child address, which is a modification of the place;

3, Nodeatrightofheight, nodeatleftofheight and inset will handle the root full situation, so the code is wrapped into a function rootfull,b tree implementation of the second place to modify;

4. The B-Tree adds a constructor, private, that is used only by node* to construct a sub-B-Tree.

**The B-tree adds a function declaration for linking and splitting:**

private:node* nodeatrightofheight (size_t); node* nodeatleftofheight (size_t); void linkatright (const T&, Btree &) void Linkatleft (const t&, btree&); void Linktwotrees (Btree &lhs, const T &link_key, Btree &RHS {if (Lhs.empty ()) {lhs.root = Rhs.root;rhs.root = nullptr;} else Lhs.link (Link_key, RHS);} void Rootfull () {node *p = Root;root = new node;//tree will grow tall root->child[0] = P;root->height = P->height + 1;root->le AF = false;split (root, 0);//Root split}explicit Btree (node *r): Root (R), compare (R->compare) {}//is only called in the Split function, private public:void Link (const t&, btree&);//tree connection, which is a forwarding function void Splittree (const t&, Btree&, btree&);//Tree Split

**The following are the specific implementations of the above functions:**

Template <typename t,int Degree,class Compare = less<t>>node<t, degree, compare>* btree<t, degree, C Ompare>::nodeatrightofheight (size_t h) {//finds the father of the rightmost node of a given height, or returns to the root when the tree height is H, prepares the tree for the right merge, and drops when looking for a full node to be split if (root-> num = = node::max_num)//If the root node is full rootfull (), Node *curr = root;if (curr->height = = h) Return curr;//Joghen is the node while (curr-> Child[curr->num]->height! = h) {//always go to the bottom right to find if (Curr->child[curr->num]->num = = node::max_num)// If the right child is full Curr = Split (Curr, Curr->num),//split, modify the Split function to return the new child's address Elsecurr = Curr->child[curr->num];} return Curr;} Template <typename T, int degree, class Compare = less<t>>node<t, degree, compare>* btree<t, degree, Compare>::nodeatleftofheight (size_t h) {//finds the father of the leftmost node of the given height, prepares the tree for the left merge, drops the search for the full node to be split if (Root->num = = Node::max _num)//If the root node is full rootfull (), Node *curr = Root;while (curr->child[0]->height! = h) {//always go to the bottom right to find if (curr->child[0]- >num = = node::max_num)//If the right child full split (Curr, 0);//Split Curr = Curr->cHILD[0];} return Curr;} Template <typename t,int degree,class Compare = less<t>>void btree<t, degree, compare>::linkatright ( Const T &k, Btree &rhs) {node *curr = nodeatrightofheight (rhs.root->height); if (Curr = = Root && curr-> Height = = rhs.root->height) {//If two trees are exactly the same height root = new Node;root->insert (k); root->child[0] = Curr;root->child [1] = Rhs.root;root->height = Curr->height + 1;root->leaf = false;} else{//Otherwise, insert the key K directly into the Curr, and then point the right child pointer to the merged tree. Because all the way down, Curr can not be full curr->insert (k); curr->child[curr->num] = Rhs.root;}} Template <typename T, int degree, class Compare = Less<t>>void btree<t, degree, Compare>::linkatleft (CO NST T &k, Btree &lhs) {node *curr = nodeatleftofheight (lhs.root->height); Curr->insert (k); for (int i = curr-& Gt;num-1; I >= 0; -i) Curr->child[i + 1] = curr->child[i];curr->child[0] = lhs.root;} Template <typename t,int degree,class Compare = less<t>>void btree<t, deGree, Compare>::link (const T &k, Btree &linkedtree) {//connection forwarding function, forwarded in the following four cases. If both trees are not empty if (compare (This->root->key[0], k) && compare (K,linkedtree.root->key[0])) {//1, any key[this] < K < Key[linkedtree]. Here the root of the No. 0 keyword is just a distinction between what kind of connection,//We assume that given the keyword and tree to meet the above relationship, the same as if (This->root->height >= linkedtree.root->height)//1.1 The tree is higher or as high as the connected tree Linkatright (k, linkedtree);//In the right side of the tree to connect else{//1.2 otherwise the tree is shorter swap (root, linkedtree.root);//Swap Two Trees linkatleft ( K, linkedtree);//Connect}}else if (compare (Linkedtree.root->key[0], k) && compare (K, this->root->) on the left side of the new tree Key[0]) {//2, Key[this] > K > key[linkedtree]if (Linkedtree.root->height < This->root->height)//2.1 If the tree high Linkatleft (k, linkedtree);//In the left side of the tree is connected else{//2.2 otherwise the tree is shorter or as high as the connected tree swap (root, linkedtree.root);//Swap Two trees linkatright (k, linkedtree);//Connect}}else{cout << "Error:bad input!" << Endl;return on the right side of the new tree; Linkedtree.root = nullptr;} Template <typename t,int Degree,class Compare = less<t>>node<t, Degree, compare>* btree<t, Degree, compare>::underfillsplit (node *curr, int index) {//Not full split, divide curr node from index to node * New_child = new Node;for (int i = index + 1; i < curr->num; ++i)//Move the key after index to the new node new_child->key[i-index-1] = Curr->key[i];if (!curr->leaf) {//If it is a leaf for (int i = index + 1; I <= curr->num; ++i)//Then move child pointer New_child->chi LD[I-INDEX-1] = Curr->child[i];} New_child->num = Curr->num-index-1;new_child->leaf = Curr->leaf;new_child->height = curr->height; Curr->num = Curr->num-new_child->num-1;return new_child;} Template <typename T, int degree, class Compare = less<t> >void btree<t,degree,compare>::splittree ( Const T &k, Btree &smalltree,btree &bigtree) {//To find the path P partition Tree of the keyword K, the collection of less than K is merged into Smalltree, and the large merge is Bigtree. We assume that k exists node *curr = root; root = nullptr; T Small_link_key = t (), Big_link_key = t (), while (true) {//index is the first keyword index in curr that is not less than k, or curr All keywords last keyword index// But this does not affect splitting int index = Curr->search (k); T temp = Curr->key[index];node *new_node = underfillsplit (Curr, index);//split the node, return the newly generated node address if (New_node->num = = 0) {/ /Jovin node has no keywords node *r = New_node;new_node = new_node->child[0];d elete R;} if (Curr->num = = 0) {//If the current node no longer has the keyword node *r = Curr;curr = curr->child[0];d elete R;} if (compare (k, temp)) {//if k is smaller than index keyword, go left, here we no longer update curr, let it continue looping at that point Linktwotrees (Bigtree, Big_link_key, Btree (new_ node); Big_link_key = temp;//Note this time the split keyword, in case the next time with}else if (compare (temp, k)) {//or if K is greater than index keyword, then go to the right, this is a special situation, When the node keyword all occurs linktwotrees (Smalltree, Small_link_key, Btree (Curr)) than the K-hour; small_link_key = Temp;curr = new_node;//Update Curr} else{//if equal, that is already split, then merge left and right two trees, End if (curr! = nullptr)//If the curr is a leaf, and if the above if statement (to satisfy NUM 0) processing,//This time curr should be empty, No need to merge Linktwotrees (Smalltree, Small_link_key, Btree (Curr)); if (new_node! = nullptr)//ditto linktwotrees (Bigtree, Big_ Link_key, Btree (New_node));

Here is an example of the test:

int main () {btree<char,2> bt,small,big;vector<char> Cvec = {' P ', ' C ', ' M ', ' T ', ' X ', ' A ', ' B ', ' D ', ' E ', ' F ', ' J ', ' K ', ' L ', ' N '};for (size_t i = 0; I! = Cvec.size (); ++i) Bt.insert (Cvec[i]) cout << "original B Tree------------" << Endl;bt.sequentialprint () bt.splittree (' F ', small, big)/*bt.splittree (' B ', small,big); Bt.splittree (' D ', Small, big); Bt.splittree (' A ', small, big) */cout << "Small-----------------------" << Endl; Small.sequentialprint () cout << "Big-------------------------" << endl;big.sequentialprint (); GetChar () ; return 0;}

In the fourth Test example above Bt.splittree (' A ', small, big), the final small tree is empty, which is correct, but the big tree has no keyword b. This is because B is the last element of the collection s ' corresponding keyword set, where two empty trees are split at a, so the last one cannot be merged, so the big tree has no keyword B, which is also true. Because the merge operation cannot merge an empty tree, the keyword will not have children, which does not conform to the nature of the B-tree.

Other tests are also correct, and for other degrees the test is correct, so it is a no-compromise B-Tree division and link, not just the 2-3-4 tree.

Finally, the first example is run:

Introduction to the algorithm 18th Chapter study Questions 18-2 2-3-4 Tree link and division, extended to the B-tree