红黑树--讲解以及详细实现过程

目录

  • 红黑树理解
    • 红黑树概念
    • 红黑树性质
  • 红黑树实现
    • 红黑树图解
    • 基础结构实现
    • 插入实现
    • 中序遍历
    • 检查是否为红黑树
  • 完整代码

红黑树理解

红黑树概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
没有AVL树那么严格的要求必须左右子树高度差小于1。
红黑树--讲解以及详细实现过程_第1张图片

红黑树性质

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

红黑树实现

红黑树图解

为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为根节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点。红黑树--讲解以及详细实现过程_第2张图片

基础结构实现

enum COLOR
{
	BLACK,
	RED
};

template <class K, class V>
struct RBNode
{
	RBNode<K, V>* _parent;
	RBNode<K, V>* _left;
	RBNode<K, V>* _right;

	//key - value
	pair<K, V> _kv;
	COLOR _color;

	RBNode(const pair<K, V>& kv = pair<K, V>())
		:_parent(nullptr)
		, _left(nullptr)
		, _right(nullptr)
		, _kv(kv)
		, _color(RED)
	{}
};

template <class K, class V>
class RBTree
{
public:
	typedef RBNode<K, V> Node;

	RBTree()
		:_header(new Node)
	{
		//创建空树
		_header->_left = _header->_right = _header;
	}


private:
	Node* _header;
};

插入实现

  1. 首先判断是否是空树:如果是空树,则创建根节点,将头结点和根节点进行连接;
  2. 如果不是空树,则根据待插入值的大小,遍历搜索到待插入的位置,创建好待插入的节点,将插入节点和父节点连接;
  3. 节点插入后,由于新插入节点都为红色,如果和父节点颜色重复则进行更新操作。
	bool insert(const pair<K, V>& kv)
	{
		//1.搜索树的插入
		// 空树:_header->parent:nullptr
		if (_header->_parent = nullptr)
		{
			//创建根节点
			Node* root = new Node(kv);

			_header->_parent = root;
			root->_parent = _header;
			_header->_left = _header->_right = root;

			//根节点是黑色
			root->_color = BLACK;

			return true;
		}

		//从根节点开始搜索
		Node* cur = _header->_parent;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			//和key值进行比较
			//kv:pair, key:pair.first
			if (cur->_kv.first == kv.first)
			{
				//key值不允许重复
				return false;
			}
			else if (cur->_kv.first > kv.first)
			{
				cur = cur->_left;
			}
			else
			{
				cur = cur->_right;
			}
		}

		//创建待插入的节点
		cur = new Node(kv);
		if (parent->_kv.first > kv.first)
			parent->_left = cur;
		else
			parent->_right = cur;
		cur->_parent = parent;

		//2.修改颜色或者调整结构
		//判断是否有红色连续的节点
		while (cur != _header->_parent && cur->_parent->_color == RED)
		{
			parent = cur->_parent;
			Node* gfather = parent->_parent;

			if (gfather->_left == parent)
			{
				Node* uncle = gfather->_right;
				//1.uncle存在,并且是红色的
				if (uncle && uncle->_color == RED)
				{
					parent->_color = uncle->_color = BLACK;
					gfather->_color = RED;
					//继续更新
					cur = gfather;
				}
				else
				{
					//判断是否为双旋的场景
					if (cur == parent->_right)
					{
						//左旋
						RotateL(parent);
						//交换cur,parent指向,退化为右旋的场景
						swap(cur, parent);
					}
					//右旋
					RotateR(gfather);
					parent->_color = BLACK;
					gfather->_color = RED;
					break;
				}

			}
			else
			{
				//gfather->_right == parent
				Node* uncle = gfather->_left;
				//1.uncle存在,并且是红色的
				if (uncle && uncle->_color == RED)
				{
					parent->_color = uncle->_color = BLACK;
					gfather->_color = RED;
					//继续更新
					cur = gfather;
				}
				else
				{
					//判断是否为双旋的场景
					if (cur == parent->_left)
					{
						//右旋
						RotateR(parent);
						//交换cur,parent指向,退化为右旋的场景
						swap(cur, parent);
					}
					//左旋
					RotateL(gfather);
					parent->_color = BLACK;
					gfather->_color = RED;
					break;
				}
			}
		}
		//根节点的颜色改成黑色
		_header->_parent->_color = BLACK;
		//更新header的左右指向
		_header->_left = leftMost();
		_header->_right = rightMost(); 
	}
	
	//右旋操作结构如下:
	//          parent(-2)
	//subL(-1)
	//     subLR(0)
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
	
		subL->_right = parent;
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;
		//更新cur和父亲的父亲之间的连接
		//判断是否为根节点
		if (parent == _root)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			Node* pparent = parent->_parent;
			if (pparent->_left == parent)
				pparent->_left = subL;
			else
				pparent->_right = subL;
			subL->_parent = pparent;
		}
			
		//更新父亲的父亲为cur
		parent->_parent = subL;
		//更新平衡因子
		subL->_bf = parent->_bf = 0;
	}
	
	//左旋操作结构如下:
	//parent(2)
	//          subR(1)
	//  subRL(0)
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
	
		subR->_left = parent;
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;
		//更新cur和父亲的父亲之间的连接
		//判断是否为根节点
		if (parent == _root)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			Node* pparent = parent->_parent;
			if (pparent->_left == parent)
				pparent->_left = subR;
			else
				pparent->_right = subR;
			subR->_parent = pparent;
		}
	
		//更新父亲的父亲为cur
		parent->_parent = subR;
		//更新平衡因子
		subR->_bf = parent->_bf = 0;
	}

	Node* leftMost()
	{
		Node* cur = _header->_parent;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return cur;
	}

	Node* rightMost()
	{
		Node* cur = _header->_parent;
		while (cur && cur->_right)
		{
			cur = cur->_right;
		}
		return cur;
	}

