map和set的设计以及红黑树的设计

1.map和set的底层是红黑树

2.map和set在STL是容器,在我看来,不过也是封装了平衡二叉搜索树红黑树的适配器

我们先看红黑树的设计,看完后map和set的封装易如反掌

#pragma once
#include<utility>
#include<iostream>
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>//T 确定迭代器指向什么类型节点,reference 引用,ptr  pointer指针
struct __RBTreeIterator //不是struct就不能直接访问迭代器成员_node
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;

	Node* _node;

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

	__RBTreeIterator(const __RBTreeIterator<T, T&, T*>& it)//set中begin()是红黑树begin()的封装,红黑树是普通红黑树成员,红黑树begin()返回的是普通迭代器,但是set中用Iterator来接收返回值,是红黑树中const_iterator的重命名,所以要加一个函数,用iterator构造出const——iterator,才能正常返回
	     : _node(it._node)
	{}

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

	Ptr operator->()//调用时少一个->,编译器会出手
	{
		return &_node->_data;
	}

	bool operator!=(Self it)
	{
		return _node != it._node;
	}
	Self& operator++()//中序左根右    迭代器不销毁传引用
	{
		if (_node->_right)
		{
			Node* tmp = _node->_right;
			while (tmp->_left)
			{
				tmp = tmp->_left;
			}
			_node = tmp;
		}
		else
		{
			Node* cur = _node,*parent=_node->_parent;
			while (parent && parent->_right == cur)//cur在右边cur遍历根早遍历过了  如果parent为空说明是最右端节点,++置空
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;

		}
		return *this;
	}

	Self& operator--()//--就是++反过来的顺序,右根左
	{
		if (_node->_left)
		{
			Node* tmp = _node->_left;
			while (tmp->_right)
			{
				tmp = tmp->right;
			}
			_node = tmp;
			return *this;
		}
		else
		{
			Node* cur = _node, * parent = _node->_parent;
			while (parent && parent->_left == cur)//右根左 cur在左边cur遍历根早遍历过了  parent为空则是最左端节点
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
			return *this;
		}
	}


	
		
	
};


template<class K,class T,class KeyOfT>//KeyOfT是仿函数,用来控制节点的比较,因为node里是T,没有K
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()//传普通红黑树的this指针
	{
		Node* tmp = _root;
		while (tmp && tmp->_left)
		{
			tmp = tmp->_left;
		}
		
		return tmp;//tmp构造一个const临时iterator,再赋值
	}
	iterator end()
	{
		return nullptr;
	}
	
	const_iterator begin()const//传const红黑树的this指针,返回const红黑树迭代器
	{
		Node* tmp = _root;
		while (tmp && tmp->_left)
		{
			tmp = tmp->_left;
		}

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

	Node* Find(const K& key)
	{
		Node* cur = _root;
		KeyOfT kot;
		while (cur)
		{
			if (kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
			
		}
		return nullptr;
	}

	pair<iterator, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root=new Node(data);
			//BUG--没有把节点变黑
			_root->_col = BLACK;
			return make_pair(_root, true);
		}


		Node* cur = _root,*parent=nullptr;
		KeyOfT kot;
		while (cur)
		{
			if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return make_pair(iterator(cur), false);
			}
		}

		cur = new Node(data);

		if (kot(parent->_data) > kot(data))
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		Node* newnode = cur;
		cur->_parent = parent;

		while (parent && parent->_col==RED)//插入的是红色,如果parent为黑就不用调整,为红就调整
		{
			//因为parent是红色,所以parent不是根,一定有爷爷节点且为黑色
			Node* grandfather = parent->_parent;
			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col=BLACK;
					grandfather->_col = RED;

					//爷爷节点的父节点可能是红,还得向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else//叔叔不存在或者是黑
				{
					if (cur == parent->_left)//cur的位置不同旋转就不同
					{
						rotateR(grandfather);
							grandfather->_col = RED;
						parent->_col = BLACK;
						
					}
					else
					{
						rotateL(parent);
						rotateR(grandfather);
						grandfather->_col = RED;
						cur->_col = BLACK;
						
					}
					break;//新子树根节点是黑色,无需再向上调
				}
			}
			else//爷爷的右边是parent
			{
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_col == RED)//叔叔为红时调整不需要考虑cur的位置
				{
					uncle->_col =parent->_col= BLACK;
					grandfather->_col = RED;
					cur = grandfather;
					parent = cur->_parent;

				}
				else
				{
					if (cur == parent->_right)
					{
						rotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
						
					}
					else
					{
						rotateR(parent);
						rotateL(grandfather);
						grandfather->_col = RED;
						cur->_col = BLACK;
						
					}
					break; // 新子树根节点是黑色,无需再向上调
				}
			}
		}
		//调整完可能有根节点为红
		_root->_col = BLACK;
		return make_pair(newnode, true);
	}

	bool isRBTree()
	{
		if (_root == nullptr) return true;

		if (_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:
	bool _Check(Node* root, int blacknum, int benchmark)
	{
		if (root == nullptr)//root为空说明一条路径结束
		{
			if (benchmark == blacknum)
			{
				return true;
			}
			else
			{
				cout << "路经黑色节点数量不一" << endl;
				return false;
			}
		}

		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 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)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			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 (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subL;
			}
			else
			{
				ppnode->_right = subL;
			}
			subL->_parent = ppnode;
		}
	}
	Node* _root = nullptr;
};


