C++ red-black tree (2/4)

Table of contents

review

Condition

partial solution

The idea of ​​global solution

the code

Drill down to the leaf node and prepare to insert new data

ready to insert data

 insert

The situation in this chapter appears

Grandparent node assignment

Uncle node assignment

Discoloration - making balance adjustments

total code

Precautions

Summarize


review

previous chapter

C++ red-black tree (1/4 )

next chapter

Red-black tree c++ (3/4 icon-default.png?t=N4P3)

In the previous chapter, I learned the characteristics and basic definitions of red-black trees

In this chapter, we will learn the first type of situation when inserting - the father node is red and the uncle node is also red (of course the grandfather node must be black)

Condition

When my red node is plugged in, it is necessary to adjust the balance of the entire tree because of feature 2 - red nodes cannot appear adjacent to each other

We can keep the color of the new node unchanged, then change the color of the parent node and uncle node to black, and then change the color of the grandpa node to red

partial solution

so as to achieve the balance of the tree

It should be noted that if the grandfather is the root node, the color of the grandfather should also be adjusted to black

The idea of ​​global solution

 But unfortunately the depth of a tree can not only be 3, it can be deeper - 4, 5, 6, 7... or more

as shown in the picture

 To insert a new red node in this red-black tree

Then adjust the method before installing and you will find a problem that the father node of the grandparent node you inserted (that is, your great-grandfather node) is red and the uncle node of your grandfather node is black. This method is not in this category.

as shown in the picture

But don't panic, the next two sections will talk about other situations and how to deal with them (you should pay attention to the blue circle part as a whole in the follow-up solution [because it has been balanced])

 Congratulations now, you have learned the solution to the first situation encountered when inserting a red-black tree

The next step is to explain the code

the code

First I want to create a RBTree (red-black tree) class

There are lchild (left child) rchild (right child) parent (parent node) data (self data) color (color)

These categories are all empty (nullptr) except the color is RED (red), as mentioned in the previous chapter

Drill down to the leaf node and prepare to insert new data

		while (point->data==nullptr)
		{
			if (e == point->data)
			{
				printf("该数据已经存在");
				return;
			}
			parent = point;
			if (e >= point)
				point = point->rchild;
			else
				point = point->lchild;

		}

Like other trees, the big one is on the right, and the small one is on the left. Repeated data cannot be inserted

Save its parent node each time

Always find the deepest layer in each traversal

ready to insert data

The next step is to initialize the data

All are empty except color

		point = new RBNode<T>;
		point->data = e;
		point->lchild = nullptr;
		point->rchild = nullptr;
		point->parent = nullptr;
		point->colour = RED;

It should be noted that if it is the root node, the color should still be changed to black

		if (parent == nullptr)
		{
			//插入的是根节点
			point->colour = BLACK;
			tnode = point;
		}

 insert

Insert, the next step is to link his parent node

Determine whether to insert the left child or the right child according to the size of the data

And when the parent node is black, insert directly without judgment and complete the return

		if (e > parent->data)
			parent->rchild = point;
		else
			parent->lchild = point;

		point->parent = parent;
		if (parent->colour == BLACK)
		{
			count << e << "插入完成" << endl;
			return;
		}

The situation in this chapter appears

Then first create its uncle node and grandparent node and start assigning

		RBNode<T>* uncle = nullptr;
		RBNode<T>* grandpa = nullptr;

Grandparent node assignment

The grandfather node is simply the father of the father

grandpa = point->parent->parent;

Uncle node assignment

Uncle nodes are a little more troublesome

It's better to create a function to get its uncle node

uncle = (parent->parent != nullptr) ? (getuncle(parent) :nullptr);

Then the getuncle() function definition is

	RBNode<T>* getuncle(RBNode<T>* p)
	{
		if (p->parent->lchild == p)
			return p->parent->rchild;
		else
			return p->parent->rchild;
	}

It should be noted that the function of obtaining uncle nodes is best placed in private (ensure that the function is private)

Discoloration - making balance adjustments

finally change color

After obtaining the uncle and grandfather nodes, the next work becomes simple

