C++_ Illustration of insertion search judgment of hand torn red black tree_ KeyValue model (trigeminal chain)

Keywords: C++ data structure Back-end

1. Red black tree concept

First look at the AVL tree:
AVL tree is a highly balanced binary search tree
Implementation of AVL tree insertion
Look at the red and black trees:
The Red Black tree is also a binary search tree. However, a storage bit is added to 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

Properties of red black tree

  1. Each node is either red or black
  2. The root node is black
  3. If a node is red, its two child nodes are black
  4. For each node, the simple path from the node to all its descendant leaf nodes contains the same number of black nodes
  5. Each empty node is black.

After ensuring the above properties, the red black tree ensures that no path will be twice longer than other paths.
Reason: suppose there are 3 black nodes on a path. The shortest path of this tree is all black 3, and the longest path is alternating black and red 6. The longest path is exactly twice as long as the shortest path, just in line with the red black tree structure.

2. Red black tree KV model

Basic structure

#pragma once

#include<iostream>
using namespace std;

enum Color
{
	RED = 0, BLACK,
};

template<class Key, class Value>
struct RBTreeNode
{
	RBTreeNode<Key, Value>* _left;
	RBTreeNode<Key, Value>* _right;
	RBTreeNode<Key, Value>* _parent;
	pair<Key, Value> _kv;
	Color col;
	RBTreeNode(const pair<Key, Value>& val)
		:_left(nullptr), _right(nullptr), _parent(nullptr), _kv(val), col(RED)//Default node color
	{}
};


template<class Key,class Value>
class RBTree
{
	typedef RBTreeNode<Key, Value> Node;
public:
	RBTree() :_root(nullptr) {}

	pair<Node*, bool>Insert(const pair<Key, Value>val);//Insertion of red black tree
private:
	Node* _root;
};

3. Insertion of red black tree

The red black tree is based on the binary search tree with its balance constraints. Therefore, the insertion of red black tree can be divided into two steps:

  1. Insert new nodes according to the tree rules of binary search.
  2. Modify the node color to maintain the red black tree property

Case 1: the red black tree is empty. At this time, a node is created during insertion, and the color of the node is changed to black.

