Rapid data structure review-balance Binary Tree AVL

Source: Internet
Author: User

A balanced binary tree is an evolutionary body of a binary search tree and the first binary tree that introduces the concept of balance. In 1962, g.m. Adelson-velsky and E. M. Landis invented the tree, so it is also called the AVL Tree. For each node, the height difference between the left and right Subtrees cannot exceed 1. If a node is inserted or deleted, the height difference must be greater than 1, it is necessary to rotate between nodes and maintain the binary tree in a balance state again. This solution solves the problem that the Binary Search Tree degrades to a linked list. The time complexity of insertion, search, and deletion is maintained at O (logn) in both the best and worst cases ). However, frequent rotation sacrifices the O (logn) Time for insertion and deletion, but the time is much more stable than that of the Binary Search Tree.

Most of the processes of implementing a balanced binary tree are the same as that of a binary search tree (the binary search tree must be used before learning to balance the binary tree ), the difference is that after insertion and deletion, a rotation algorithm should be written to maintain the balance. To maintain the balance, a node height attribute must be used. I wrote a C ++ version of code by referring to data structure and algorithm analysis-C language description by the Mechanical Industry Publishing House. The avltree in this book is very good, but it is not completely described. I will explain how to write a balanced binary tree step by step, focusing on the core part of the balanced binary tree, that is, the rotation algorithm.

Step 1: node Information

Compared with a binary tree node, we need to use an attribute binary tree height to maintain the Rotation Algorithm during insertion and deletion.

The Code is as follows:

 

// AVL Tree node Information
 1 class tnode 2 { 3     public: 4     int val; 5     int hgt; 6     int freq; 7     tnode* pleft; 8     tnode* pright; 9     tnode(int v):val(v),hgt(0),freq(1),pleft(NULL),pright(NULL){};10     tnode():val(0x7fffffff),hgt(0),freq(1),pleft(NULL),pright(NULL){};11 12 };

 

Step 2: declare the header Node

Tnode * head;

 

Step 3: two auxiliary methods

The rotation algorithm requires assistance from two functions: one is to calculate the height of the tree and the other is to calculate the maximum values of the two heights. It is specified that the height of an empty tree is-1, and the height of a tree with only one root node is 0. In the future, the height of each layer is increased by 1. To solve the problem of NULL pointer, write a function to calculate the height. This function is still necessary.

The Code is as follows:

 

// Calculate the height of the tree with the node as the root
1 int height(tnode *t)2 {3     if(t)4         return t->hgt;5     else6         return -1;7 }

 

Step 4: Rotate

For a balanced node, any node has a maximum of two sons. Therefore, when the height is not balanced, the height difference between the two subtree is 2. it is easy to see that this imbalance occurs in the following four situations:

1. The height of the Left subtree 3 node is 2 higher than that of the right subtree 7 node. The height of the Left subtree 1 node of the Left subtree 3 node is greater than that of the right subtree 4 node. This situation becomes left.

2. The height of the Left subtree 2 is 2 higher than that of the right subtree 7 nodes, and the height of the Left subtree 1 node of the Left subtree 2 node is less than that of the right subtree 4 nodes. This situation is left and right.

3. The height of the Left subtree 1 node of Node 2 is smaller than that of the right subtree 5 Node 2. The height of the Left subtree 3 node of the right subtree 5 Node is greater than that of the right subtree 6 node, in this case, it is left-right.

4. The height of the Left subtree 1 node of Node 2 is smaller than that of the right subtree 4 node 2. The height of the Left subtree 3 node of the right subtree 4 node is smaller than that of the right subtree 6 node, this situation becomes right.

From figure 2, we can see that the two situations 1 and 4 are symmetric, and the rotation algorithms of these two cases are consistent, and the target can be achieved only after one rotation, we call it single rotation. Two and three cases are also symmetric, and the rotation algorithms for these two cases are also consistent. Two rotations are required, which we call double rotation.

Step 5: single rotation

Single rotation is a solution for the left-left and right-right cases. These two cases are symmetric. As long as the left-left condition is solved, the right-right corner is easy to handle. Figure 3 shows the solution for the left-left condition. node K2 does not meet the Balance Feature because its left subtree K1 is two layers deeper than the right subtree Z, and in the subtree K1, A deeper layer is the left subtree x subtree of K1, so it belongs to the left subtree.

To restore the tree balance, we change K2 to the root node of the tree. Because K2 is greater than K1, K2 is placed on the right tree of K1, however, if y in the right subtree of K1 is greater than K1 and less than K2, Y is placed on the left subtree of K2, which satisfies the nature of the Binary Search Tree, it satisfies the nature of the balanced binary tree.

