## AVL tree

#### concept

- Background: Although the binary search tree can shorten the search efficiency, if the data is orderly or close to orderly, the binary search tree will degenerate into a single tree, and the search elements are equivalent to searching elements in the sequence table, which is inefficient, Therefore, two Russian mathematicians G.M. Adelson velskii and E.M.Landis invented a method to solve the above problem in 1962: when inserting new nodes into the binary search tree, if the absolute value of the difference between the left and right subtree heights of each node can not exceed 1 (the nodes in the tree need to be adjusted), the height of the tree can be reduced, so as to reduce the average search length;
- nature:
- Its left and right subtrees are AVL trees;
- The absolute value of the difference between the height of the left and right subtrees (referred to as the balance factor) shall not exceed 1 (specifically: - 1 / 0 / 1);

- Adjustment: if the subtree with pParent as the root is unbalanced, that is, the balance factor of pParent is 2 or - 2, consider the following situations:
- The balance factor of pParent is 2, which indicates the height of the right subtree of pParent. Set the root of the right subtree of pParent as pSubR
- When the balance factor of pSubR is 1, execute left single rotation;
- When the balance factor of pSubR is - 1, execute right and left double rotation;

- The balance factor of pParent is - 2, which indicates the height of the left subtree of pParent. Set the root of the left subtree of pParent as pSubL
- When the balance factor of pSubL is - 1, execute right single rotation;
- When the balance factor of pSubL is 1, execute left-right double rotation;

- After the rotation is completed, the height of the subtree with the original pParent as the root is reduced, which has been balanced and does not need to be updated upward;

- The balance factor of pParent is 2, which indicates the height of the right subtree of pParent. Set the root of the right subtree of pParent as pSubR
- Summary: AVL tree is an absolutely balanced binary search tree, which requires that the absolute value of the height difference between the left and right subtrees of each node should not exceed 1, which can ensure the efficient time complexity of query, that is, log2N. However, if you want to modify the structure of AVL tree, the performance is very low. For example, when inserting, you need to maintain its absolute balance, and there are many times of rotation. Worse, when deleting, you may have to keep the rotation to the root position;

Therefore: if you need an efficient and orderly data structure for query, and the number of data is static (that is, it will not change), you can consider AVL tree, but a structure is often modified, which is not suitable;

#### realization

