C++ 红黑树插入,红黑树迭代器实现

看懂本篇博客需有树旋转基础

红黑树是近似平衡的二叉搜索树,每个节点都有红黑中一色,他满足以下几点规则

一、红节点的左右子树必须为黑色(没有连续的红节点)

二、根节点必须为黑色

三、每条路径的黑色节点必须数量相同

红黑树的节点需要三叉链用于访问parents,插入时手首先按照搜索树的规则进行插入,在创好新节点并连接后,默认新节点的颜色为红,如果parents的颜色为红,需要进行调整,因为破坏了规则一,一定不能将新节点颜色调为黑,因为破坏了规则三,这样每条路径都要进行调整,而破坏规则一只需调整一条路径,调整时会有三种情况

一、uncle存在且uncle为红(uncle指parents的parents另外一颗子树)

此时需要注意的是,parents为红,那么parents的parents(以下用grandfather代替)一定存在且为黑,因为如果parents为红,那么代表他不是根,而如果grandfather为红,早已被调整过,所以grandfather一定为黑,下面是一副具象图:

此时为了既能保证黑节点总数不变,又能保证没有连续的红节点,我们选择将grandfater变红,parents和uncle变黑,变化后如图

这样做既可以使得grandfather的所有路径黑节点数量不变,也可使得没有连续的树中没有连续的红节点,这样做有一个隐患是grandfather->parents可能为红,所以需要继续向上更新,直到没有连续的红节点或parents为空为止。

二、uncle不存在或存在为黑(旋转一次)

uncle不存在或存在为黑处理方法相同,以uncle存在为黑举例如图

此时需要将grandfather进行一次右旋转,旋转后如图:

再将grandfather变为红,parents变为黑,黑节点数量依旧不变,同样没有连续的红节点,变色后如图

三、uncle不存在或uncle为黑(需双旋)

此时需要将parents先进行一次旋转,旋转后如图

此时情况就和第二种情况一样了,只是new和parents的位置不同,只需将new和parents的指针进行调换即可完美将第三种情况变为第二种

