The AVL tree is the first self-balancing Binary Search Tree invented. Its time complexity for addition, deletion, and query is O (logn), which is a very efficient data structure. The AVL tree is very suitable for scenarios such as frequent search and frequent addition and deletion. [Blog: http://blog.csdn.net/thisinnocence]
AVL Tree was born in 1962 and was invented by g.m. Adelson-velsky and E. M. Landis. The AVL Tree is a binary search tree. The binary search tree is defined as null or has the following properties:
- If its left subtree is not empty, the value of all vertices on the left subtree is smaller than its root node;
- If its right subtree is not empty, the value of all vertices on the right subtree is greater than its root node;
- Its left/right subtree is a binary search tree;
The AVL Tree is a binary search tree of the following properties:
- The height difference (balance factor) between the left and right subtree cannot exceed 1;
- Both the left and right subtree are AVL trees;
AVL Tree and red-black tree compared to common algorithms used to balance Binary Trees, they had to mention the red-black tree. The red-black tree was born in 1972 and was invented by Rudolf Bayer. It is more widely used than AVL Tree for 10 years because of its better random data insertion performance. For example, the treemap of Java, the map of C ++ STL, and the user-state address space management in Linux kernel all adopt the red-black tree algorithm. Of course, the AVL Tree is also very useful. For example, the 32-bit Windows system uses the AVL Tree for user-mode address space management. After all, aVL's search performance is quite advantageous.
Before comparison, we will introduce the definition of the red/black tree. In the introduction to algorithms, the red and black trees are defined as follows. The red and black trees refer to a binary search tree that meets the following requirements: (1) each node is either black or red. (2) the root node is black. (3) each leaf node (actually a null pointer) is black. (4) If a node is red, then its two subnodes are black (that is, there cannot be two adjacent red nodes); (5) for each node, the number of black nodes contained in the path from this node to all its child leaf nodes must be the same;
What is the difference between aVL and the red/black tree:
- The red/black tree provides better performance for random insertion of values. This type of scenario is more common and is widely used;
- AVL Tree is more advantageous for sequential data insertion;
- The red and black trees are partially balanced, reducing the rotation requirement;
- The AVL Tree is highly balanced, making query operations more advantageous;
- AVL Tree Code is easier to implement;
Small experiments (C implementation) require recursive thinking for Binary Tree-related algorithms. When analyzing problems, the overall and local aspects should be reasonably analyzed. The core of AVL tree implementation is how to maintain its balance after data is inserted. For data insertion, we must use recursion to find the corresponding leaf node and insert the corresponding data. After insertion, the corresponding rotation operation is used to maintain its balance. There are four situations for this rotation:
- Ll type, insert a new node to the left subtree of the left child of the node, with a single right hand;
- LR type. A new node is inserted into the right tree of the left child of the node, which is in double rotation. The node is left-handed first and then right-handed;
- Type RR. A new node is inserted into the right subtree of the right child of the node;
- Type RL: Insert a new node into the left Tree of the right child of the node, which is in double rotation. First, right, then left;
Code:
# Include <stdlib. h> # include <stdio. h> typedef int bool; # define true 1 # define false 0 typedef int datatype; typedef struct bitnode {datatype data; int balance; // balance factor = left subtree depth-right subtree depth, balanced binary tree:-1, 0, 1 struct bitnode * lchild, * rchild;} bitnode, * bitree; /* Right insert, left-hand */void leftrotate (bitree * t) {bitree righttree = (* t)-> rchild; (* t)-> rchild = righttree-> lchild; righttree-> lchild = (* t); (* t) = righttree;}/* left insert, right Spin */void rightrotate (bitree * t) {bitree lefttree = (* t)-> lchild; (* t)-> lchild = lefttree-> rchild; lefttree-> rchild = (* t); (* t) = lefttree;}/* left sub-tree height, left balanced */void leftbalance (bitree * t) {bitree lefttree = (* t)-> lchild; bitree lefttreeright = lefttree-> rchild; Switch (lefttree-> balance) {Case 1: // The left subtree balance factor is 1, (Insert left subtree), right-hand (* t)-> balance = 0; lefttree-> balance = 0; rightrotate (t); break; Case-1: // The left subtree balance factor is-1, (Insert left child to right subtree), double spin switch (lefttreeright-> balance) {Case 1 :( * t)-> balance =-1; lefttree-> balance = 0; break; Case 0 :( * t)-> balance = 0; lefttree-> balance = 0; break; Case-1 :( * t)-> balance = 0; lefttree-> balance = 1; break;} lefttreeright-> balance = 0; leftrotate (& (* t)-> lchild); rightrotate (t );}} /* Right sub-tree height, right balancing */void rightbalance (bitree * t) {bitree righttree = (* t)-> rchild; bitree righttreeleft = righttree-> lchild; Switch (righttree-> balance) {Case-1: // The balance factor of the right subtree is-1 (insert the right subtree), single left (* t) -> balance = 0; righttree-> balance = 0; leftrotate (t); break; Case 1: // The balance factor of the right subtree is 1, (Insert the left subtree of the right child) and switch (righttreeleft-> balance) {Case-1 :( * t)-> balance = 1; righttree-> balance = 0; break; case 0 :( * t)-> balance = 0; righttree-> balance = 0; break; Case 1 :( * t)-> balance = 0; righttree-> balance =-1; break;} righttreeleft-> balance = 0; rightrotat E (& (* t)-> rchild); leftrotate (t) ;}}/* AVL Tree insert, locate first, and then insert, then maintain the self-balancing */bool insertavl (bitree * t, int ELEM, bool * taller) {If (* t = NULL) {* t = (bitree) malloc (sizeof (bitnode); (* t)-> DATA = ELEM; (* t)-> balance = 0; (* t)-> lchild = NULL; (* t)-> rchild = NULL; * taller = true; return true;} If (ELEM = (* t)-> data) {* taller = false; return false;} // If the inserted element is smaller than the root node, search for the left subtree recursively and maintain the-left balance after insertion if (ELEM <(* t)-> data) {If (! Insertavl (& (* t)-> lchild), ELEM, Taller) return false; If (* taller) {Switch (* t)-> balance) {Case 1: leftbalance (t); * taller = false; break; Case 0 :( * t)-> balance = 1; * taller = true; break; case-1 :( * t)-> balance = 0; * taller = false; break ;}}// if the inserted element is greater than the root node, search for the right subtree recursively, after insertion, maintain-right balance if (ELEM> (* t)-> data) {If (! Insertavl (& (* t)-> rchild), ELEM, Taller) return false; If (* taller) {Switch (* t)-> balance) {Case 1 :( * t)-> balance = 0; * taller = false; break; Case 0 :( * t)-> balance =-1; * taller = true; break; case-1: rightbalance (t); * taller = false; break ;}}return true;} void inordertraverse (bitree t) {If (t = NULL) return; inordertraverse (t-> lchild); printf ("% d", T-> data); inordertraverse (t-> rchild);} void preordertraverse (bitree T) {If (t = NULL) return; printf ("% d", T-> data); preordertraverse (t-> lchild); preordertraverse (t-> rchild );} int main () {int A [10] = {3, 2, 1, 4, 5, 6, 7, 0, 9, 8}; int I; bool taller; bitree T = NULL; for (I = 0; I <10; I ++) {insertavl (& T, a [I], & taller);} printf ("inordertraverse: "); inordertraverse (t); printf (" \ npreordertraverse: "); preordertraverse (t); Return 0 ;}/ * The running result is as follows, the recoverable Binary Tree verifies accuracy of inordertraverse: 0 1 2 3 4 5 6 7 8 9 preordertraverse: 4 2 1 0 3 6 5 8 7 9 */
Algorithm learning note balancing Binary Tree AVL Tree