http://blog.csdn.net/niteip/article/details/11840691
The Balanced binary tree (Balanced binary trees) is an evolutionary body of a two-fork search tree, and the first two-tree that introduces a concept of balance. In 1962, G.M Adelson-velsky and E.M Landis invented the tree, so it was also called the AVL tree. Balanced binary tree requirements for each node, its left and right sub-tree height difference can not exceed 1, if the insertion or deletion of a node so that the difference between the height of more than 1, it is necessary to rotate between the nodes, the two fork tree back to maintain a balance state. This solution solves the problem of a two-fork lookup tree degenerate into a linked list, keeping the time complexity of inserting, finding, deleting, and the worst case in O (Logn). However, frequent rotations can make insertion and deletion sacrifice O (Logn) time, but the time is much more stable relative to binary search trees.
The majority of the process of the balanced binary tree is the same as the two-fork search tree (the binary tree must be found before balancing the two forks), the difference is that after inserting and deleting a rotation algorithm to maintain the balance, maintaining the balance requires the use of a node height attribute. I refer to the mechanical industry press, "Data structure and algorithm analysis-C language description" wrote a C + + version of the code. The Avltree of the book is very good, but it is not completely described. I'll explain how to write a balanced binary tree, with emphasis on balancing the core of the binary tree, which is the rotation algorithm.
First Step: node information
With respect to the nodes of the binary lookup tree, we need to use the height of an attribute binary tree to maintain the rotation algorithm in the INSERT and delete processes.
The code is as follows:
AVL tree Node Information
Template<class t>
Class TreeNode
{
Public
TreeNode (): Lson (null), Rson (null), Freq (1), HGT (0) {}
T data;//Value
int hgt;//The height of the tree with this node as its root
unsigned int freq;//frequency
treenode* lson;//pointing to the left son's address
treenode* rson;//means the address of the right son.
};
Second step: Balance the declaration of the Binary Tree class
The rotation function in the declaration is explained in the following steps.
The code is as follows:
Properties and method declarations for AVL tree classes
Template<class t>
Class Avltree
{
Private
treenode<t>* root;//root Node
void Insertpri (treenode<t>* &node,t x);//Insert
treenode<t>* Findpri (treenode<t>* node,t x);//Find
void Insubtree (treenode<t>* node);//Middle sequence traversal
void Deletepri (treenode<t>* &node,t x);//delete
int height (treenode<t>* node);//Find the height of the tree
void Singrotateleft (treenode<t>* &k2);//rotation in left-left case
void Singrotateright (treenode<t>* &k2);//right-right case rotation
void Doublerotatelr (treenode<t>* &k3);//rotation around the case
void Doublerotaterl (treenode<t>* &k3);//rotation in right-left case
int max (int cmpa,int CMPB);//MAX value
Public
Avltree (): root (NULL) {}
void Insert (T x);//Insert Interface
treenode<t>* Find (T x);//Lookup interface
void Delete (T x);//delete interface
void traversal ();//Traversal interface
};
Step three: two helper methods
The rotation algorithm needs the aid of two functions, one is to find the height of the tree, and the other is to find the maximum value of two heights. It is stipulated here that the height of an empty tree is-1, the height of the tree with only one root node is 0, and the height of each additional layer is added 1. In order to solve the null of the pointer, it is necessary to write a function of height.
The code is as follows:
Calculate the height of a tree with a node root
Template<class t>
int Avltree<t>::height (treenode<t>* node)
{
if (node!=null)
Return node->hgt;
return-1;
}
To find the maximum value
Template<class t>
int Avltree<t>::max (int cmpa,int CMPB)
{
Return cmpa>cmpb?cmpa:cmpb;
}
Fourth step: Rotate
For a balanced node, since any node has a maximum of two sons, the height imbalance of the two subtrees of this node is 2. It is easy to see that this imbalance appears in the following four scenarios:
1, 6 nodes of the left subtree 3 node height than the right subtree 7 node large 2, left subtree 3 node left subtree 1 node height is greater than right subtree 4 node, this situation becomes left left.
2, 6 nodes of the left subtree 2 node height than the right subtree 7 node large 2, left subtree 2 node of the left subtree 1 node height is less than the right subtree 4 nodes, this situation becomes around.
3, 2 nodes of the left subtree 1 node height than the right subtree 5 node small 2, right subtree 5 node left subtree 3 node height is greater than right subtree 6 node, this situation becomes right left.
4, 2 nodes of the left subtree 1 node height than the right subtree 4 node small 2, right subtree 4 node of the left subtree 3 node height is less than the right subtree 6 node, this situation becomes right and right.
As can be seen from Figure 2, the 1 and 42 cases are symmetric, the two cases of rotation algorithm is consistent, only need to go through a single rotation to achieve the goal, we call it a one-spin. The 2 and 32 cases are also symmetrical, and the rotation algorithm of the two cases is consistent and requires two rotations, which we call double rotations.
Fifth Step: Single rotation
Single rotation is a solution for both left and right, and the two cases are symmetric, as long as the left-left is resolved, right-right is good. Figure 3 is the left-to-left solution, the node K2 does not meet the balance characteristics, because its left subtree K1 than the right subtree Z depth 2 layers, and K1 subtree, the deeper layer is the K1 left subtree x subtree, so belongs to the left left case.
To restore the balance of the tree, we turn the K2 into the root node of this tree, because K2 is greater than K1, the K2 is placed on the right sub-tree of K1, while the original K1 right subtree of y is greater than K1, less than K2, put y in the K2 of the left sub-tree, so that both meet the nature of the two-fork search tree, and meet the nature of
This operation only requires a part of the pointer changes, and we get another binary search tree, which is an AVL tree, because x moves up one layer, Y also stays on the original level, Z moves down a layer. The new height of the whole tree is the same as the height that was not previously inserted on the left subtree, and the insert operation causes the x height to grow high. Therefore, the path to the root node does not need to continue to rotate because the subtree height has not changed.
The code is as follows:
Rotation in left-to-left case
Template<class t>
void Avltree<t>::singrotateleft (treenode<t>* &k2)
{
treenode<t>* K1;
k1=k2->lson;
k2->lson=k1->rson;
k1->rson=k2;
K2->hgt=max (height (k2->lson), height (k2->rson)) +1;
K1->hgt=max (height (k1->lson), k2->hgt) +1;
}
Right-right case rotation
Template<class t>
void Avltree<t>::singrotateright (treenode<t>* &k2)
{
treenode<t>* K1;
k1=k2->rson;
k2->rson=k1->lson;
k1->lson=k2;
K2->hgt=max (height (k2->lson), height (k2->rson)) +1;
K1->hgt=max (height (k1->rson), k2->hgt) +1;
}
Sixth step: Double rotation
For both right and left, the single rotation does not make it a balanced state, and it has to be rotated two times. Double rotation is a solution for both cases, and the same is true for both cases, as long as the right and left side of the situation is resolved. Figure 4 is a solution to the situation, the node K3 does not meet the balance characteristics, because its left subtree K1 than the right subtree Z depth 2 layer, and K1 subtree, the deeper layer is K1 right subtree K2 subtree, so belongs to the situation.
In order to restore the balance of the tree, we need to take two steps, the first step, the K1 as the root, a right-right rotation, after the rotation of the left to the left, so the second step to the left and left rotation, and finally got a k2 root of the balance of the binary tree tree.
The code is as follows:
Rotation of the left and right conditions
Template<class t>
void Avltree<t>::D oublerotatelr (treenode<t>* &k3)
{
Singrotateright (K3->lson);
Singrotateleft (K3);
}
Rotation of the right-to-left condition
Template<class t>
void Avltree<t>::D Oublerotaterl (treenode<t>* &k3)
{
Singrotateleft (K3->rson);
Singrotateright (K3);
}
Seventh step: Insert
The method of insertion is basically the same as a two-fork lookup tree, except that when the insert is complete, a path to the root node is maintained from the inserted node, maintaining the tree balance for each node that passes through it. To maintain the balance of the tree, different rotation algorithms are chosen according to the characteristics of height difference.
The code is as follows:
Insert
Template<class t>
void Avltree<t>::insertpri (treenode<t>* &node,t x)
{
if (node==null)//If the node is empty, add x information at this node
{
Node=new treenode<t> ();
node->data=x;
Return
}
if (node->data>x)//If x is less than the value of the node, continue inserting X in the left subtree of the node
{
Insertpri (NODE->LSON,X);
if (2==height (Node->lson)-height (Node->rson))
if (X<node->lson->data)
Singrotateleft (node);
Else
DOUBLEROTATELR (node);
}
else if (node->data<x)//If x is greater than the value of the node, continue inserting X in the right subtree of the node
{
Insertpri (NODE->RSON,X);
if (2==height (Node->rson)-height (Node->lson))//If the difference in height is 2, you lose balance and need to rotate
if (X>node->rson->data)
Singrotateright (node);
Else
Doublerotaterl (node);
}
else + + (node->freq);//If equal, increase the frequency by 1
Node->hgt=max (height (node->lson), height (node->rson));
}
Insert Interface
Template<class t>
void Avltree<t>::insert (T x)
{
Insertpri (ROOT,X);
}
Eighth Step: Find
Compared to the two-fork lookup tree, the lookup method has no political reform, but depending on the stored characteristics, the AVL tree can maintain a stable time of O (Logn), while the binary lookup tree is quite unstable.
The code is as follows:
Find
Template<class t>
treenode<t>* Avltree<t>::findpri (treenode<t>* node,t x)
{
if (node==null)//If the node is empty description not found, return NULL
{
return NULL;
}
if (node->data>x)//If x is less than the value of the node, continue looking for x in the left subtree of the node
{
Return Findpri (NODE->LSON,X);
}
else if (node->data<x)//If x is greater than the value of the node, continue to find X in the left subtree of the node
{
Return Findpri (NODE->RSON,X);
}
else return node;//If equal, this node is found
}
Find interfaces
Template<class t>
treenode<t>* Avltree<t>::find (T x)
{
Return Findpri (ROOT,X);
}
Nineth Step: Delete
The removed method is also consistent with the two-fork lookup tree, except that after the deletion is complete, the father that deletes the node needs to start to maintain the balance of the tree up to the root node.
The code is as follows:
Delete
Template<class t>
void Avltree<t>::D eletepri (treenode<t>* &node,t x)
{
if (node==null) return;//the node with the value x is not found
if (x < node->data)
{
Deletepri (node->lson,x);//If x is less than the value of the node, continue to delete the X in the left subtree of the node
if (2==height (Node->rson)-height (Node->lson))
if (node->rson->lson!=null&& (height (node->rson->lson) >height (Node->rson->rson)))
Doublerotaterl (node);
Else
Singrotateright (node);
}
else if (x > Node->data)
{
Deletepri (node->rson,x);//if x is greater than the value of the node, continue to delete the X in the right subtree of the node
if (2==height (Node->lson)-height (Node->rson))
if (node->lson->rson!=null&& (height (node->lson->rson) >height (Node->lson->lson)))
DOUBLEROTATELR (node);
Else
Singrotateleft (node);
}
else//if equal, this node is the node to be deleted
{
if (Node->lson&&node->rson)//This node has two sons
{
treenode<t>* Temp=node->rson;//temp pointing to the right son of the node
while (Temp->lson!=null) temp=temp->lson;//finds the node with the lowest value in the right subtree
Assigns the value of the smallest node in the right subtree to this node
node->data=temp->data;
node->freq=temp->freq;
Deletepri (node->rson,temp->data);//delete the node with the smallest value in the right subtree
if (2==height (Node->lson)-height (Node->rson))
{
if (node->lson->rson!=null&& (height (node->lson->rson) >height (Node->lson->lson)))
DOUBLEROTATELR (node);
Else
Singrotateleft (node);
}
}
else//there are 1 or 0 sons of this node
{
treenode<t>* Temp=node;
if (node->lson==null)//have a right son or no son
node=node->rson;
else if (node->rson==null)//have left son
node=node->lson;
Delete (temp);
Temp=null;
}
}
if (node==null) return;
Node->hgt=max (height (node->lson), height (node->rson)) +1;
Return
}
Remove interface
Template<class t>
void Avltree<t>::D elete (T x)
{
Deletepri (ROOT,X);
}
Tenth step: Middle Sequence traversal
The code is as follows:
Middle Sequence traversal function
Template<class t>
void Avltree<t>::insubtree (treenode<t>* node)
{
if (node==null) return;
Insubtree (Node->lson);//Traverse Zuozi First
cout<<node->data<< "";//output root node
Insubtree (Node->rson);//re-traverse right sub-tree
}
Middle Sequence Traversal interface
Template<class t>
void Avltree<t>::traversal ()
{
Insubtree (root);
}
11th Step: About efficiency
This data structure inserts, finds, and deletes have a time complexity of O (LOGN), but inserting and deleting requires additional rotation algorithms, and sometimes too much rotation can affect efficiency.
About recursion and non-recursion. I use recursive methods to insert, find and delete, rather than recursive methods are generally much faster than recursive methods, but I feel that the non-recursive method is more difficult to write, so I chose the recursive method.
There is also a problem with the efficiency of the storage of high information, because we need only the height of the difference, do not need to know the height of the tree, so only need to use two bits can represent the difference. This avoids the repetitive calculation of the balance factor and can speed up a little bit, but the code loses its relative simplicity and clarity. This micro-acceleration is even more negligible if you use recursive notation.
If there is something wrong or unclear, please point out that I will revise and refine it.
Step by step Write balanced binary tree (AVL tree)