用红黑树封装map&set【C++】

这篇具有很好参考价值的文章主要介绍了用红黑树封装map&set【C++】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

一,定义

二,完善set&map比较 

三,迭代器实现

operator++

operator--

operator[]

四,发现问题

解决

修改一: set封装层面

修改二:正向迭代器修改

下期预告: 哈希!!

结语


用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

前言

我们在上篇文章红黑树——插入底层实现【C++】面试重灾区!!-CSDN博客

在上篇文章我们实现了红黑树的插入实现,同时也知道map与set底层一般是红黑树实现,那么本篇问文章我们来尝试封装map&set。

注意:建议完整学完本节,代码是逐步完善的。

首先我们从STL源码中寻找线索

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

还是比较明显的,红黑树的底层更加适合Map,但STL想让set复用map的红黑树,所以让set做出了一些 “ 妥协 ”:

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

 参数传递方向:

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

一,定义

根据STL源代码的提示,我们能初步形成框架

namespace my_map
{
	template <class K, class V>
	class map
	{
		RB_Tree<K, pair<const K, V>> _t;

	public:
		bool insert(const pair<const K, V>& p)
		{
			return _t.insert(p);
		}

	};
}
namespace my_set
{
	template <class K>
	class set
	{
		RB_Tree<K, K> _t;

	public:
		bool insert(const K& p)
		{
			return _t.insert(p);
		}
	};
}

同时我们要对红黑树的定义进行修改:

template <class T>
struct RBT_Data
{
	T _data;
	RBT_Data<T>* left = nullptr;
	RBT_Data<T>* right = nullptr;
	RBT_Data<T>* parent = nullptr;
	color _col;  // 颜色

	RBT_Data(const T& p)
		:_data(p)
		,_col(RED) //与其修改黑色路径数量,不如违反红子孩子都为黑的原则来的轻松。
	{}
};

template <class K, class V>
class RB_Tree 
{
	typedef RBT_Data<V> RBT_Data;
	RBT_Data* root = nullptr;
....

二,完善set&map比较 

从结果上来看,set&map 竟然运行成功。这是为什么呢??  没有了固定的  cur->_kv.first map应该是无法访问pair里面的数据,那又是如何进行比较大小,形成排序的呢??

答案在pair里面

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

pair类里面重载了比较大小的符号,但都是first,second之间进行比较,我们的排序需要依照Key值进行判断。那如何解决??

通过构建仿函数

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linuxset与map形成各自的仿函数,这样set就能适配map。

三,迭代器实现

基础框架,基本符号" * ", " -> " , " != "的重载。

这里以set封装为例 

// 在set封装上的处理
namespace my_set
{
	template <class K>
	class set
	{
		typedef  RB_Tree_Iterator<K, K&, K*> iterator;
        typedef  RB_Tree_Iterator<K, const K&, const K*> const_iterator;
		struct KeyofT
		{
			const K& operator()(const K& data)
			{
				return data;
			}
		};

		RB_Tree<K, K, KeyofT> _t;
	public:
		bool insert(const K& p)
		{
			return _t.insert(p);
		}

		iterator begin()
		{
			return _t.begin();
		}

		iterator end()
		{
			return _t.end();
		}
	};
}

// 迭代器类处理
template <class T, class Ref, class Ptr>
class RB_Tree_Iterator
{
	typedef RBT_Data<T>  RBT_Data;
	typedef RB_Tree_Iterator<T, Ref, Ptr> Seft;

	RBT_Data* it_root ;

public:
	RB_Tree_Iterator( RBT_Data* _node = nullptr)
	    :it_root(_node)
	{}

	Ref operator*()
	{
		return it_root->_data;
	}

	Ptr operator->()
	{
		return &it_root->_data;
	}
};

// 在RB_Tree上的处理
template <class K, class V, class KeyofT>
class RB_Tree
{
	typedef RB_Tree_Iterator<V, V&, V*> iterator;
	typedef RB_Tree_Iterator<V, const V&, const V*> const_iterator;
.......