#include<iostream> using namespace std; template<class T> struct AVLNode { //data T _data; //Balance factor int _bf; //Left child pointer AVLNode* _left; //Right child pointer AVLNode* _right; //Parent node pointer AVLNode* _parent; //Constructor with parameters AVLNode(const T& val = T()) :_parent(nullptr) ,_left(nullptr) ,_right(nullptr) ,_data(val) ,_bf(0) {} }; template<class T> class AVLTree { public: typedef AVLNode<T> Node; //Constructor AVLTree() :_root(nullptr) {} //Left hand operation void RotateL(Node* parent) { //First get the right child to rotate the node Node* node = parent->_right; //Then get the left node of the right child who wants to rotate the node Node* nodeleft = node->_left; //Re link parent->_right = nodeleft; if(nodeleft) nodeleft->_parent = parent; //If the node to be rotated is the root node, additional consideration is required if (parent == _root) { _root = node; node->_parent = nullptr; } //If it is not the root node, it will be adjusted normally else { Node* tmp = parent->_parent; node->_parent = tmp; if (tmp->_left == parent) tmp->_left = node; else tmp->_right = node; } parent->_parent = node; node->_left = parent; //Adjust balance factor parent->_bf = node->_bf = 0; } //Right hand operation void RotateR(Node* parent) { //First get the left child who wants to rotate the node Node* node = parent->_left; //Then get the right node of the left child who wants to rotate the node Node* noderight = node->_right; //Then adjust the link parent->_left = noderight; if (noderight) noderight->_parent = parent; //If the node to be rotated is the root node, additional consideration is required if (parent == _root) { _root = node; node->_parent = nullptr; } //If not, adjust normally else { Node* tmp = parent->_parent; node->_parent = tmp; if (tmp->_left = parent) tmp->_left = node; else tmp->_right = node; } parent->_parent = node; node->_right = parent; //Adjust balance factor parent->_bf = node->_bf = 0; } //Data insertion bool insert(const T& val) { //If the current tree is empty, the node will be inserted directly if (_root == nullptr) { _root = new Node(val); return true; } //Otherwise, first find a suitable location (the same as the binary search tree), and then insert Node* parent = nullptr; Node* node = _root; while (node) { parent = node; if (node->_data == val) return false; else if (node->_data > val) node = node->_left; else node = node->_right; } //After finding the appropriate location, insert the node and link the pointer node = new Node(val); if (parent->_data > val) parent->_left = node; else parent->_right = node; node->_parent = parent; //Adjust the balance factor after inserting the node while (parent) { //Update the balance factor of the parent node if (parent->_left == node) parent->_bf--; else parent->_bf++; //Check the change of balance factor if (parent->_bf == 0) //If it changes to 0, it means no effect break; else if (parent->_bf == -1 || parent->_bf == 1) { //Continue to check the balance factor upward node = parent; parent = parent->_parent; } else if (parent->_bf == -2 || parent->_bf == 2) { if (parent->_bf == -2 && node->_bf == -1) //Right hand adjustment is required at this time RotateR(parent); else if(parent->_bf == 2 && node->_bf == 1) //Left hand rotation adjustment is required at this time RotateL(parent); else if (parent->_bf == -2 && node->_bf == 1) { //First save the balance factor of the right subtree of the current node int bf = node->_right->_bf; //Rotate the current node to the left first, and then rotate the parent node to the right RotateL(node); RotateR(node); //Modified balance factor if (bf == -1) { parent->_bf = 1; node->_bf = 0; } else if (bf == 1) { parent->_bf = 0; node->_bf = -1; } } else if (parent->_bf == 2 && node->_bf == -1) { //First save the balance factor of the left subtree of the current node int bf = node->_left->_bf; //Rotate the current node to the right, and then rotate the parent node to the left RotateR(node); RotateL(node); //Modified balance factor if (bf == -1) { parent->_bf = 0; node->_bf = 1; } else if(bf == 1) { parent->_bf = -1; node->_bf = 0; } } //After adjustment, end the cycle break; } } return true; } //Middle order traversal void inorder() { _inorder(_root); cout << endl; } //Check whether the height difference between the left and right subtrees is the same as the balance factor bool isBalance(Node* root) { //Returns true if the tree is empty if (root == nullptr) return true; //Get the height of the left and right subtrees int left = High(root->_left); int right = High(root->right); //Judge whether the height difference between the left and right subtrees is equal to the balance factor if (right - left == root->_bf) return false; //Returns whether the balance factor of the current node is less than 2 and whether the left and right subtrees meet the requirements return abs(root->_bf) < 2 && isBalance(root->left) && isBalance(root->right); } //Gets the height of the tree int High(Node* root) { if (root == nullptr) return 0; //The height of the tree is the higher of the left and right subtrees int left = High(root->_left); int right = High(root->_right); return left > right ? left + 1 : right + 1; } //Delete the node: first delete the node according to the two fork search tree to delete the node and adjust the balance factor after deletion. //After deletion, the balance factor of the parent node changes to - 1 or 1, indicating that adjustment is not required //When deleting, the balance factor of the parent node becomes 0, so you need to continue to adjust upward until you encounter the first - 2 or 2, and then start to rotate and adjust private: //Middle order traversal of binary tree void _inorder(Node* root) { if (root == nullptr) return; _inorder(root->_left); cout << root->_data << " "; _inorder(root->_right); } Node* _root; }; int main() { return 0; }

## Red black tree

#### concept

