红黑树封装map和set

news2024/11/25 0:04:57

文章目录

  • 红黑树封装map和set
    • 1. 改良红黑树
      • 1.1 改良后的节点
      • 1.2 改良后的类
        • 分别添加仿函数
        • 代码
    • 3. 封装map和set
      • 3.1 set
      • 3.2 map
    • 3. 迭代器
      • 3.1 begin 和 end
      • 3.2 operator++()和operator--()
      • 3.3 const迭代器
        • set的迭代器
        • map的迭代器
    • 4. map的operator[]的重载
    • 5. 完整代码实现
      • 5.1 RBTree.h
      • 5.2 set.h
      • 5.3 map.h

红黑树封装map和set

1. 改良红黑树

如何改良,可以参考stl源码

在这里插入图片描述

我们先看库中,map和set的大框架, 发现set在底层红黑树存储的是<k,k>的键值对,不像我们平时认知以为只存储一个k,map在底层红黑树存储的是<k,v>的键值对。继续看库中红黑树的源码

在这里插入图片描述

发现在红黑树节点这里并不是我们之前实现的K, V形式,而是只给了一个Value形式。

对于set第二个模板参数是K,其节点中存储的就是K,这里的Value就代表的是K;

对于map第二个模板参数是pair<const K,V>,其节点中存储的就是pair<const K,V>,这里的Value就代表的是pair<const K,V>;

那么在红黑树模板参数设计时,为什么要多设计一个Key的模板参数呢? 是为了拿到单独的K类型,find和erase这些接口函数的参数是K;第二个模板参数才真正决定节点里面存储什么

1.1 改良后的节点

template<class T>
struct RBTreeNode	//三叉链
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _data;
	Colour _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)       //默认颜色给红色
	{}
};

1.2 改良后的类

分别添加仿函数

插入和查找的过程中的比较不能想红黑树一样实现成kv.first的形式,我们要实现成用节点中实际存储的类型去比较,对于set存储的是K,可以直接去比较;对于map存储的是pair,比较时是用pair比较,但是pair的比较并不是我们想要的,我们还是想要pair中的K比较

在这里插入图片描述

上面的问题我们可以看库中源码,发现多给了一个模板参数KeyOfValue,其目的是取出K,可以分别给具体的仿函数来实现。

在这里插入图片描述

set这里直接返回key就行

struct SetKeyOfT
{
    const K &operator()(const K &key)
    {
        return key;
    }
};

map这里需要返回pair的first, 即K

struct MapKeyOfT
{
    const K &operator()(const pair<const K, V> &kv)
    {
        return kv.first;
    }
};

那么为什么需要这么做,对于set来说直接比较不就行了吗,当然可以,但是map并不是直接用_data类型比较(即pair本身), set为了和map复用同一棵红黑树,所以要实现成这种形式

在这里插入图片描述

同样我们插入和查找时也需要修改,用map和set传过来的仿函数定义出一个对象kot,帮助我们取出帮助我们取出_data中的Key。