	iterator begin()
	{
		RBT_Data* node = root;
		while (node && node->left)
		{
			node = node->left;	
		}
		return iterator(node);
	}
	
	// end跟以往的不同,end表示最后一个数据的下一个数据,也就是nullptr,实际距离是根的父节点。
	iterator end() 
	{
		return iterator(nullptr);
	}

	const const_iterator begin() const
	{
		RBT_Data* node = root;
		while (node && node->left)
		{
			node = node->left;
		}
		return const_iterator(node);
	}

	const const_iterator end() const
	{
		return const_iterator(nullptr);
	}
....

  

但我们还差一个极其重要的字符 “ ++ ”的实现,由于这个比较特殊我们分开单独讲。

operator++

思想:中序遍历来访问各个数据。比较难的是如何利用红黑树的三叉链,来实现中序遍历。

   Seft& operator++()
	{
		if (it_root && it_root->right)
		{
			// 假设右孩子存在
			RBT_Data* subleft = it_root->right;
			while (subleft->left)
			{
				subleft = subleft->left;
			}
			it_root = subleft;
		}
		else //如果没有右孩子,就向上回溯
		{
			RBT_Data* cur = it_root;
			RBT_Data* par = it_root->parent;
			while (par && par->right == cur)
			{
				cur = par;
				par = par->parent;
			}
				it_root = par;
		}
		return *this;
	}

operator--

 " -- "与 “ ++ ”两符号重载,本质上没多大改变,就是从原来的 左 ->  根  -> 右   =>    右 -> 根 -> 左

Seft& operator--()
	{
		if (it_root && it_root->right)
		{
			// 假设左侧存在
			RBT_Data* subright = it_root->left;
			while (subright->right)
			{
				subright = subright->right;
			}
			it_root = subright;
		}
		else //如果左侧没有
		{
			RBT_Data* cur = it_root;
			RBT_Data* par = it_root->parent;
			while (par && par->left == cur)
			{
				cur = par;
				par = par->parent;
			}
			it_root = par;
		}
		return *this;
	}

operator[]

这是STL对operator[] 的使用, 这需要我们对insert()进行返回值的修改,我们需要返回一个pair类型,里面放着pair<iterator, bool>,方便我们修改value的值。

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

这里我给一个案例进行修改:insert返回value的引用

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

后面的返回值处理成pair返回类似。

然后就是map与set的封装层,我们要如何使用呢??代码如下:

//  set     
    K& operator[](const K& key)
    {
	pair<iterator, bool> ret = _t.insert(key);
	if (ret.second)
		return ret.first.it_root->_data;
	cout << "插入失败" << endl;
		}
// map
V& operator[](const K& key)
{
   pair<iterator, bool> ret = _t.insert(make_pair(key, V()));
   if (ret.second)
     return ret.first->second;
   cout << "插入失败" << endl;
}

四,发现问题

 我们运行这段测试代码,我们会发现,set里面的数据被修改,但这是不被允许的。

    my_set::set<int> st;
	st[1];
	st[2];
	st[3];
	st[4];

	for (auto& e : st)
	{
		cout << e << " ";
	}

	for (auto& e : st)
	{
		e = 1;
		cout << e << " ";
	}

原因分析:下图是普通对象set获取迭代器参数的传递

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

解决

对于set的普通对象,如果是上面的代码,我们无法在适配map的前提下,保证set的value不可修改。解决思路:我们让set的普通迭代器类型底层是const迭代器。但其中的细节还是非常巧妙,我们通过下图讲解特殊之初吧。

修改一: set封装层面

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

修改二:正向迭代器修改

用红黑树封装map&set【C++】,C++——从入门到入土,安排!,c++,java,开发语言,算法,linux

好啦,map与set封装精华就到这里了。

map_set.h

namespace my_set
{
	template <class K>
	class set
	{
		struct KeyofT
		{
			const K& operator()(const K& data)
			{
				return data;
			}
		};
		typedef  typename RB_Tree<K, K, KeyofT>::const_iterator iterator;  //直接用,const对象的迭代器充当普通迭代器
		typedef  typename RB_Tree<K, K, KeyofT>::const_iterator const_iterator;