This operation only requires some pointer changes. As a result, we get another binary search tree, which is an AVL Tree, because X moves a layer to the previous one, Y is still at the original layer, and Z moves down one layer. The new height of the entire tree is the same as the previous height not inserted in the left subtree. The insert operation increases the x height. Therefore, since the height of the subtree remains unchanged, the path to the root node does not need to be rotated.

The Code is as follows:

 

1 // rotate left 2 void llrotate (tnode * & tree) 3 {4 tnode * TMP; 5 TMP = tree-> pleft; 6 tree-> pleft = TMP-> pright; 7 TMP-> pright = tree; 8 9 tree-> HgT = max (height (tree-> pleft), height (tree-> pright) + 1; 10 TMP-> HgT = max (height (TMP-> pleft), tree-> HgT) + 1; 11 // 12 tree = TMP; 13} 14 15 // Rotate 16 void rrrotate (tnode * & tree) 17 {18 tnode * TMP; 19 TMP = tree-> pright; 20 tree-> pright = TMP-> pleft; 21 TMP-> pleft = tree; 22 23 Tree-> HgT = max (height (tree-> pleft ), height (tree-> pright) + 1; 24 TMP-> HgT = max (height (TMP-> pleft), tree-> HgT) + 1; 25 26 tree = TMP; 27}


 

Step 6: Double Rotation

For both the left and right sides, a single rotation cannot bring it to a balanced state and requires two rotations. Dual rotation is a solution for these two cases. Likewise, these two cases are symmetric. As long as the left and right sides of the situation are solved, the right and left sides are easy to handle. Figure 4 shows the solution to the left and right situations. node K3 does not meet the Balance Feature because its left subtree K1 is two layers deeper than the right subtree Z, and in the subtree K1, the deeper layer is the right subtree K2 of K1, so it is left and right.

To restore the tree balance, we need to take two steps. The first step is to take K1 as the root and perform a right-right rotation. After rotation, it becomes the left-left condition, therefore, in the second step, the left rotation is performed again, and a balanced binary tree with K2 root is obtained.

The Code is as follows:

 

1 // rotate left and right 2 void lrrotate (tnode * & tree) 3 {4 rrrotate (tree-> pleft); 5 llrotate (tree ); 6} 7 8 // rotate 9 void rlrotate (tnode * & tree) 10 {11 llrotate (tree-> pright); 12 rrrotate (tree); 13}

 

 Step 7: insert

The insert method is basically the same as that of the binary search tree. The difference is that after the insert is complete, you need to maintain a path to the root node from the inserted node, every time a node passes through a node, the tree balance must be maintained. To maintain the tree balance, you must select different rotation algorithms based on the characteristics of the height difference.

The Code is as follows:

 

// Insert
 1 void insert(tnode *&tree,int v) 2 { 3     if(tree == NULL) 4     { 5         tree = new tnode(v); 6         return; 7     }     8     if(tree->val > v) 9     {10         insert(tree->pleft,v);11         if(2 == height(tree->pleft)-height(tree->pright))12         {13             if(v<tree->pleft->val)14                 LLRotate(tree);15             else16                 LRRotate(tree);17         }18     }19     else if(tree->val < v)20     {21         insert(tree->pright,v);22         if( 2 == height(tree->pright)-height(tree->pleft))23         {24             if(v > tree->pright->val)25                 RRRotate(tree);26             else27                 RLRotate(tree);28         }29     }30     else31         (tree->freq)++;32     33     tree->hgt = max(height(tree->pleft),height(tree->pright))+1;34 }

 

 

 

 

Step 8: traverse in the middle order

The Code is as follows:

 

// Ordinal traversal Function
1 void inOrder(tnode *tree)2 {3     if(tree == NULL)return;4     inOrder(tree->pleft);5 //    printf("%d\t",tree->val);6     printf("num:%d\thgt:%d\t",tree->val,tree->hgt);7     inOrder(tree->pright);8 }

 

Step 2: Efficiency

  The time complexity of insertion, query, and deletion of this data structure is O (logn), but the insertion and deletion of this data structure requires an additional Rotation Algorithm time, and sometimes too much rotation will also affect the efficiency.

About recursion and non-recursion. I use recursive methods to insert, search, and delete data. Non-recursive methods are generally much faster than recursive methods, however, I felt that it would be difficult to write non-recursive methods, so I chose recursive methods.

Another efficiency problem is the storage of high information. Because we only need a high degree of difference, we do not need to know the height of this tree, therefore, you only need to use two binary bits to indicate the difference. In this way, we can avoid repeated calculation of the balance factor, which can speed up a little, but the Code also loses its relative simplicity and clarity. If recursive writing is used, this microacceleration will become even smaller.

 

Because the original text in the left-handed right-hand function forgot to update the pointing of the parent class node, and the calculation of the node height in the inserted function forgot + 1, this article excerpted its content, but corrected the corresponding function.

From: http://www.cppblog.com/cxiaojia/archive/2014/03/02/187776.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.