中序遍历

	void inorder()
	{
		_inorder(_header->_parent);
		cout << endl;
	}

	void _inorder(Node* root)
	{
		if (root)
		{
			_inorder(root->_left);
			cout << root->_kv.first << " " << root->_kv.second;
			_inorder(root->_right);
		}
	}

检查是否为红黑树

	//红黑树:
	//1.根:黑色
	//2.每条路径黑色个数相同
	//3.红色不能连续
	bool isBalance()
	{
		if (_header->_parent == nullptr)
			return true;
		Node* root = _header->_parent;
		
		if (root->_color == RED)
			return false;
		//统计一条路径上的黑色节点个数
		int bCount = 0;
		Node* cur = root;
		while (cur)
		{
			if (cur->_color == BLACK)
				++bCount;
			cur = cur->_left;
		}

		//遍历每一条路径
		int curBCount = 0;
		return _isBalance(root, bCount, curBCount);
	}

	bool _isBalance(Node* root, int& bCount, int curBCount)
	{
		//当root为空时,一条路径遍历结束
		if (root == nullptr)
		{
			//判断黑色节点个数是否相同
			if (curBCount != bCount)
				return false;
			else
				return true;
		}

		//判断节点是否为黑色
		if (root->_color == BLACK)
			++curBCount;

		//判断是否由红色连续的节点
		if (root->_parent && root->_color == RED && root->_parent->_color == RED)
		{
			cout << "data:" << root->_kv.first << endl;
			return false;
		}

		return _isBalance(root->_left) && _isBalance(root->_right);
	}

完整代码

enum COLOR
{
	BLACK,
	RED
};

template <class K, class V>
struct RBNode
{
	RBNode<K, V>* _parent;
	RBNode<K, V>* _left;
	RBNode<K, V>* _right;

	//key - value
	pair<K, V> _kv;
	COLOR _color;

	RBNode(const pair<K, V>& kv = pair<K, V>())
		:_parent(nullptr)
		, _left(nullptr)
		, _right(nullptr)
		, _kv(kv)
		, _color(RED)
	{}
};

template <class K, class V>
class RBTree
{
public:
	typedef RBNode<K, V> Node;

	RBTree()
		:_header(new Node)
	{
		//创建空树
		_header->_left = _header->_right = _header;
	}

	bool insert(const pair<K, V>& kv)
	{
		//1.搜索树的插入
		// 空树:_header->parent:nullptr
		if (_header->_parent = nullptr)
		{
			//创建根节点
			Node* root = new Node(kv);

			_header->_parent = root;
			root->_parent = _header;
			_header->_left = _header->_right = root;

			//根节点是黑色
			root->_color = BLACK;

			return true;
		}

		//从根节点开始搜索
		Node* cur = _header->_parent;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			//和key值进行比较
			//kv:pair, key:pair.first
			if (cur->_kv.first == kv.first)
			{
				//key值不允许重复
				return false;
			}
			else if (cur->_kv.first > kv.first)
			{
				cur = cur->_left;
			}
			else
			{
				cur = cur->_right;
			}
		}

		//创建待插入的节点
		cur = new Node(kv);
		if (parent->_kv.first > kv.first)
			parent->_left = cur;
		else
			parent->_right = cur;
		cur->_parent = parent;