		RB_Tree<K, K, KeyofT> _t;
	public:
		pair<iterator, bool> insert(const K& p)
		{
			return _t.insert(p);
		}

		K& operator[](const K& key)
		{
			pair<iterator, bool> ret = _t.insert(key);
			if (ret.second)
				return ret.first.it_root->_data;
			cout << "插入失败" << endl;
		}

		iterator begin()
		{
			return _t.begin();
		}

		iterator end()
		{
			return _t.end();
		}

		const_iterator begin() const
		{
			return _t.begin();
		}

		const_iterator end() const
		{
			return _t.end();
		}
	};
}

namespace my_map
{
	template <class K, class V>
	class map
	{
		typedef  RB_Tree_Iterator<pair<const K, V>, pair<const K, V>&, pair<const K, V>*> iterator;
		typedef  RB_Tree_Iterator<pair<const K, V>, const pair<const K, V>&, const pair<const K, V>*> const_iterator;
		struct KeyofT
		{
			const K& operator()(const pair<const K, V>& data)
			{
				return data.first;
			}
		};

		RB_Tree<K, pair<const K, V>, KeyofT> _t;

	public:
		pair<iterator, bool> insert(const pair<const K, V>& p)
		{
			return _t.insert(p);
		}

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _t.insert(make_pair(key, V()));
			if (ret.second)
				return ret.first->second;
			cout << "插入失败" << endl;
		}
		iterator begin()
		{
			return _t.begin();
		}

		iterator end()
		{
			return _t.end();
		}

		const_iterator begin() const
		{
			return _t.begin();
		}

		const_iterator end() const
		{
			return _t.end();
		}
	};
}

RB_Tree.h

#include <iostream>
#include<string>
#include <assert.h>
#include <utility>
using namespace std;

enum color
{
	RED,
	BLACK
};


template <class T>
struct RBT_Data
{
	T _data;
	RBT_Data<T>* left = nullptr;
	RBT_Data<T>* right = nullptr;
	RBT_Data<T>* parent = nullptr;
	color _col;  // 颜色

	RBT_Data(const T& p)
		:_data(p)
		, _col(RED) //与其修改黑色路径数量,不如违反红子孩子都为黑的原则来的轻松。
	{}
};

template <class T, class Ref, class Ptr>
class RB_Tree_Iterator
{
	typedef RBT_Data<T>  RBT_Data;
	typedef RB_Tree_Iterator<T, Ref, Ptr> Self;
	typedef RB_Tree_Iterator<T, T&, T*> iterator;  // 跟上面的不同,这个iterator只以T为准,这样在set const的对象时,不会出现
	                                               // 两个const 的情况

public:
	RBT_Data* it_root ;

	RB_Tree_Iterator(RBT_Data* _node = nullptr)
		:it_root(_node)
	{}

	RB_Tree_Iterator(const iterator& it)
		:it_root(it.it_root)
	{}

	Ref operator*()
	{
		return it_root->_data;
	}

	Ptr operator->()
	{
		return &it_root->_data;
	}

	// node* 地址也算不同罢了
	bool operator!= (const Self& node)
	{
		return node.it_root != it_root;
	}

	Self& operator++()
	{
		if (it_root && it_root->right)
		{
			// 假设右侧存在
			RBT_Data* subleft = it_root->right;
			while (subleft->left)
			{
				subleft = subleft->left;
			}
			it_root = subleft;
		}
		else //如果右侧没有
		{
			RBT_Data* cur = it_root;
			RBT_Data* par = it_root->parent;
			while (par && par->right == cur)
			{
				cur = par;
				par = par->parent;
			}
			it_root = par;
		}
		return *this;
	}