代码

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	~RBTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}

	Node* Find(const K& key)
	{
		Node* cur = _root;
		KeyOfT kot;		//仿函数定义出对象,帮助我们取出_data中的Key
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) >key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;      
			}
		}
		return nullptr;
	}

	bool Insert(const T& data)
	{
		//第一次插入
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;         //根节点给黑色
			return true;
		}

		KeyOfT kot;
		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;    //该元素已经在树中存在了, 无法插入
			}
		}

		//链接
		cur = new Node(data);
		Node* newnode = cur;      //cur可能会变色, 需要提前记录cur
		if (kot(parent->_data) > kot(data))
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		//处理红黑树颜色
		while (parent && parent->_col==RED)
		{
			Node* grandfather = parent->_parent;

			//找叔叔  =>  看父亲在祖父的哪边
			if (grandfather->_left == parent)   
			{
				Node* uncle = grandfather->_right;

				//3种情况

				//情况1: u存在且为红, 变色处理, 并继续向上处理
				//变色: p,u变黑, g变红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续向上调整
					cur=grandfather;
					parent = cur->_parent;
				}
				else    //情况2+3: u不存在/u存在且为黑, 旋转 + 变色
				{
					//     g
					//   p   u
					// c
					if(cur==parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
					//     g
					//   p   u
					//     c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else    //(grandfather->_right == parent)
			{
				Node* uncle = grandfather->_left;

				//3种情况

				//情况1: u存在且为红, 变色处理, 并继续向上处理
				//变色: p,u变黑, g变红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else      //情况2+3: u不存在/u存在且为黑, 旋转 + 变色
				{
					//     g
					//   u   p
					//         c
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//     g
						//   u   p
	                    //     c

						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
		}
		_root->_col = BLACK;   //根节点是黑色的
		return true;
	}
private:
    	Node* _root = nullptr;
};	

3. 封装map和set

3.1 set

namespace yj
{
	template<class K>
	class set
	{
		//作用是:将T中的key提取出来
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		bool insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
}

3.2 map

namespace yj
{
	template<class K, class V>
	class map
	{
		//作用是:将T中的key提取出来
		struct MapKeyOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
	    bool insert(const pair<const K, V>& kv)
		{
			return _t.Insert(kv);
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
}

3. 迭代器

迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代器,需要考虑以前问题:

3.1 begin 和 end

STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位置,end()放在最大节点(最右侧节点)的下一个位置,STL是将end()放在头结点的位置:我们上次设计的RBTree没有头结点这个结构,因此我们也就不与STL的实现方式完全一样,end()就直接设置为nullptr

iterator begin() // 中序遍历第一个
{
    Node *cur = _root;

    while (cur && cur->_left)   //找最左侧节点
    {
        cur = cur->_left;
    }

    return iterator(cur); // 节点指针构造的迭代器
}

iterator end() // 最后一个节点的下一个
{
    return iterator(nullptr);
}

3.2 operator++()和operator–()

++的实现思路:

  1. 右不为空, 下一个就是右子树的最左节点

  2. 右为空, 沿着到根的路径, 找孩子是父亲左的那个祖先

Self &operator++()
{
    if (_node->_right)
    {
        // 1. 右不为空, 下一个就是右子树的最左节点
        Node *subLeft = _node->_right;
        while (subLeft->_left)
        {
            subLeft = subLeft->_left;
        }

        _node = subLeft; // 将节点的地址赋值即可
    }
    else
    {
        // 2. 右为空, 沿着到根的路径, 找孩子是父亲左的那个祖先
        Node *cur = _node;
        Node *parent = _node->_parent;
        while (parent && cur == parent->_right)
        {
            cur = parent;
            parent = parent->_parent;
        }

        _node = parent;
    }
    return *this;
}

–的实现思路: 与++相反

  1. 左不为空, 下一个就是左子树的最右节点

  2. 左为空, 沿着到根的路径, 找孩子是父亲右的那个祖先

Self &operator--()
{
    if (_node->_left)
    {
        // 1. 左不为空, 下一个就是左子树的最右节点
        Node *subRight = _node->_left;
        while (subRight->_right)
        {
            subRight = subRight->_right;
        }

        _node = subRight; // 将节点的地址赋值即可
    }
    else
    {
        // 2. 左为空, 沿着到根的路径, 找孩子是父亲右的那个祖先
        Node *cur = _node;
        Node *parent = _node->_parent;
        while (parent && cur == parent->_left)
        {
            cur = parent;
            parent = parent->_parent;
        }

        _node = parent;
    }
    return *this;
}

3.3 const迭代器

如果是const迭代器,那可以在迭代器类中多加上两个模板参数:T&, T*偏特化,当然实际上是Ref,Ptr的全特化;

那如何实现set的const迭代器呢?由于set不能修改普通迭代器就是const迭代器,const迭代器还是const迭代器;

对于map来说普通迭代器就是普通迭代器,const迭代器就是const迭代器,但是map的pair中的value是可以修改的,因此我们就需要在RBTree中把普通迭代器和const迭代器均实现出来,同时也要支持从普通迭代器 隐式类型转换 成构造const迭代器的构造函数。,当map的迭代器类模板被实例化成普通迭代器时,它就是拷贝构造;迭代器类模板被实例化成const迭代器时,它是一个支持用普通迭代器构造初始化const迭代器的构造函数

在这里插入图片描述

template <class T, class Ref, class Ptr>
struct _RBTreeIterator
{
    typedef RBTreeNode<T> Node;
    typedef _RBTreeIterator<T, Ref, Ptr> Self;
    Node *_node;

    _RBTreeIterator(Node *node)
        : _node(node)
    {
    }

    // 1. typedef _RBTreeIterator<T, T&, T*> iterator;  拷贝构造
    //
    // 支持普通迭代器构造const迭代器的构造函数
    // 2. typedef _RBTreeIterator<T, const T&, const T*> const_iterator;

    // 支持从普通迭代器 隐式类型转换 成构造const迭代器的构造函数
    _RBTreeIterator(const _RBTreeIterator<T, T &, T *> &it)
        : _node(it._node)
    {
    }
}

set的迭代器

typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

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

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

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

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

map的迭代器

typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

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

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

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

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

4. map的operator[]的重载

根据map的[]性质: 返回make_pair<iterator,bool>的first,解引用找到节点value, 借助Insert函数,同时需要将我们插入函数返回类型的从bool变成pair类型

V& operator[](const K &key)
{
    pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));   //V()构造一个匿名对象
    return ret.first->second; 
    // 找到ret(make_pair<iterator,bool>)的first,解引用找到节点value
}
pair<iterator, bool> Insert(const T &data)
{
    // 第一次插入
    if (_root == nullptr)
    {
        _root = new Node(data);
        _root->_col = BLACK; // 根节点给黑色
        return make_pair(iterator(_root), true);
    }

    KeyOfT kot;
    Node *parent = nullptr;
    Node *cur = _root;

    while (cur)
    {
        if (kot(cur->_data) < kot(data))
        {
            parent = cur;
            cur = cur->_right;
        }
        else if (kot(cur->_data) > kot(data))
        {
            parent = cur;
            cur = cur->_left;
        }
        else
        {
            return make_pair(iterator(cur), false); // 该元素已经在树中存在了, 无法插入
        }
    }

    // 链接
    cur = new Node(data);
    Node *newnode = cur; // cur可能会变色, 需要提前记录cur
    if (kot(parent->_data) > kot(data))
    {
        parent->_left = cur;
    }
    else
    {
        parent->_right = cur;
    }
    cur->_parent = parent;

    // 处理红黑树颜色
    while (parent && parent->_col == RED)
    {
        Node *grandfather = parent->_parent;

        // 找叔叔  =>  看父亲在祖父的哪边
        if (grandfather->_left == parent)
        {
            Node *uncle = grandfather->_right;

            // 3种情况

            // 情况1: u存在且为红, 变色处理, 并继续向上处理
            // 变色: p,u变黑, g变红
            if (uncle && uncle->_col == RED)
            {
                parent->_col = BLACK;
                uncle->_col = BLACK;
                grandfather->_col = RED;

                // 继续向上调整
                cur = grandfather;
                parent = cur->_parent;
            }
            else // 情况2+3: u不存在/u存在且为黑, 旋转 + 变色
            {
                //     g
                //   p   u
                // c
                if (cur == parent->_left)
                {
                    RotateR(grandfather);
                    parent->_col = BLACK;
                    grandfather->_col = RED;
                }
                else
                {
                    //     g
                    //   p   u
                    //     c
                    RotateL(parent);
                    RotateR(grandfather);
                    cur->_col = BLACK;
                    grandfather->_col = RED;
                }

                break;
            }
        }
        else //(grandfather->_right == parent)
        {
            Node *uncle = grandfather->_left;

            // 3种情况

            // 情况1: u存在且为红, 变色处理, 并继续向上处理
            // 变色: p,u变黑, g变红
            if (uncle && uncle->_col == RED)
            {
                parent->_col = BLACK;
                uncle->_col = BLACK;
                grandfather->_col = RED;

                // 继续向上调整
                cur = grandfather;
                parent = cur->_parent;
            }
            else // 情况2+3: u不存在/u存在且为黑, 旋转 + 变色
            {
                //     g
                //   u   p
                //         c
                if (cur == parent->_right)
                {
                    RotateL(grandfather);
                    parent->_col = BLACK;
                    grandfather->_col = RED;
                }
                else
                {
                    //     g
                    //   u   p
                    //     c

                    RotateR(parent);
                    RotateL(grandfather);
                    cur->_col = BLACK;
                    grandfather->_col = RED;
                }

                break;
            }
        }
    }
    _root->_col = BLACK; // 根节点是黑色的

    return make_pair(iterator(newnode), true);
}

5. 完整代码实现

5.1 RBTree.h

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


//节点的颜色
enum Colour
{
	RED,
	BLACK,
};


template<class T>
struct RBTreeNode	//三叉链
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _data;
	Colour _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)       //默认颜色给红色
	{}
};



template<class T,class Ref, class Ptr>
struct _RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef _RBTreeIterator<T,Ref,Ptr> Self;
	Node* _node;

	_RBTreeIterator(Node* node)
		:_node(node)
	{}


	// 1. typedef _RBTreeIterator<T, T&, T*> iterator;  拷贝构造
	// 
	// 支持普通迭代器构造const迭代器的构造函数
	// 2. typedef _RBTreeIterator<T, const T&, const T*> const_iterator;  

	//支持从普通迭代器 隐式类型转换 成构造const迭代器的构造函数
	_RBTreeIterator(const _RBTreeIterator<T, T&, T*>&it)
		:_node(it._node)
	{}



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

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

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}


	Self& operator++()
	{
		if (_node->_right)
		{
			//1. 右不为空, 下一个就是右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}

			_node = subLeft;     //将节点的地址赋值即可
		}
		else
		{
			//2. 右为空, 沿着到根的路径, 找孩子是父亲左的那个祖先
			Node* cur = _node;
			Node* parent = _node->_parent;
			while (parent && cur==parent->_right)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}


	Self& operator--()
	{
		if (_node->_left)
		{
			//1. 左不为空, 下一个就是左子树的最右节点
			Node* subRight = _node->_left;
			while (subRight->_right)
			{
				subRight = subRight->_right;
			}

			_node = subRight;     //将节点的地址赋值即可
		}
		else
		{
			//2. 左为空, 沿着到根的路径, 找孩子是父亲右的那个祖先
			Node* cur = _node;
			Node* parent = _node->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}
};




//仿函数
template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	~RBTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}

	typedef _RBTreeIterator<T, T&, T*> iterator;
	typedef _RBTreeIterator<T, const T&, const T*> const_iterator;

	iterator begin()    //中序遍历第一个
	{
		Node* cur = _root;
		
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}

		return iterator(cur);      //节点指针构造的迭代器
	}




	iterator end()    //最后一个节点的下一个
	{
		return iterator(nullptr);   
	}


	const_iterator begin()const
	{
		Node* cur = _root;

		while (cur && cur->_left)
		{
			cur = cur->_left;
		}

		return const_iterator(cur);      
	}

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


	Node* Find(const K& key)
	{
		Node* cur = _root;
		KeyOfT kot;			//仿函数定义出对象,帮助我们取出_data中的Key
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) >key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;      
			}
		}

		return nullptr;
	}



	pair<iterator,bool> Insert(const T& data)
	{
		//第一次插入
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;         //根节点给黑色
			return make_pair(iterator(_root), true);
		}

		KeyOfT kot;
		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return make_pair(iterator(cur), false);    //该元素已经在树中存在了, 无法插入
			}

		}


		//链接
		cur = new Node(data);
		Node* newnode = cur;      //cur可能会变色, 需要提前记录cur
		if (kot(parent->_data) > kot(data))
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;


		//处理红黑树颜色
		while (parent && parent->_col==RED)
		{
			Node* grandfather = parent->_parent;

			//找叔叔  =>  看父亲在祖父的哪边
			if (grandfather->_left == parent)   
			{
				Node* uncle = grandfather->_right;

				//3种情况

				//情况1: u存在且为红, 变色处理, 并继续向上处理
				//变色: p,u变黑, g变红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续向上调整
					cur=grandfather;
					parent = cur->_parent;
				}
				else    //情况2+3: u不存在/u存在且为黑, 旋转 + 变色
				{
					//     g
					//   p   u
					// c
					if(cur==parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
					//     g
					//   p   u
					//     c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else    //(grandfather->_right == parent)
			{
				Node* uncle = grandfather->_left;

				//3种情况

				//情况1: u存在且为红, 变色处理, 并继续向上处理
				//变色: p,u变黑, g变红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else      //情况2+3: u不存在/u存在且为黑, 旋转 + 变色
				{
					//     g
					//   u   p
					//         c
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//     g
						//   u   p
	                    //     c

						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;

					}

					break;
				}
			}
		}

		_root->_col = BLACK;   //根节点是黑色的

		return make_pair(iterator(newnode), true);
	}

	void Inorder()
	{
		_Inorder(_root);
	}

	int Height()
	{
		return _Height(_root);
	}

	bool IsBalance()    //重点检查规则
	{
		//先检查根节点
		if (_root && _root->_col == RED)
		{
			cout << "根节点颜色是红色" << endl;
			return false;
		}

		int benchmark = 0;       //基准值
		Node* cur = _root;
		while(cur)               //走最左路径
		{
			if (cur->_col == BLACK)
				++benchmark;

			cur = cur->_left;
		}

		//连续红色节点
		return _Check(_root, 0,benchmark);
	}