Just follow the picture above to change the color according to the gourd painting

		while (true)
		{
			uncle = (parent->parent != nullptr) ? (getuncle(parent) :nullptr);
			grandpa = point->parent->parent;
			if grandpa == nullptr
				break;
			if (uncle != nullptr && uncle->colour == RED)
			{
				parent->colour = BLACK;
				uncle->colour = BLACK;
				grandpa->colour = RED;
				if (grandpa == root)
					grandpa->colour = BLACK;

			}
		}
		//无论如何根节点颜色为黑色
		root->colour = BLACK;

total code

Finally attached the adjusted source code

#include <iostream>
using namespace std;
//定义一个颜色
enum Colour
{
	RED,
	BLACK,
};
//定义一个模版T
template<typename T>
//一个节点的结构体
struct RBNode
{
	RBNode* lchild,
		* rchild,
		* parent;
	T	data;
	//初始化为RED也可以后面定义一个初始化函数
	Colour colour=RED;
};
//再定义一个模版T(template只能联系到下面一句语句)
template <typename T>
class RBTree//树
{
public:
	RBTree()
	{
		root = nullptr;
	}
	~RBTree()
	{
		ReleaseNode(root);
	}
	//插入元素
	void InsNode(const T& e)
	{
		InsNode(root, e);
	}
	void InsNode(RBNode<T>*& tnode, const T& e)
	{
		RBNode<T>* point = tnode;
		RBNode<T>* parent = nullptr;
		//深入到叶子节点准备插入新数据
		while (point->data==nullptr)
		{
			if (e == point->data)
			{
				printf("该数据已经存在");
				return;
			}
			parent = point;
			if (e >= point)
				point = point->rchild;
			else
				point = point->lchild;

		}
		//准备插入数据
		point = new RBNode<T>;
		point->data = e;
		point->lchild = nullptr;
		point->rchild = nullptr;
		point->parent = nullptr;
		point->colour = RED;
		
		if (parent == nullptr)
		{
			//插入的是根节点
			point->colour = BLACK;
			tnode = point;
		}
		//不是根节点
		if (e > parent->data)
			parent->rchild = point;
		else
			parent->lchild = point;

		point->parent = parent;
		if (parent->colour == BLACK)
		{
			count << e << "插入完成" << endl;
			return;
		}
		//接下来就是插入地方的父亲节点是红色的,且深度至少为3(因为第二层父亲节点颜色一定为黑色
		RBNode<T>* uncle = nullptr;
		RBNode<T>* grandpa = nullptr;
		while (true)
		{
			uncle = (parent->parent != nullptr) ? (getuncle(parent) :nullptr);
			grandpa = point->parent->parent;
			if grandpa == nullptr
				break;
			if (uncle != nullptr && uncle->colour == RED)
			{
				parent->colour = BLACK;
				uncle->colour = BLACK;
				grandpa->colour = RED;
				if (grandpa == root)
					grandpa->colour = BLACK;

			}
			point = grandpa;
			parent = grandpa->parent;
			if (parent->colour == BLACK)
				break;
			continue;
		}
		//无论如何根节点颜色为黑色
		root->colour = BLACK;
	}
private:
	//删除节点,释放内存
	void ReleaseNode(RBNode<T>* pnode)
	{
		if (pnode != nullptr)
		{
			ReleaseNode(pnode->lchild);
			ReleaseNode(pnode->rchild);
		}
		delete pnode;
	}
	RBNode<T>* getuncle(RBNode<T>* p)
	{
		if (p->parent->lchild == p)
			return p->parent->rchild;
		else
			return p->parent->rchild;
	}
private:
	//根节点
	RBNode <T>* root;
};

int main()
{
	//还没有到定义的时候
	printf("OK");
	return 0;
}

Precautions

It should be noted that the code cannot be run yet after being typed , and the reason is the same as that mentioned above—there are still some other situations that we cannot solve, and we need to continue to study the next two types of situations.

Summarize

Congratulations, you have initially learned the first balance adjustment of the red-black tree. Even if there are still some situations that you don't know, please don't worry. The following articles will teach you how to do it.

Guess you like

Origin blog.csdn.net/mumuemhaha/article/details/131159253