	Self& operator--()
	{
		if (it_root && it_root->right)
		{
			// 假设左侧存在
			RBT_Data* subright = it_root->left;
			while (subright->right)
			{
				subright = subright->right;
			}
			it_root = subright;
		}
		else //如果左侧没有
		{
			RBT_Data* cur = it_root;
			RBT_Data* par = it_root->parent;
			while (par && par->left == cur)
			{
				cur = par;
				par = par->parent;
			}
			it_root = par;
		}
		return *this;
	}

};


template <class K, class V, class KeyofT>
class RB_Tree
{
public:
	typedef RBT_Data<V> RBT_Data;
	typedef RB_Tree_Iterator<V, V&, V*> iterator;
	typedef RB_Tree_Iterator<V, const V&, const V*> const_iterator;

	// 这个也是按照后序遍历方式进行析构
	void Destroy(RBT_Data* node)
	{
		if (node == nullptr)
			return;
		Destroy(node->left);
		Destroy(node->right);
		delete(node);
	}

	~RB_Tree()
	{
		if (root)
		{
			Destroy(root);
			root = nullptr;
		}
	}

	iterator begin()
	{
		RBT_Data* node = root;
		while (node && node->left)
		{
			node = node->left;
		}
		return iterator(node);
	}

	// end跟以往的不同,end表示最后一个数据的下一个数据,也就是nullptr
	iterator end()
	{
		return iterator(nullptr);
	}


	const_iterator begin() const
	{
		RBT_Data* node = root;
		while (node && node->left)
		{
			node = node->left;
		}
		return const_iterator(node);
	}

	const_iterator end() const
	{
		return const_iterator(nullptr);
	}

	void Print()
	{
		_Print(root);
	}

	bool IsBalance()
	{
		if (root && root->_col == RED)
		{
			return false;
		}

		int BlackNum = 0;
		// 还差一个最长路径
		int standard = 0;
		RBT_Data* cur = root;
		while (cur)
		{
			if (cur->_col == BLACK)
				standard++;
			cur = cur->left;
		}
		return _IsBalance(root->left, BlackNum, standard) && _IsBalance(root->right, BlackNum, standard);
	}

	pair<iterator, bool>  insert(const V& p)
	{
		RBT_Data* new_a_d = new RBT_Data(p);
		if (!root)
		{
			root = new_a_d;
			root->_col = BLACK;
			return make_pair(iterator(new_a_d), true);
		}
		else
		{
			RBT_Data* cur = root;
			RBT_Data* parent = nullptr;
			KeyofT Kt;
			while (cur)
			{
				if (Kt(p) < Kt(cur->_data))
				{
					parent = cur;
					cur = cur->left;
				}
				else if (Kt(p) > Kt(cur->_data))
				{
					parent = cur;
					cur = cur->right;
				}
				else
				{
					delete(new_a_d); // 插入失败,删除新建结点
					return make_pair(iterator(root), false);
				}
			}

			if (p < parent->_data)
			{
				parent->left = new_a_d;
			}
			else
			{
				parent->right = new_a_d;
			}
			new_a_d->parent = parent;

			// 调整颜色
			cur = new_a_d;
			RBT_Data* par = cur->parent;
			if (cur == root)
			{
				cur->_col = BLACK;
			}

			while (par && par->_col == RED)
			{
				RBT_Data* gf = par->parent;
				RBT_Data* uncle = nullptr;
				if (gf && par == gf->right)
				{
					uncle = gf->left;
				}
				else if (gf && par == gf->left)
				{
					uncle = gf->right;
				}
				else
				{
					assert(false);
				}


				if (uncle && uncle->_col == RED)// 有u且为红
				{
					gf->_col = RED;
					uncle->_col = BLACK;
					par->_col = BLACK;

					cur = gf;  // 切换为祖先,进入循环向上
					par = cur->parent;
				}
				else if (!uncle ||
					(uncle && uncle->_col == BLACK))
				{   // 情况2 + 3,判断,是否是折线还是直线
					if (gf->left == par && par->left == cur)
					{  // 右单选
						RotateR(gf);
					}
					else if (gf->right == par && par->right == cur)
					{  // 左单旋
						RotateL(gf);
					}
					else if (gf->left == par && par->right == cur)
					{  // 需要左双旋
						RotateLR(gf);
					}
					else if (gf->right == par && par->left == cur)
					{  // 需要右双旋
						RotateRL(gf);
					}
					else
					{
						assert(false);
					}
					break;
				}
				else
				{
					assert(false);
				}
			}

			if (root->_col == RED)
			{
				root->_col = BLACK;
			}
			return make_pair(iterator(new_a_d), true);
		}
	}

private:
		RBT_Data* root = nullptr;