		//2.修改颜色或者调整结构
		//判断是否有红色连续的节点
		while (cur != _header->_parent && cur->_parent->_color == RED)
		{
			parent = cur->_parent;
			Node* gfather = parent->_parent;

			if (gfather->_left == parent)
			{
				Node* uncle = gfather->_right;
				//1.uncle存在,并且是红色的
				if (uncle && uncle->_color == RED)
				{
					parent->_color = uncle->_color = BLACK;
					gfather->_color = RED;
					//继续更新
					cur = gfather;
				}
				else
				{
					//判断是否为双旋的场景
					if (cur == parent->_right)
					{
						//左旋
						RotateL(parent);
						//交换cur,parent指向,退化为右旋的场景
						swap(cur, parent);
					}
					//右旋
					RotateR(gfather);
					parent->_color = BLACK;
					gfather->_color = RED;
					break;
				}

			}
			else
			{
				//gfather->_right == parent
				Node* uncle = gfather->_left;
				//1.uncle存在,并且是红色的
				if (uncle && uncle->_color == RED)
				{
					parent->_color = uncle->_color = BLACK;
					gfather->_color = RED;
					//继续更新
					cur = gfather;
				}
				else
				{
					//判断是否为双旋的场景
					if (cur == parent->_left)
					{
						//右旋
						RotateR(parent);
						//交换cur,parent指向,退化为右旋的场景
						swap(cur, parent);
					}
					//左旋
					RotateL(gfather);
					parent->_color = BLACK;
					gfather->_color = RED;
					break;
				}
			}
		}
		//根节点的颜色改成黑色
		_header->_parent->_color = BLACK;
		//更新header的左右指向
		_header->_left = leftMost();
		_header->_right = rightMost(); 
	}
	
	//右旋操作结构如下:
	//          parent(-2)
	//subL(-1)
	//     subLR(0)
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
	
		subL->_right = parent;
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;
		//更新cur和父亲的父亲之间的连接
		//判断是否为根节点
		if (parent == _root)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			Node* pparent = parent->_parent;
			if (pparent->_left == parent)
				pparent->_left = subL;
			else
				pparent->_right = subL;
			subL->_parent = pparent;
		}
			
		//更新父亲的父亲为cur
		parent->_parent = subL;
		//更新平衡因子
		subL->_bf = parent->_bf = 0;
	}
	
	//左旋操作结构如下:
	//parent(2)
	//          subR(1)
	//  subRL(0)
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
	
		subR->_left = parent;
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;
		//更新cur和父亲的父亲之间的连接
		//判断是否为根节点
		if (parent == _root)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			Node* pparent = parent->_parent;
			if (pparent->_left == parent)
				pparent->_left = subR;
			else
				pparent->_right = subR;
			subR->_parent = pparent;
		}
	
		//更新父亲的父亲为cur
		parent->_parent = subR;
		//更新平衡因子
		subR->_bf = parent->_bf = 0;
	}

	Node* leftMost()
	{
		Node* cur = _header->_parent;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return cur;
	}

	Node* rightMost()
	{
		Node* cur = _header->_parent;
		while (cur && cur->_right)
		{
			cur = cur->_right;
		}
		return cur;
	}

	void inorder()
	{
		_inorder(_header->_parent);
		cout << endl;
	}

	void _inorder(Node* root)
	{
		if (root)
		{
			_inorder(root->_left);
			cout << root->_kv.first << " " << root->_kv.second;
			_inorder(root->_right);
		}
	}

	//红黑树:
	//1.根:黑色
	//2.每条路径黑色个数相同
	//3.红色不能连续
	bool isBalance()
	{
		if (_header->_parent == nullptr)
			return true;
		Node* root = _header->_parent;
		
		if (root->_color == RED)
			return false;
		//统计一条路径上的黑色节点个数
		int bCount = 0;
		Node* cur = root;
		while (cur)
		{
			if (cur->_color == BLACK)
				++bCount;
			cur = cur->_left;
		}

		//遍历每一条路径
		int curBCount = 0;
		return _isBalance(root, bCount, curBCount);
	}

	bool _isBalance(Node* root, int& bCount, int curBCount)
	{
		//当root为空时,一条路径遍历结束
		if (root == nullptr)
		{
			//判断黑色节点个数是否相同
			if (curBCount != bCount)
				return false;
			else
				return true;
		}

		//判断节点是否为黑色
		if (root->_color == BLACK)
			++curBCount;

		//判断是否由红色连续的节点
		if (root->_parent && root->_color == RED && root->_parent->_color == RED)
		{
			cout << "data:" << root->_kv.first << endl;
			return false;
		}

		return _isBalance(root->_left) && _isBalance(root->_right);
	}

private:
	Node* _header;
};

void test()
{
	RBTree<int, int> rbt;
	rbt.insert(make_pair(10, 10));
	rbt.insert(make_pair(15, 15));
	rbt.insert(make_pair(5, 5));
	rbt.insert(make_pair(2, 2));
}

int main()
{
	test();
	return 0;
}

你可能感兴趣的:(c++,红黑树)