bool insert(const T& data)
		{
			if (_root == nullptr)
			{
				_root = new TreeNode(data);
				_root->color = BLACK;
				return true;
			}
			KOfT koft;
			TreeNode* cur = _root;
			TreeNode* parents = nullptr;
			while (cur)
			{
				if (koft(cur->_data) < koft(data))
				{
					parents = cur;
					cur = cur->_right;
				}
				else if (koft(cur->_data) > koft(data))
				{
					parents = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			cur = new TreeNode(data);
			if (koft(parents->_data) < koft(cur->_data))
			{
				parents->_right = cur;
				cur->_parents = parents;
			}
			else
			{
				parents->_left = cur;
				cur->_parents = parents;
			}
			cur->color = RED;
			while (parents && parents->color == RED)
			{
				TreeNode* grandfather = parents->_parents;
				if (grandfather->_left == parents)
				{
					TreeNode* uncle = grandfather->_right;
					//uncle 存在且为红
					if (uncle && uncle->color == RED)
					{
						grandfather->color = RED;
						parents->color = BLACK;
						uncle->color = BLACK;
						//继续向上更新
						cur = grandfather;
						parents = cur->_parents;
					}
					//uncle 不存在 或 uncle存在且为黑
					else
					{
						//将双旋变为单旋
						if (cur == parents->_right)
						{
							Left_Rotate(parents);
							swap(parents, cur);
						}
						Right_Rotate(grandfather);
						grandfather->color = RED;
						parents->color = BLACK;
						break;
					}
				}
				else if(grandfather->_right == parents)
				{
					TreeNode* uncle = grandfather->_left;
					//uncle 存在且为红
					if (uncle && uncle->color == RED)
					{
						grandfather->color = RED;
						parents->color = BLACK;
						uncle->color = BLACK;
						//继续向上更新
						cur = grandfather;
						parents = cur->_parents;
					}
					else
					{
						//将双旋变为单旋
						if (cur == parents->_left)
						{
							Right_Rotate(parents);
							std::swap(parents, cur);
						}
						Left_Rotate(grandfather);
						grandfather->color = RED;
						parents->color = BLACK;
						break;
					}
				}
			}
			_root->color = BLACK;
			return true;

		}
		void Left_Rotate(TreeNode* parents)
		{
			TreeNode* subR = parents->_right;
			TreeNode* subRL = subR->_left;
			TreeNode* ppnode = parents->_parents;
			subR->_left = parents;
			parents->_right = subRL;
			//旋转时如果subRL为空,则不需要parents
			if (subRL)
				subRL->_parents = parents;

			parents->_parents = subR;
			//parents->parents为空,说明parents为root
			if (_root == parents)
			{
				_root = subR;
				subR->_parents = nullptr;

			}
			else
			{
				if (ppnode->_left == parents)
					ppnode->_left = subR;
				else
					ppnode->_right = subR;
				subR->_parents = ppnode;
			}

			//parents->_bf = 0;
			//if (subR)
			//{
			//	subR->_bf = 0;
			//	subR->_parents = ppnode;
			//}

		}

		void Right_Rotate(TreeNode* parents)
		{
			TreeNode* subL = parents->_left;
			TreeNode* ppnode = parents->_parents;
			TreeNode* subLR = subL->_right;
			subL->_right = parents;
			parents->_left = subLR;
			if (subLR)
				subLR->_parents = parents;
			parents->_parents = subL;

			if (_root == parents)
			{
				_root = subL;
				subL->_parents = nullptr;
			}
			else
			{
				if (ppnode->_left == parents)
					ppnode->_left = subL;
				else
					ppnode->_right = subL;

				subL->_parents = ppnode;
			}
			/*	parents->_bf = 0;
				if (subL)
					subL->_bf = 0;*/
		}

红黑树的迭代器实现

enum _RB_Tree_color
	{
		RED,
		BLACK
	};
	template<typename T>
	struct __RB_Tree_Node
	{
		__RB_Tree_Node<T>* _left;
		__RB_Tree_Node<T>* _right;
		__RB_Tree_Node<T>* _parents;
		T _data;
		_RB_Tree_color color;
		__RB_Tree_Node(const T& kv) :_left(nullptr), _right(nullptr), _parents(nullptr), _data(kv), color(RED) {}
	};
	template<typename T>
	class _RB_Tree_iterator
	{
		typedef __RB_Tree_Node<T> Node;
		typedef _RB_Tree_iterator<T> self;
		Node* _node;
	public:
		_RB_Tree_iterator(Node* node) :_node(node) {}
		T& operator*()
		{
			return this->_node->_data;
		}
		T* operator->()
		{
			return &(_node->_data);
		}
		bool operator!=(const self& node)
		{
			return this->_node != node._node;
		}
		bool operator==(const self& node)
		{
			return this->_node == node._node;
		}

		//
		self& operator++() 
		{
			
			if (_node->_right)
			{
				Node* subleft = _node->_right;
				while (subleft->_left)
				{
					subleft = subleft->_left;
				}
				_node = subleft;
			}
			else
			{
				Node* cur = _node;
				Node* parents = _node->_parents;
				while (parents && parents->_right == cur)
				{
					cur = parents;
					parents = parents->_parents;
				}
				_node = parents;
			}

			return *this;
			
		}
		void operator--() 
		{
			//左子树不为空
			if (_node->_left)
			{
				Node* subleft = _node->_left;
				_node = subleft;
			}
			//左子树为空
			else
			{
				//如果我是父亲的右树,那么减到父亲,
				//如果我是父亲的左树,代表左树已经访问完,我成为我的父亲,并继续判断
				Node* cur = _node;
				Node* parents = _node->_parents;
				while (parents && parents->_left == cur)
				{
					cur = parents;
					parents = parents->_parents;
				}
				_node = parents;
			}
		}
	};

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值