		void RotateL(RBT_Data* parent)
		{
			assert(parent->right);
			RBT_Data* par = parent;
			RBT_Data* par_R = par->right;
			RBT_Data* par_RL = par->right->left;
			RBT_Data* ppnode = par->parent;

			par->right = par_RL;
			if (par_RL)
				par_RL->parent = par;

			par_R->left = par;
			par->parent = par_R;
			par_R->parent = ppnode;

			if (!ppnode)
			{
				root = par_R;
			}
			else if (ppnode->left == par)
			{
				ppnode->left = par_R;
			}
			else
			{
				ppnode->right = par_R;
			}

			par->_col = RED;
			par_R->_col = BLACK;
		}

		void RotateR(RBT_Data* parent)
		{
			assert(parent->left);
			RBT_Data* par = parent;
			RBT_Data* par_L = par->left;
			RBT_Data* par_LR = par->left->right;
			RBT_Data* ppnode = par->parent;

			par->left = par_LR;
			if (par_LR)
				par_LR->parent = par;

			par_L->right = par;
			par->parent = par_L;
			par_L->parent = ppnode;

			if (!ppnode)
			{
				root = par_L;
			}
			else
			{
				if (ppnode->left == par)
				{
					ppnode->left = par_L;
				}
				else
				{
					ppnode->right = par_L;
				}
			}

			par->_col = RED;
			par_L->_col = BLACK;
		}

		void RotateLR(RBT_Data* parent)
		{
			assert(parent->left);
			RBT_Data* par = parent;
			RBT_Data* par_L = par->left;
			RBT_Data* par_LR = par->left->right;

			RotateL(par_L);
			RotateR(par);

			par_LR->_col = BLACK;
			par_L->_col = BLACK;
		}

		void RotateRL(RBT_Data* parent)
		{
			assert(parent->right);
			RBT_Data* par = parent;
			RBT_Data* par_R = par->right;
			RBT_Data* par_RL = par->right->left;

			RotateR(par_R);
			RotateL(par);

			par_RL->_col = BLACK;
			par_R->_col = BLACK;
		}

		void _Print(const RBT_Data* root)
		{
			if (root == nullptr)
			{
				// cout << "[]";
				return;
			}
			_Print(root->left);
			cout << KeyofT(root->_data) << " ";
			_Print(root->right);
		}

		bool _IsBalance(const RBT_Data* cur, int BlackNum, int standard)
		{
			if (cur == nullptr)
			{
				return true;
			}
			if (cur->_col == BLACK)
				BlackNum++;

			if (cur->_col == RED && cur->_col == cur->parent->_col)
			{
				return false;
			}

			return  _IsBalance(cur->left, BlackNum, standard) && _IsBalance(cur->right, BlackNum, standard);
		}
};

下期预告: 哈希!!

结语

   本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力文章来源地址https://www.toymoban.com/news/detail-740342.html

到了这里,关于用红黑树封装map&set【C++】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++【一棵红黑树封装 set 和 map】