private:

	//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		Node* ppnode = parent->_parent;

		subR->_left = parent;
		parent->_parent = subR;


		if (ppnode == nullptr)				//parent本身就是根
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else								//parent只是一棵子树
		{
			if (ppnode->_left == parent)   //判断原来的节点是左右哪一棵子树
			{
				ppnode->_left = subR;
			}
			else
			{
				ppnode->_right = subR;
			}
			subR->_parent = ppnode;
		}
	}


	//右单旋
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		Node* ppnode = parent->_parent;

		subL->_right = parent;
		parent->_parent = subL;


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


	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		return leftH > rightH ? leftH + 1 : rightH + 1;
	}


	bool _Check(Node* root, int blackNum, int benchmark)  //基准值
	{
		if (root == nullptr)
		{
			if (benchmark != blackNum)
			{
				cout << "某条路径黑色节点的数量不相等" << endl;
				return false;
			}
			return true;
		}

		//DFS检查黑色节点数量
		if (root->_col == BLACK)
		{
			++blackNum;
		}

		//反向检查  ---> 红色节点不能连续
		if (root->_col == RED
			&& root->_parent
			&& root->_parent->_col == RED)
		{
			cout << "存在连续的红色节点" << endl;
			return false;
		}

		return _Check(root->_left,  blackNum,  benchmark)
			&& _Check(root->_right, blackNum,  benchmark);
	}

	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}

	void _Inorder(Node* root)
	{
		if (root == nullptr)
			return;

		_Inorder(root->_left);
		cout << root->_kv.first << " ";
		_Inorder(root->_right);

	}

	Node* _root = nullptr;
};