1.红黑树结点的设计

三个指针一个T类型数据,还有一个颜色

2.红黑树的模板参数

第一个是节点排序所用的类型K,第二个是节点里数据的类型T,第三个是把T变成K的仿函数类型

3.g++的红黑树设计思路是一个哨兵节点,一个节点数量

g++中哨兵节点(_M_header)的结构

  • _M_header->_M_parent:指向红黑树的 根节点(如果树非空)。

  • _M_header->_M_left:指向树的 最左节点(即中序遍历的第一个节点)。

  • _M_header->_M_right:指向树的 最右节点(即中序遍历的最后一个节点)。

template <typename _Key, typename _Val, typename _KeyOfValue, typename _Compare, typename _Alloc>
class _Rb_tree {
private:
    _Rb_tree_node<_Val>* _M_header;  // 哨兵节点(根节点的父节点)
    size_t _M_node_count;            // 节点数量
    _Compare _M_key_compare;         // 比较函数(默认 std::less<_Key>)

public:
    // 插入、删除、查找等操作...
};

但是我上面代码的实现并没有设计哨兵节点,也没有节点个数,就一个根节点

4.红黑树的迭代器设计

红黑树的迭代器和list一样是封装了结点指针的类,第一个模板参数是为了形成结点指针类型,二、三模板参数则是为了实例化出迭代器和const迭代器类

5.g++设计迭代器 和  我上面代码设计的迭代器

g++迭代器的 begin() 和 end() 逻辑

  • begin() 直接返回 _M_header->_M_left(最左节点)。

  • end() 返回 哨兵节点_M_header

自己设计的迭代器的 begin() 和 end() 逻辑:

  • begin() 遍历查找返回最左节点。

  • end() 返回 nullptr。

map和set适配红黑树

#pragma once
#include"RBTree.h"
namespace aqc
{
	template<class K,class V>
	class map
	{
	public:
		struct MapKeyOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};

		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;//如果不加typename可能编译器会识别为类中的静态变量
		iterator begin()
		{
			return t.begin();
		}

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

		pair<iterator,bool> Insert(const pair<const K, V>& kv)
		{
			 return t.Insert(kv);
		}

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = t.Insert(make_pair(key, V()));
			return ret.first->second;//iterator->返回的是_data的地址
		}
	private:
		RBTree<K, pair<const K,V>, MapKeyOfT> t;
	};
}







#pragma once
#include"RBTree.h"
namespace aqc
{
	template<class K>
	class set
	{
	public:
		struct SetKeyOfT
		{
			const K& operator()(const K& key)//如果写成struct外面调不到运算符重载
			{
				return key;
			}
		};

		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;//set中二叉树节点的T即为key,不能被修改
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

		iterator begin()
		{
			return t.begin();//普通红黑树成员调begin返普通迭代器,接受类型为:const_iterator,因此先前在红黑树加了个const迭代器构造函数
		}

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

		const_iterator begin()const
		{
			return t.begin();//const set调用begin:首先普通红黑树调用begin返回普通迭代器,然后接受类型构造
		}


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

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

1.封装map,节点来排序的类型是K,节点里数据的类型pair<const K,V>,还有把T变成K的仿函数类

2.封装set,节点用来排序的类型是K,节点里数据的类型还是K,还有把T变成K的仿函数类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值