pair<Node*, bool>Insert(const pair<Key, Value>val)//Insertion of red black tree
{
	if (_root == nullptr)
	{
		_root = new Node(val);
		_root->col = BLACK;
		return make_pair(_root, true);
	}

Case 2:
1. The red black tree is not empty. First traverse the red black tree to find the location to insert. At the same time, find whether there are duplicate nodes. If the insertion of duplicate nodes fails, return the pointer of this position and false. In order to implement the trigeminal chain, a parent pointer is also required to point to the previous node of cur

//Binary search tree insertion
Node* cur = _root;
Node* parent = nullptr;
while (cur != nullptr)
{
	if (cur->_kv.first < val.first)
	{
		parent = cur;
		cur = cur->_right;
	}
	else if (cur->_kv.first > val.first)
	{
		parent = cur;
		cur = cur->_left;
	}
	else//Duplicate key value, failed to insert
	{
		return make_pair(cur, false);
	}
}

2. After the above function is completed, cur points to nullptr and parent points to the previous location to be connected

Cur creates a new red node. According to the characteristics of binary search tree, it is also necessary to judge the value of cur node and parent node. If the value of cur node is less than parent, insert it to the left of parent node, otherwise insert it to the right of parent node.

cur = new Node(val);
cur->col = RED;
if (parent->_kv.first > val.first)
{
	parent->_left = cur;
}
else
{
	parent->_right = cur;
}
cur->_parent = parent;

3. Here, even if the node insertion is completed, we have to adjust the node color of the red black tree to make it comply with the rules of the red black tree. Before that, record the position of the inserted node to return the pair value

The second is to adjust the color of red and black trees
For the convenience of description, record the names of the four nodes cur, parent, uncle and grandparent. The positions of these four nodes are shown in the figure below, referred to as c p u g for short

If the inserted parent is black, there is no need to adjust the color of the tree, and the insertion is completed.

The inserted parent is red, and the two red are continuous. Need to deal with

① p is the left subtree of g, cur is red, p is red, g is black, u exists and is red


You can write the code according to the figure above

while (parent != nullptr && parent->col == RED)//The stop condition is analyzed in the figure above
{
	Node* GradParent = parent->_parent;//Record gradparent node
	if (parent == GradParent->_left)//The key is to see the color of the Uncle node
	{
		Node* Uncle = GradParent->_right;
		//Case 1: Uncle exists and is red
		if (Uncle && Uncle->col == RED)
		{
			parent->col = Uncle->col = BLACK;
			GradParent->col = RED;
			cur = GradParent;//Circular upward judgment
			parent = cur->_parent;
		}
	}
	else//parent=GradParent->_right
	{
		......
	}
}
_root->col = BLACK;//Change the color of the root to black to prevent the above process from changing the root node to red
return make_pair(End, true);

② p is the left subtree of g, cur is red, p is red, g is black, u does not exist / u is black (cur,p,g is a straight line)_ Single rotation

First: when this happens, cur must not be a newly inserted node. It must have happened when the color was adjusted upward
reason:

Treatment method:

According to the above analysis, we can write the following code

pair<Node*, bool>Insert(const pair<Key, Value>val)//Insertion of red black tree
{
	if (_root == nullptr)
	{
		_root = new Node(val);
		_root->col = BLACK;
		return make_pair(_root, true);
	}
	//Binary search tree insertion
	Node* cur = _root;
	Node* parent = nullptr;
	while (cur != nullptr)
	{
		if (cur->_kv.first < val.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > val.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else//Duplicate key value, failed to insert
		{
			return make_pair(cur, false);
		}
	}
	cur = new Node(val);
	cur->col = RED;
	if (parent->_kv.first > val.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
	Node* End = cur;//Node that records the insertion location
	//Control path
	while (parent != nullptr && parent->col == RED)
	{
		Node* GradParent = parent->_parent;
		if (parent == GradParent->_left)//The key is to see the color of the Uncle node
		{
			Node* Uncle = GradParent->_right;
			//Case 1: Uncle exists and is red
			if (Uncle && Uncle->col == RED)
			{
				parent->col = Uncle->col = BLACK;
				GradParent->col = RED;
				cur = GradParent;
				parent = cur->_parent;
			}
			else//Uncle does not exist or is black
			{
				if (cur == parent->_left)//Right high, right rotation
				{
					_Single_Right(GradParent);
					GradParent->col = RED;
					parent->col = BLACK;
				}
				break;//After rotation, the number of black nodes remains unchanged and directly jump out of the cycle
			}
		else//parent=GradParent->_right
		{
			......
		}
	}
	_root->col = BLACK;//Change the color of the root to black to prevent it from jumping out of the root and turning red
	return make_pair(End, true);
}

The right single rotation code is similar to the right rotation of AVL tree. Write the code according to the rotation diagram below

void _Single_Right(Node* parent)//The right single rotation connects the correspondence according to the figure
{
	//Record the node to be moved
	Node* SubL = parent->_left;
	Node* SubLR = SubL->_right;

	//connect
	parent->_left = SubLR;
	if (SubL->_right != nullptr)//Modify parent pointer
	{
		SubLR->_parent = parent;
	}
	//connect
	SubL->_right = parent;
	Node* GradParent = parent->_parent;//Record the parent node of this node in order to modify the root node
	parent->_parent = SubL;//Modify parent pointer
	//Adjust root node
	if (parent == _root)//The node to rotate is the root node
	{
		_root = SubL;
		SubL->_parent = GradParent;
	}
	else//If the node to be rotated is a subtree, modify the GradParent pointer
	{
		if (GradParent->_left == parent)
		{
			GradParent->_left = SubL;
		}
		else
		{
			GradParent->_right = SubL;
		}
		SubL->_parent = GradParent;
	}
}

③ p is the left subtree of g, cur is red, p is red, g is black, u does not exist / u is black (cur,p,g are broken lines)_ Double rotation


Treatment method:

Write the code according to the figure above

pair<Node*, bool>Insert(const pair<Key, Value>val)//Insertion of red black tree
{
	if (_root == nullptr)
	{
		_root = new Node(val);
		_root->col = BLACK;
		return make_pair(_root, true);
	}
	//Binary search tree insertion
	Node* cur = _root;
	Node* parent = nullptr;
	while (cur != nullptr)
	{
		if (cur->_kv.first < val.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > val.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else//Duplicate key value, failed to insert
		{
			return make_pair(cur, false);
		}
	}
	cur = new Node(val);
	cur->col = RED;
	if (parent->_kv.first > val.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
	Node* End = cur;//Node that records the insertion location
	//Control path
	while (parent != nullptr && parent->col == RED)
	{
		Node* GradParent = parent->_parent;
		if (parent == GradParent->_left)//The key is to see the color of the Uncle node
		{
			Node* Uncle = GradParent->_right;
			//Case 1: Uncle exists and is red
			if (Uncle && Uncle->col == RED)
			{
				parent->col = Uncle->col = BLACK;
				GradParent->col = RED;
				cur = GradParent;
				parent = cur->_parent;
			}
			else//Uncle does not exist or is black
			{
				if (cur == parent->_left)//Right high, right rotation
				{
					_Single_Right(GradParent);
					GradParent->col = RED;
					parent->col = BLACK;
				}
				else//Broken line shape, left and right double rotation
				{
					_Single_Left(parent);
					_Single_Right(GradParent);
					cur->col = BLACK;
					parent->col = GradParent->col = RED;
				}
				break;//After rotation, the number of black nodes remains unchanged and directly jump out of the cycle
			}
		else//parent=GradParent->_right
		{
			......
		}
	}
	_root->col = BLACK;//Change the color of the root to black to prevent the above process from changing the root node to red
	return make_pair(End, true);
}

The left single rotation is similar to the left single rotation of AVL tree, and the rotation principle is the same as that of the right single rotation picture, so it is not repeated

void _Single_Left(Node* parent)//Left rotation
{
	//Record the node to be moved
	Node* SubR = parent->_right;
	Node* SubRL = SubR->_left;

	//connect
	parent->_right = SubRL;
	if (SubRL != nullptr)
	{
		SubRL->_parent = parent;
	}
	SubR->_left = parent;
	Node* GradParent = parent->_parent;//Record the parent node of this node in order to modify the root node
	parent->_parent = SubR;

	//Adjust root node
	if (parent == _root)
	{
		_root = SubR;
		SubR->_parent = GradParent;
	}
	else //If the node to be rotated is a subtree, modify the GradParent pointer
	{
		if (GradParent->_left == parent)//The rotation is the left subtree, connected to the left
		{
			GradParent->_left = SubR;
		}
		else
		{
			GradParent->_right = SubR;//conversely
		}
		SubR->_parent = GradParent;
	}
}

④ p is the right subtree of g, cur is red, p is red, g is black, u exists and is red

This situation is the same as ①, so it is not repeated

⑤ p is the right subtree of g, cur is red, p is red, g is black, u does not exist / u is black (cur,p,g is a straight line)_ Single rotation

⑥ p is the right subtree of g, cur is red, p is red, g is black, u does not exist / u is black (cur,p,g are broken lines)_ Double rotation


According to the above figure, the lower half logic of red black tree insertion can be written

Insertion code of red black tree

pair<Node*, bool>Insert(const pair<Key, Value>val)//Insertion of red black tree
{
	if (_root == nullptr)
	{
		_root = new Node(val);
		_root->col = BLACK;
		return make_pair(_root, true);
	}
	//Binary search tree insertion
	Node* cur = _root;
	Node* parent = nullptr;
	while (cur != nullptr)
	{
		if (cur->_kv.first < val.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > val.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else//Duplicate key value, failed to insert
		{
			return make_pair(cur, false);
		}
	}
	cur = new Node(val);
	cur->col = RED;
	if (parent->_kv.first > val.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
	Node* End = cur;//Node that records the insertion location
	//Control path
	while (parent != nullptr && parent->col == RED)
	{
		Node* GradParent = parent->_parent;
		if (parent == GradParent->_left)//The key is to see the color of the Uncle node
		{
			Node* Uncle = GradParent->_right;
			//Case 1: Uncle exists and is red
			if (Uncle && Uncle->col == RED)
			{
				parent->col = Uncle->col = BLACK;
				GradParent->col = RED;
				cur = GradParent;
				parent = cur->_parent;
			}
			else//Uncle does not exist or is black
			{
				if (cur == parent->_left)//Right high, right rotation
				{
					_Single_Right(GradParent);
					GradParent->col = RED;
					parent->col = BLACK;
				}
				else//Broken line shape, left and right double rotation
				{
					_Single_Left(parent);
					_Single_Right(GradParent);
					cur->col = BLACK;
					parent->col = GradParent->col = RED;
				}
				break;//After rotation, the number of black nodes remains unchanged and directly jump out of the cycle
			}
		}
		else//parent=GradParent->_right
		{
			Node* Uncle = GradParent->_left;
			if (Uncle != nullptr && Uncle->col == RED)
			{
				Uncle->col = parent->col = BLACK;
				GradParent->col = RED;
				cur = GradParent;
				parent = cur->_parent;
			}
			else
			{
				if (cur == parent->_right)//Left high, left rotation
				{
					_Single_Left(GradParent);
					GradParent->col = RED;
					parent->col = BLACK;
				}
				else//Polyline, right left double rotation
				{
					_Single_Right(parent);
					_Single_Left(GradParent);
					cur->col = BLACK;
					GradParent->col = RED;
				}
				break;
			}
		}
	}
	_root->col = BLACK;//Change the color of the root to black to prevent the root node from jumping out of the loop in the first case, and the root node turns red
	return make_pair(End, true);
}

//Private: rotation code
void _Single_Right(Node* parent)//The right single rotation connects the correspondence according to the figure
{
	//Record the node to be moved
	Node* SubL = parent->_left;
	Node* SubLR = SubL->_right;

	//connect
	parent->_left = SubLR;
	if (SubL->_right != nullptr)//Modify parent pointer
	{
		SubLR->_parent = parent;
	}
	//connect
	SubL->_right = parent;
	Node* GradParent = parent->_parent;//Record the parent node of this node in order to modify the root node
	parent->_parent = SubL;//Modify parent pointer
	//Adjust root node
	if (parent == _root)//The node to rotate is the root node
	{
		_root = SubL;
		SubL->_parent = GradParent;
	}
	else//If the node to be rotated is a subtree, modify the GradParent pointer
	{
		if (GradParent->_left == parent)
		{
			GradParent->_left = SubL;
		}
		else
		{
			GradParent->_right = SubL;
		}
		SubL->_parent = GradParent;
	}
}

void _Single_Left(Node* parent)//Left rotation
{
	//Record the node to be moved
	Node* SubR = parent->_right;
	Node* SubRL = SubR->_left;

	//connect
	parent->_right = SubRL;
	if (SubRL != nullptr)
	{
		SubRL->_parent = parent;
	}
	SubR->_left = parent;
	Node* GradParent = parent->_parent;//Record the parent node of this node in order to modify the root node
	parent->_parent = SubR;

	//Adjust root node
	if (parent == _root)
	{
		_root = SubR;
		SubR->_parent = GradParent;
	}
	else //If the node to be rotated is a subtree, modify the GradParent pointer
	{
		if (GradParent->_left == parent)//The rotation is the left subtree, connected to the left
		{
			GradParent->_left = SubR;
		}
		else
		{
			GradParent->_right = SubR;//conversely
		}
		SubR->_parent = GradParent;
	}
}

4. Judge whether a tree is a red black tree

bool CheckRBTree()
{
	if (_root == nullptr)
	{
		return true;
	}
	else if(_root->col == RED)
	{
		cout << "The root node is red" << endl;
		return false;
	}
	//First record the number of black nodes on the leftmost node, and take this number as the benchmark to check other paths
	int NumBack = 0;
	Node* LeftBack = _root;
	while (LeftBack != nullptr)
	{
		if (LeftBack->col == BLACK)
		{
			NumBack++;
		}
		LeftBack = LeftBack->_left;
	}
	int Num = 0;//Check the variable of the number of black nodes in other channels
	return _CheckRBTree(_root, NumBack, Num);
}

//Private:
bool _CheckRBTree(Node* root, const int NumBack, int Num)
{
	if (root == nullptr)//If it is empty, it means to traverse to the bottom of the red black tree and jump out of the loop condition
	{
		//Check the number of black nodes and NumBack on this road
		if (NumBack != Num)
		{
			cout << "The number of black nodes is different" << endl;
			return false;
		}
		else
		{
			return true;
		}
	}
	//Preorder traversal
	if (root->col == RED && root->_parent->col == RED)
	{
		cout << "Red node continuous" << endl;
		return false;
	}
	else if (root->col == BLACK)
	{
		Num++;
	}
	return _CheckRBTree(root->_left, NumBack, Num) && _CheckRBTree(root->_right, NumBack, Num);
}

5. The red black tree finds nodes by the key value key

You can traverse the red black tree once, which is a simple binary search tree. I won't repeat it

Node* Find(const Key& key)//Returns the node pointer through key value lookup
{
	Node* cur = _root;
	Node* ret = nullptr;
	while (cur != nullptr)
	{
		if (key > cur->_kv.first)
		{
			cur = cur->_right;
		}
		else if (key < cur->_kv.first)
		{
			cur = cur->_left;
		}
		else
		{
			ret = cur;
			break;
		}
	}
	return ret;
}

6. Printing of red and black trees

Medium order printing red black tree

void PrintInord()
{
	return _PrintInord(_root);
}

//Private:
void _PrintInord(Node* root)//Medium order printing
{
	if (root == nullptr)
		return;
	_PrintInord(root->_left);
	cout << root->_kv.first << "->" << root->_kv.second << endl;
	_PrintInord(root->_right);
}

7. Destructor of red black tree

Postorder ergodic destructor

~RBTree()
{
	_Destory(_root);//Postorder traversal
	_root = nullptr;
}

//Private:
void _Destory(Node* root)//Postorder traversal
{
	if (root == nullptr)
	{
		return;
	}
	_Destory(root->_left);
	_Destory(root->_right);
	delete root;
}

8. Insert, search and judge the complete code of red black tree

#pragma once

#include<iostream>
using namespace std;

enum Color
{
	RED = 0, BLACK,
};

template<class Key, class Value>
struct RBTreeNode
{
	RBTreeNode<Key, Value>* _left;
	RBTreeNode<Key, Value>* _right;
	RBTreeNode<Key, Value>* _parent;
	pair<Key, Value> _kv;
	Color col;
	RBTreeNode(const pair<Key, Value>& val)
		:_left(nullptr), _right(nullptr), _parent(nullptr), _kv(val), col(RED)//Default node color
	{}
};

template<class Key, class Value>
class RBTree
{
	typedef RBTreeNode<Key, Value> Node;
public:
	RBTree() :_root(nullptr) {}

	~RBTree()
	{
		_Destory(_root);//Postorder traversal
		_root = nullptr;
	}

	bool CheckRBTree()
	{
		if (_root == nullptr)
		{
			return true;
		}
		else if(_root->col == RED)
		{
			cout << "The root node is red" << endl;
			return false;
		}
		//Record the number of black nodes on the leftmost node first
		int NumBack = 0;
		Node* LeftBack = _root;
		while (LeftBack != nullptr)
		{
			if (LeftBack->col == BLACK)
			{
				NumBack++;
			}
			LeftBack = LeftBack->_left;
		}
		int Num = 0;//Record the number of black nodes at this time
		return _CheckRBTree(_root, NumBack, Num);
	}

	Node* Find(const Key& key)//Returns the node pointer through key value lookup
	{
		Node* cur = _root;
		Node* ret = nullptr;
		while (cur != nullptr)
		{
			if (key > cur->_kv.first)
			{
				cur = cur->_right;
			}
			else if (key < cur->_kv.first)
			{
				cur = cur->_left;
			}
			else
			{
				ret = cur;
				break;
			}
		}
		return ret;
	}

	//Print red black tree
	void PrintInord()
	{
		return _PrintInord(_root);
	}

	pair<Node*, bool>Insert(const pair<Key, Value>val)//Insertion of red black tree
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			_root->col = BLACK;
			return make_pair(_root, true);
		}
		//Binary search tree insertion
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur != nullptr)
		{
			if (cur->_kv.first < val.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > val.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else//Duplicate key value, failed to insert
			{
				return make_pair(cur, false);
			}
		}
		cur = new Node(val);
		cur->col = RED;
		if (parent->_kv.first > val.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;
		Node* End = cur;//Node that records the insertion location
		//Control path
		while (parent != nullptr && parent->col == RED)
		{
			Node* GradParent = parent->_parent;
			if (parent == GradParent->_left)//The key is to see the color of the Uncle node
			{
				Node* Uncle = GradParent->_right;
				//Case 1: Uncle exists and is red
				if (Uncle && Uncle->col == RED)
				{
					parent->col = Uncle->col = BLACK;
					GradParent->col = RED;
					cur = GradParent;
					parent = cur->_parent;
				}
				else//Uncle does not exist or is black
				{
					if (cur == parent->_left)//Right high, right rotation
					{
						_Single_Right(GradParent);
						GradParent->col = RED;
						parent->col = BLACK;
					}
					else//Broken line shape, left and right double rotation
					{
						_Single_Left(parent);
						_Single_Right(GradParent);
						cur->col = BLACK;
						parent->col = GradParent->col = RED;
					}
					break;//After rotation, the number of black nodes remains unchanged and directly jump out of the cycle
				}
			}
			else//parent=GradParent->_right
			{
				Node* Uncle = GradParent->_left;
				if (Uncle != nullptr && Uncle->col == RED)
				{
					Uncle->col = parent->col = BLACK;
					GradParent->col = RED;
					cur = GradParent;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)//Left high, left rotation
					{
						_Single_Left(GradParent);
						GradParent->col = RED;
						parent->col = BLACK;
					}
					else//Polyline, right left double rotation
					{
						_Single_Right(parent);
						_Single_Left(GradParent);
						cur->col = BLACK;
						GradParent->col = RED;
					}
					break;
				}
			}
		}
		_root->col = BLACK;//Change the color of the root to black to prevent the above process from changing the root node to red
		return make_pair(End, true);
	}
private:
	Node* _root;

	void _PrintInord(Node* root)
	{
		if (root == nullptr)
			return;
		_PrintInord(root->_left);
		cout << root->_kv.first << "->" << root->_kv.second << endl;
		_PrintInord(root->_right);
	}

	bool _CheckRBTree(Node* root, const int NumBack, int Num)
	{
		if (root == nullptr)
		{
			//Check the number of black nodes and NumBack on this road
			if (NumBack != Num)
			{
				cout << "The number of black nodes is different" << endl;
				return false;
			}
			else
			{
				return true;
			}
		}
		//Preorder traversal
		if (root->col == RED && root->_parent->col == RED)
		{
			cout << "Red node continuous" << endl;
			return false;
		}
		else if (root->col == BLACK)
		{
			Num++;
		}
		return _CheckRBTree(root->_left, NumBack, Num) && _CheckRBTree(root->_right, NumBack, Num);
	}

	void _Destory(Node* root)//Postorder traversal
	{
		if (root == nullptr)
		{
			return;
		}
		_Destory(root->_left);
		_Destory(root->_right);
		delete root;
	}
	void _Single_Right(Node* parent)//The right single rotation connects the correspondence according to the figure
	{
		//Record the node to be moved
		Node* SubL = parent->_left;
		Node* SubLR = SubL->_right;

		//connect
		parent->_left = SubLR;
		if (SubL->_right != nullptr)//Modify parent pointer
		{
			SubLR->_parent = parent;
		}
		//connect
		SubL->_right = parent;
		Node* GradParent = parent->_parent;//Record the parent node of this node in order to modify the root node
		parent->_parent = SubL;//Modify parent pointer
		//Adjust root node
		if (parent == _root)//The node to rotate is the root node
		{
			_root = SubL;
			SubL->_parent = GradParent;
		}
		else//If the node to be rotated is a subtree, modify the GradParent pointer
		{
			if (GradParent->_left == parent)
			{
				GradParent->_left = SubL;
			}
			else
			{
				GradParent->_right = SubL;
			}
			SubL->_parent = GradParent;
		}
	}

	void _Single_Left(Node* parent)//Left rotation
	{
		//Record the node to be moved
		Node* SubR = parent->_right;
		Node* SubRL = SubR->_left;

		//connect
		parent->_right = SubRL;
		if (SubRL != nullptr)
		{
			SubRL->_parent = parent;
		}
		SubR->_left = parent;
		Node* GradParent = parent->_parent;//Record the parent node of this node in order to modify the root node
		parent->_parent = SubR;

		//Adjust root node
		if (parent == _root)
		{
			_root = SubR;
			SubR->_parent = GradParent;
		}
		else //If the node to be rotated is a subtree, modify the GradParent pointer
		{
			if (GradParent->_left == parent)//The rotation is the left subtree, connected to the left
			{
				GradParent->_left = SubR;
			}
			else
			{
				GradParent->_right = SubR;//conversely
			}
			SubR->_parent = GradParent;
		}
	}
};

9. Test red and black trees

#include"RBTree.h" / / header file of red black tree
#include<stdlib.h>
#include<time.h>

void Test()//Test inserting and printing the red black tree to judge the red black tree
{
	int arr[] = { 3,2,5,1,7,11,6,15 };
	RBTree<int, int>t;
	for (const auto& e : arr)
	{
		t.Insert(make_pair(e, e));
	}
	t.PrintInord();
	if (t.CheckRBTree())
	{
		cout << "Is RedBlackTree" << endl;
	}
	else
	{
		cout << "Is Not RedBlackTree" << endl;
	}
}

//Random insertion of red black tree
void Test2()
{
	int n = 20;
	RBTree<int, int>t;
	srand((unsigned int)time(0));
	for (int i = 0; i < n; i++)
	{
		int tmp = rand();
		t.Insert(make_pair(tmp,tmp));
	}
	t.PrintInord();
	if (t.CheckRBTree())
	{
		cout << "Is RedBlackTree" << endl;
	}
	else
	{
		cout << "Is Not RedBlackTree" << endl;
	}
}

int main()
{
	Test();
	Test2();
	return 0;
}

The operation result is:

10. Code link

gitee red black tree code link

Posted by tekky on Tue, 23 Nov 2021 17:43:41 -0800