5.2 set.h

#include"RBTree.h"

namespace yj
{
	template<class K>
	class set
	{
		//作用是:将T中的key提取出来
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

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

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

		pair<iterator, bool>  insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
}

5.3 map.h

#include"RBTree.h"

namespace yj
{
	template<class K, class V>
	class map
	{
		//作用是:将T中的key提取出来
		struct MapKeyOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:

		//取类模板的内嵌类型前需要添加typename, 因为编译器无法区分取到的是内嵌类型还是静态变量
		//加typename告诉编译器这是类模板的内嵌类型
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

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

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

		V& operator[](const K& key)
		{
			pair<iterator,bool> ret= _t.Insert(make_pair(key, V()));
			return ret.first->second; //找到ret(make_pair<iterator,bool>)的first,解引用找到节点value
		}

		pair<iterator, bool> insert(const pair<const K, V>& kv)
		{
			return _t.Insert(kv);
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/534918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

美团二面:聊聊ConcurrentHashMap的存储流程

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、Spring源码系列、Netty源码系列、Kafka源码系列、JUC源码…

手把手教你彻底卸载MySQL

❤写在前面 ❤博客主页&#xff1a;努力的小鳴人 ❤系列专栏&#xff1a;MySQL8.0基础学习 ❤欢迎小伙伴们&#xff0c;点赞&#x1f44d;关注&#x1f50e;收藏&#x1f354;一起学习&#xff01; ❤如有错误的地方&#xff0c;还请小伙伴们指正&#xff01;&#x1f339; ​ …

抖音SEO矩阵系统源码开发搭建(一)

抖音SEI矩阵系统源码开发&#xff0c;需要遵循一下步骤&#xff1a; 1. 确定需求和功能&#xff1a;明确系统的主要目标和需要实现的功能&#xff0c;包括关键词研究、短视频制作、外链建设、数据分析、账号设置优化等方面。 2. 设计系统架构&#xff1a;根据需求和功能确定系…

Golang每日一练(leetDay0068) 二叉树右视图、岛屿数量

目录 199. 二叉树的右视图 Binarytree Right Side View &#x1f31f;&#x1f31f; 200. 岛屿数量 Number-of-islands &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日…

【C++】图解类和对象(中)

类和对象&#xff08;中&#xff09; 文章目录 类和对象&#xff08;中&#xff09;一、类的6个默认成员函数二、构造函数1.定义2.特性3.对特性的理解及几点注意事项 二、析构函数总结 一、类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的…

只需6步,就能让你的 React +Tailwind.css站点实现暗黑功能

欢迎回来&#xff0c;开始一次新的编码之旅吧&#xff01;今天&#xff0c;我们将进入神秘的世界&#xff0c;探索如何在你的React.js网站中使用Tailwind.css实现暗黑模式。Tailwind.css 是你编码工具中的强大助手&#xff0c;结合React.js使用&#xff0c;你可以创造出令人惊叹…

Swoft中使用Consul微服务

目录 Swoft中接入Consul Swoft服务限流 Swoft服务熔断和降级 在之前我写的一篇内容&#xff1a;PHP中接入consul&#xff0c;实现微服务的注册发现和配置中心_浮尘笔记的博客-CSDN博客 中&#xff0c;使用ThinkPHP6.0框架接入了微服务Consul&#xff0c;并且留下了一个彩蛋 …

【K8s】Helm

文章目录 一、Helm介绍1、背景2、介绍3、核心概念4、chart的基本结构5、helm官网 二、部署Helm1、安装helm客户端2、安装Tiller 三、常用指令1、仓库相关 helm repo2、chart相关 四、入门案例1、构建第一个chart2、将chart包发布到Repository3、在 Kubernetes 中部署应用4、升级…

用JS实现虚拟列表(IT枫斗者)

用JS实现虚拟列表 简介 当一个列表需要渲染大量数据的时候是非常耗时的&#xff0c;而且在列表滚动的过程中会出现卡顿的现象。即使用上懒加载解决了列表初始化时渲染过慢的问题&#xff0c;但是每次拉取下一页数据的时候都会造成列表的重新渲染。随着拉取的数据越来越多&…

使用火焰图进行性能分析(一)

为什么会用到火焰图&#xff1f;火焰图能干那些事儿&#xff1f; 分析函数执行的频度&#xff1b;分析哪些函数经常阻塞&#xff1b;分析哪些函数频繁操作内存&#xff1b; 火焰图的主要特点&#xff1a; 每一列代表一个调用栈&#xff0c;每个格子代表一个函数&#xff1b;…

计算机图形学-GAMES101-4

一、变换矩阵中的旋转部分 当我们旋转Q角度和旋转-Q角度时&#xff0c;变换矩阵中旋转的部分如下图所示&#xff1a; 旋转Q和旋转-Q的变换矩阵应该互为逆矩阵&#xff0c;而我们可以看到它们互为对方矩阵的转置。其实Rq是一个正交矩阵&#xff0c;因此其逆矩阵就是它自己的转…

chrome渲染引擎的工作主流程

一见如故 浏览器的渲染&#xff1a;HTML字符串>渲染成最终的像素1、CSS Parser发生在css预解析线程中&#xff0c;不在主线程中&#xff1b;会预览整个HTML文档&#xff0c;下载css相关全部内容&#xff0c;解析生成CSSOM树 2、attachment >以及生成布局树>分层>按…

微服务的使用场景和架构设计方案

目录 【单体架构】 【微服务解决哪些问题】 微服务的拆分原则 微服务使用过程中有哪些坑&#xff1f; 【RPC框架】 常见的网络 IO 模型 RPC 执行过程总结 【CAP原理】 如何使用 CAP 理论 【服务注册和发现】 【配置中心】 【Consul】 Consul介绍 Consul角色 Con…

Go语言的结构体、方法、指针

目录 【定义新数据类型】 【结构体】 定义结构体 结构体变量的声明和初始化 结构体的内存表示 【方法】 receiver 参数 receiver参数的约束 方法的深入理解 goroutine中方法的使用 receiver 参数类型如何选择&#xff1f;T还是*T&#xff1f; 方法集合 【指针】 …

9. 三星索引和Mysql内核查询成本计算实战

MySQL性能调优 1. 高性能的索引创建策略1.1 只为用于搜索、排序或分组的列创建索引1.2 合理设计多列索引1.3 尽可能设计三星索引1.4 主键尽量是很少改变的列1.5 处理冗余和重复索引1.6 删除未使用的索引1.7 InnoDB中的索引 2. 补充资料&#xff1a;磁盘和B树Mysql内核查询成本计…

从0到1无比流畅的React入门教程

无比流畅的React入门教程TOC React 是什么 简介 用于构建 Web 和原生交互界面的库React 用组件创建用户界面通俗来讲&#xff1a;是一个将数据渲染为HTML视图的开源JS库 其他信息 Facebook 开发&#xff0c;并且开源 为什么使用React? 原生JS使用DOM-API修改UI代码很繁…

使用Appium实现录制回放

1、cmd中转到abd所在位置&#xff1a; cd C:\Users\lenovo\AppData\Local\Android\Sdk\platform-tools 2、打开Appium运行 3、打开Appium Inspector &#xff08;1&#xff09;获取设备名称 在cmd中输入以下命令&#xff1a; adb devices &#xff08;2&#xff09;获取appP…

c++核心知识—多态

目录 一、多态 1、多态的基本概念 2、深入剖析多态原理&#xff1a; 3、纯虚函数和抽象类 4、虚析构和纯虚析构 一、多态 1、多态的基本概念 多态是C面向对象三大特性之一 多态分为两类&#xff1a; 1、静态多态: 函数重载 和 运算符重载 属于静态多态&#xff0c;复用…

前端八股文(二)

1.什么是diff算法&#xff1f; https://www.bilibili.com/video/BV1JR4y1R7Ln/?spm_id_from333.337.search-card.all.click&vd_source0406fa5cf8203ba41f1c8aec5f967e9d 我们修改了文本内容后会生成新的虚拟dom,新旧俩个虚拟dom之间是存在一定差异的&#xff0c;如果能快…

未来的航空电子设备会是什么样子?

具有多功能航空电子设备、大触摸屏显示器、先进通信系统、高性能/低功耗解决方案和人工智能 (AI) 功能的驾驶舱将成为未来军事飞行员日常生活的一部分。 如今&#xff0c;配备模拟驾驶舱的军用飞机已经很少见&#xff0c;因为大多数都已被采用先进嵌入式硬件和软件解决方案的现…