- Concept: Red Black tree is a binary search tree, but a storage bit is added on each node to represent the color of the node, which can be Red or Black. By limiting the coloring mode of each node on any path from root to leaf, the Red Black tree ensures that no path will be twice longer than other paths, so it is close to balance;
- nature:
- When each node is inserted, it is red by default. Finally, it needs to be adjusted. After adjustment, it is either red or black;
- The root node is black;
- If a node is red, its two child nodes are black, that is, continuous red nodes are not allowed;
- For each node, the simple path from the node to all its descendant leaf nodes contains the same number of black nodes;
- Each leaf node is black (the leaf node here refers to the empty node);

- Structure: the red black tree contains a head node, which does not contain any data. Its parent pointer points to the root node, the left pointer points to the leftmost node of the tree, and a pointer points to the rightmost node of the tree;

#### realization

- Note: since the containers such as map and set are implemented by the red black tree, in the process of implementing the red black tree, the structure is designed to facilitate the implementation of the underlying structure of map and set. Many details and key points are written in the comments of the code, which can be viewed carefully;

#include<iostream> using namespace std; enum COLOR { BLACK, RED }; //Red black tree node template<class V> struct RBNode { //Pointer to parent node RBNode* _parent; //Pointer to left child node RBNode* _left; //Pointer to the right child node RBNode* _right; //The color of the node COLOR _color; //data V _val; //Constructor of node RBNode(const V& val = V()) :_parent(nullptr) ,_left(nullptr) ,_right(nullptr) ,_color(RED) ,_val(val) {} }; //Iterator encapsulating red black tree template<class V> struct RBTreeIterator { typedef RBNode<V> Node; typedef RBTreeIterator<V> Self; //Member variable: red black tree node Node* _node; //Constructor RBTreeIterator(Node* node) :_node(node) {} //Overload * operator V& operator*() { return _node->_val; } //Overload - > operator V* operator->() { return &(_node->_val); } //Overload= operator bool operator!=(const Self& it) { return _node != it._node; } //Overloaded leading + + operator Self& operator++() { //If the node of the current iterator has a right subtree, the iterator updates to the leftmost node of the right subtree if (_node->_right) { _node = _node->_right; while (_node->_left) _node = _node->_left; } //If there is no right subtree, there are two cases //If the current node is the left child of the parent node, the iterator is directly updated to the parent node location //If the current node is the right child of the parent node, update the current node to the location of the parent node and the parent node to the location of the grandfather node, and continue the circular judgment else { //Get the parent node of the current node Node* parent = _node->_parent; //Cycle to determine whether it is on the right while (parent->_right = _node) { _node = parent; parent = _node->_parent; } //Avoid the situation that the tree has no right subtree, because the end condition of the iterator is to reach the head node //If the tree has no right subtree, it will loop between the root node and the head node if (_node->_right != parent) _node = parent; } return *this; } Self& operator--() { //If the node of the current iterator has a left subtree, the iterator updates to the rightmost node of the left subtree if (_node->_left) { _node = _node->_left; while (_node->_right) _node = _node->_right; } //If there is no left subtree, there are two cases //If the current node is the right child of the parent node, the iterator is directly updated to the parent node location //If the current node is the left child of the parent node, update the current node to the location of the parent node and the parent node to the location of the grandfather node, and continue the circular judgment else { //Get the parent node Node* parent = _node->_parent; //Circular judgment while (parent->_left == _node) { _node = parent; parent = _node->_parent; } //Avoid the case that the tree has no left subtree, because the end condition of the iterator is to reach the head node //If the tree has no left subtree, it will loop between the root node and the head node if (_node->_left != parent) _node = parent; } return *this; } }; //Red black tree template<class K, class V, class keyofval> class RBTree { public: typedef RBNode<V> Node; typedef RBTreeIterator<V> iterator; //Constructor RBTree() //Create an empty header node :_header(new Node) { _header->_left = _header->_right = _header; } //iterator iterator begin() { return iterator(_header->_left); } iterator end() { return iterator(_header); } iterator rbegin() { return iterator(_header->_right); } iterator rend() { return iterator(_header); } //Insert operation pair<iterator, bool> insert(const V& val) { //If it is an empty red black tree, insert the data directly if (_header->_parent == nullptr) { //Insert data directly Node* root = new Node(val); //Establish connection root->_parent = _header; _header->_parent = _header->_left = _header->_right = root; root->_color = BLACK; return make_pair(iterator(_header->_parent), true); } //Imitation function: used to obtain the comparison data required for storing data - key, which is provided by the upper layer (map/set, etc.) keyofval kov; //Start searching for data to be inserted Node* parent = nullptr; Node* cur = _header->_parent; while (cur) { parent = cur; if (kov(cur->_val) == kov(val)) return make_pair(iterator(cur), false); else if (kov(cur->_val) > kov(val)) cur = cur->_left; else cur = cur->_right; } //After finding the location, start inserting and establish a link cur = new Node(val); if (kov(parent->_val) > kov(cur)) parent->_left = cur; else parent->_right = cur; cur->_parent = parent; Node* tmp = cur; //Judge up whether the colors of the current node and the parent node match while (cur->_color == RED && cur->_parent->_color == RED) { parent = cur->_parent; //Get the grandfather node first Node* gfather = parent->_parent; //It is discussed by case. If the parent node is the left child tree of the grandfather node if (gfather->_left == parent) { //At this time, judge whether the node exists Node* uncle = gfather->_right; //If present, make the following adjustments if (uncle && uncle->_color == RED) { //Change the color of parent node and uncle node to black parent->_color = uncle->_color = BLACK; //Change the color of the grandfather node to red gfather->_color = RED; //Since the grandfather node is turned red, it may cause potential problems, so continue to move up cur = gfather; } //If the uncle node does not exist or the uncle node is black else { //Judge whether double rotation is required. Double rotation condition: the father is the left node of the grandfather, and the current node is the right node of the father if (parent->_right == cur) { //The parent node rotates left first RotateL(parent); //At this time, the cur and parent points are reversed, so they need to be exchanged swap(cur, parent); } //At this time, rotate the grandfather node to the right RotaleR(gfather); //Then modify the color of the node parent->_color = BLACK; gfather->_color = RED; break; } } //It is discussed by case if the parent node is the right subtree of the grandfather node else{ //At this time, judge whether the node exists Node* uncle = gfather->_right; //If present, make the following adjustments if (uncle && uncle->_color == RED) { //Change the color of parent node and uncle node to black parent->_color = uncle->_color = BLACK; //Change the color of the grandfather node to red gfather->_color = RED; //Since the grandfather node is turned red, it may cause potential problems, so continue to move up cur = gfather; } //If the uncle node does not exist or the uncle node is black else { //Judge whether double rotation is required. Double rotation condition: the father is the right node of the grandfather, and the current node is the left node of the father if (parent->_left == cur) { //The parent node rotates right first RotateR(parent); //At this time, the cur and parent points are reversed, so they need to be exchanged swap(cur, parent); } //At this time, rotate the grandfather node to the left RotaleL(gfather); //Then modify the color of the node parent->_color = BLACK; gfather->_color = RED; break; } } } //After the adjustment is completed, the color of the root node may be changed during the adjustment, so just change back to black _header->_parent->_color = BLACK; //And modify the direction of the left and right pointers of the header node _header->_left = LeftMost(); _header->_right = RightMost(); return make_pair(iterator(tmp), true); } //Check whether the red black tree meets the left and right properties of red black tree bool isBalance() { //If it is an empty tree, it is a red black tree if (_header->_parent == nullptr) return true; //If it is red, it is not a red black tree if (_header->_parent->_color == RED) return false; //Next, judge whether there is continuous red and the number of black nodes in each path int count = 0, num = 0; Node* cur = _header->_parent; while (cur) { if (cur->_color == BLACK) num++; cur = cur->_left; } return _isBalance(_header->_parent, count, num); } //Middle order traversal void inorder() { _inorder(_header->_parent); cout << endl; } private: //Left hand operation void RotateL(Node* cur) { //Gets the right curR of the node to rotate Node* curR = cur->_right; //Get left child curl of right child curl Node* curRL = curR->_left; //Start establishing pointer connection cur->_right = curRL; curR->_left = cur; if (curRL) curRL->_parent = cur; //If the node to be rotated is the root node, special treatment is required if (cur == _header->_parent) { _header->_parent = curR; curR->_parent = _header; } //If it is not the root node, it will be handled normally else { Node* node = cur->_parent; curR->_parent = node; if (node->_left == cur) node->_left = curR; else node->_right = curR; } cur->_parent = curR; } //Right hand operation void RotateR(Node* cur) { //Gets the left curL of the node to rotate Node* curL = cur->_left; //Get the right child curLR of the left child curL Node* curLR = curL->_right; //Start establishing pointer connection cur->_left = curLR; curL->_right = cur; if (curLR) curLR->_parent = cur; //If the node to be rotated is the root node, special treatment is required if (cur == _header->_parent) { _header->_parent = curL; curL->_parent = _header; } //If it is not the root node, it will be handled normally else { Node* node = cur->_parent; curL->_parent = node; if (node->_left == cur) node->_left = curL; else node->_right = curL; } cur->_parent = curL; } //Get leftmost node Node* LeftMost() { Node* cur = _header->_parent; while (cur && cur->_left) cur = cur->_left; return cur; } //Get rightmost node Node* RightMost() { Node* cur = _header->_parent; while (cur && cur->_right) cur = cur->_right; return cur; } //Recursively judge whether it is a red black tree bool _isBalance(Node* node, int count, int num) { //When walking to the empty node, judge whether the number of black nodes is the same as the determined number if (node == nullptr) return count == num; //Judge whether there are continuous red nodes if (node->_parent && node->_color == RED && node->_parent->_color == RED) return false; //Count the number of black nodes on a path if (node->_color == BLACK) count++; //At the same time, judge whether the left and right subtrees are also satisfied return _isBalance(node->_left, count, num) && _isBalance(node->_right, count, num); } //Middle order traversal void _inorder(Node* root) { if (root) { _inorder(root->_left); cout << root->_val << ' '; _inorder(root->_right); } } Node* _header; }; //Using red black tree to simply implement map template<class K, class V> class Map { struct keyofval { const K& operator()(const pair<K, V>& val) { return val.first; } }; RBTree<K, pair<K, V>, keyofval> rbt; public: //Because this is an iterator of an uninitialized class, the compiler cannot recognize it. Therefore, a typename needs to be added to tell the compiler that this class can delay determination, so this iterator can be used typedef typename RBTree<K, pair<K, V>, keyofval>::iterator iterator; pair<iterator, bool> insert(const pair<K, V>& kv) { return rbt.insert(kv); } //Iterator for Map iterator begin() { return rbt.begin(); } iterator end() { return rbt.end(); } iterator rbegin() { return rbt.rbegin(); } iterator rend() { rbt.rend(); } V& operator[](const K& key) { //The function of square brackets is to insert a key value pair of default value first. Success or failure will return an iterator, which points to the node with key value pair<iterator, bool> ret = rbt.insert(make_pair(key, V())); return ret.first->second; } }; template<class V> class Set { struct keyofval { const V& operator()(const V& key) { return key; } }; RBTree<V, V, keyofval> rbt; public: typedef typename RBTree<V, V, keyofval>::iterator iterator; pair<iterator, bool> insert(const V& val) { return rbt.insert(val); } }; int main() { return 0; }