    ✨个人主页: 北 海 🎉所属专栏: C++修行之路 🎃操作环境: Visual Studio 2019 版本 16.11.17 红黑树的基本情况我们已经在上一篇文章中学习过了,本文主要研究的是红黑树的实际应用:封装实现 set 和 map ,看看如何通过一棵红黑树满足两个不同的数据结构;在正式封装之前,

    2024年02月11日
    浏览(40)
  • C++ | 红黑树以及map与set的封装

    目录 前言 一、红黑树 1、红黑树的基本概念 2、红黑树相关特性 3、红黑树结点的定义 4、红黑树的查找 5、红黑树的插入 6、二叉树的拷贝构造与析构 7、红黑树的检测 8、红黑树总结 二、map与set的封装 1、红黑树的结点 2、红黑树迭代器 3、set的封装 4、map的封装 三、源码仓库

    2024年02月14日
    浏览(37)
  • 【C++】map与set容器——红黑树底层封装

    💭STL中,容器大概可分为两种类型——序列式容器和关联式容器。在前面的系列文章中,我们已经介绍了诸多序列式容器,如:vector、list、stack、queue等,它们以序列的形式存储数据。 💭而关联式容器也是一种非常重要的容器。标准的STL关联式容器分为set(集合)和map(映

    2023年04月11日
    浏览(40)
  • 【C++】使用红黑树进行封装map和set

    🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘 。 🛸 C++专栏 : C++内功修炼基地 家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真

    2024年02月07日
    浏览(46)
  • 【C++】用一棵红黑树同时封装出map和set

    苦厄难夺凌云志,不死终有出头日。 1. 在源码里面,对于map和set的实现,底层是用同一棵红黑树封装出来的,并不是用了两棵红黑树,一个红黑树结点存key,一个红黑树结点存key,value的键值对,这样的方式太不符合大佬的水准了,实际上在红黑树底层中用了一个模板参数Va

    2023年04月13日
    浏览(43)
  • Learning C++ No.23【红黑树封装set和map】

    北京时间:2023/5/17/22:19,不知道是以前学的不够扎实,还是很久没有学习相关知识,对有的知识可以说是遗忘了许多,以该篇博客有关知识为例,我发现我对迭代器和模板的有关知识的理解还不够透彻,不知道是对以前知识的遗忘,还是现在所学确实有难度,反正导致我很懵

    2024年02月05日
    浏览(50)
  • 【C++】STL——用一颗红黑树封装出map和set

    我们都知道set是K模型的容器,而map是KV模型的容器,但是它俩的底层都是用红黑树实现的,上篇博文中我们模拟实现了一颗红黑树,接下来将对其进行改造,继而用一颗红黑树封装出map和set。 本质上map和set其内部的主要功能都是套用了红黑树现成的接口,只是稍作改动即可

    2023年04月15日
    浏览(35)
  • AVL树,红黑树,红黑树封装map和set

    二叉搜索树虽可以缩短查找的效率,但如果 数据有序或接近有序二叉搜索树将退化为单支树 ,查找元素相当于在顺序表中搜索元素, 效率低下 。因此,咱们中国的邻居俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法: 当向二叉搜索树中插入

    2023年04月25日
    浏览(61)
  • 红黑树封装set和map(插入部分)

    之前我们实现了红黑树的插入的部分,本文主要介绍将之前实现的红黑树封装成map和set。我们是以学习的角度来封装容器,不用非要把库中容器所有功能都实现出来。我们主要目的是学习库中代码设计技巧和模板复用的思想。 我们在实现之前还是和以前一样去看看库中是怎么

    2024年02月07日
    浏览(40)
  • 【C++】红黑树 --- map/set 底层

    红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是 Red 或 Black . 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的;如下图: 每个结点不是红色就是黑色;

    2024年02月04日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包