使用红黑树封装map和set

目录

一、set和map的底层结构

使用模板区分map和set

 使用仿函数来比较大小

二、红黑树中set和map的迭代器

end和begin迭代器

operator++迭代器

operator--

三、set与map中的迭代器和const迭代器

四、迭代器的拷贝构造

五、完整代码

set.h

map.h 

RBTree.h


一、set和map的底层结构

使用模板区分map和set

set:

使用红黑树封装map和set_第1张图片

 map:

使用红黑树封装map和set_第2张图片

我们通过去看源码,我们能发现无论是set还是map使用的是同一颗红黑树。并且set中key_type和value_type中其实使用的都是key,然而map中key_type是key,value_type却是pair

也就是通过传过去的value_type来区分我们用的是map还是set。由于为了区分value与pair我们吧pair在模板中用T来表示。

template
struct RBTreeNode
{
	T _data;
	RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;
	Colour _col;

	RBTreeNode(const T& data)
		:_data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _col(RED)
	{}
};

 使用仿函数来比较大小

在set中我们比较大小时,是直接使用key来比较大小的。可是我们map中封装的是pair,pair的比较大小是先比较first,first比较完之后还要比较s0econd。因此不符合我们期望的比较规则,我们需要实现一个仿函数来改变pair的比较规则。

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



template
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair& kv)
			{
				return kv.first;
			} 
		};

仿函数实现过后,我们使用红黑树的时候直接让该仿函数的结构体作为参数传到红黑树里面。然后使用该结构体定义一个对象,对这个对象进行传参来完成区分map和set的比较。

使用红黑树封装map和set_第3张图片

二、红黑树中set和map的迭代器

end和begin迭代器



template
struct _RBTreeIterator
{
	typedef RBTreeNode Node;
}

typedef _RBTreeIterator iterator;




//提供这个普通迭代器版本是为了与map中的value能改动做照应
//最左结点作为红黑树的begin
iterator begin()
{
	Node* left = _root;
	while (left && left->_left)
	{
		left = left->_left;
	}
	return iterator(left);
}

//最右结点的右结点(即nullptr)作为红黑树的end
iterator end()
{
	return iterator(nullptr);
}

operator++迭代器

由于我们的红黑树是一个平衡二叉树的结构,当我们++的时候其实是去访问该结点中序遍历后的下一个结点,详细解释在下边代码的注释中。

typedef _RBTreeIterator iterator;
iterator& operator++()
	{

		//如果该结点的右不为空,那么++就是走到该结点右子树的最左结点
		if (_node->_right)
		{
			Node* min = _node->_right;
			while (min->_left)
			{
				min = min->_left;
			}
			_node = min;
		}

		//如果该结点的右为空,且本身是其父节点的左孩子
		//那么其父节点就是我们需要找的结点
		// 
		//如果其本身是父节点的右孩子
		//那么将顺着根节点往上去找,直到找到其结点是父结点左孩子的结点
		//然后父结点就是我们需要找的结点
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;//this结点其实就是本身
	}

operator--

operator--与operator++相反,其实就是返回中序遍历的前一个结点。具体解释在下边代码的注释中。

typedef _RBTreeIterator iterator;
iterator& operator--()
	{
		//如果该结点的左结点不为空,那么就去找左子树的最右结点
		if (_node->_left)
		{
			Node* max = _node->_left;
			while (max->_right)
			{
				max = max->_right;
			}
			_node = max;
		}

		//如果该结点的左结点为空
		//且该结点是父节点的右孩子,那么其父节点就是我们需要找的结点
		//
		//如果该结点是父节点的左孩子,那么需要顺着根节点去找
		//结点是父节点的右孩子的结点
		//该父节点就是我们需要找的结点
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_left == cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

三、set与map中的迭代器和const迭代器

set:

首先我们要明白,set是不允许改变当前结点的值的(具体原因是因为set底层是红黑树(是特殊的平衡二叉树,也满足平衡二叉树的性质),如果轻易去改变结点的值会造成该树不满足平衡二叉树的性质,如果实在需要改变,应该先删除,再插入)因此在set中,无论是普通迭代器iterator还是cosnt迭代器cosnt_iterator都需要封装成const迭代器。

//因为这个类模板没有进行实例化所以需要加上typename来说明 
//RBTree, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充
//由于set的key和value都不能改变,所以我们效仿底层将set的const迭代器和普通迭代器全部封装为const迭代器
typedef typename RBTree::const_iterator iterator;
typedef typename RBTree::const_iterator const_iterator;
iterator begin() const
{
	return _t.begin();//返回红黑树中的begin
}

iterator end() const
{
	return _t.end();//返回红黑树中的end
}

map:

在map中key是不可以改变的,但是value是可以改变的。因此我们不仅要实现普通迭代器,还要实现const迭代器。

//因为这个类模板没有进行实例化所以需要加上typename来说明 
//RBTree, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充
//由于map的value是可以改变的所以我们对map的迭代器要分清楚const迭代器和普通迭代器
typedef typename RBTree, MapKeyOfT>::iterator iterator;
typedef typename RBTree, 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();
}

四、迭代器的拷贝构造

在自定义类型中我们就学过,普通类型的值是可以赋给const类型的值的。因为这是权限的缩小。

cosnt int a=3;
int b=2;
a=b;

但是const类型的值是不可以赋给普通类型的值的。因为这是权限的放大。

a =2;
cosnt b=3;
a=b;//会报错,因为b的权限比a的权限大

迭代器亦是如此,因此我们要满足普通迭代器可以赋给const迭代器,然而const迭代器不可以赋给普通迭代器。

template
struct _RBTreeIterator
{

	typedef RBTreeNode Node;

	typedef _RBTreeIterator Self;

	//无论传过来的是T& T* 还是const T& , const T*  
	//iterator都是普通迭代器 为了满足const迭代器去构造普通迭代器
	typedef _RBTreeIterator iterator;

	Node* _node;//迭代器结构体中存放的只有一个结点的成员变量


	//构造函数
	_RBTreeIterator(Node* node)
		:_node(node)
	{}
	
	//普通迭代器的时候,他是拷贝构造
	//const迭代器的时候,他是构造,支持用普通迭代器构造cosnt迭代器
	_RBTreeIterator(const iterator& s)
		:_node(s._node)
	{}
}

五、完整代码

其中还包含了一些我没有单独拿出来解释的一些知识,但是都在完整代码中注释中一一解释。

set.h

#pragma once
#include"RBTree.h"

namespace bit
{
	template
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		//因为这个类模板没有进行实例化所以需要加上typename来说明 
		//RBTree, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充
		//由于set的key和value都不能改变,所以我们效仿底层将set的const迭代器和普通迭代器全部封装为const迭代器
		typedef typename RBTree::const_iterator iterator;
		typedef typename RBTree::const_iterator const_iterator;

		
		iterator begin() const
		{
			return _t.begin();//返回红黑树中的begin
		}
		
		iterator end() const
		{
			return _t.end();//返回红黑树中的end
		}



		pair insert(const K& key)
		{
			pair::iterator, bool>ret = _t.Insert(key);
			return pair(ret.first, ret.second);
		}
	private:
		RBTree _t;
	};

	void test_set()
	{
		int a[] = { 1,2,3,4,5,6,7,8};
		set s;
		for (auto e : a)
		{
			s.insert(e);
		}

		set::iterator it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

map.h 

#pragma once
#include"RBTree.h"

namespace bit
{
	template
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		//因为这个类模板没有进行实例化所以需要加上typename来说明 
		//RBTree, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充
		//由于set的key和value都不能改变,所以我们效仿底层将set的const迭代器和普通迭代器全部封装为const迭代器
		typedef typename RBTree::const_iterator iterator;
		typedef typename RBTree::const_iterator const_iterator;

		
		iterator begin() const
		{
			return _t.begin();//返回红黑树中的begin
		}
		
		iterator end() const
		{
			return _t.end();//返回红黑树中的end
		}



		pair insert(const K& key)
		{
			pair::iterator, bool>ret = _t.Insert(key);
			return pair(ret.first, ret.second);
		}
	private:
		RBTree _t;
	};

	void test_set()
	{
		int a[] = { 1,2,3,4,5,6,7,8};
		set s;
		for (auto e : a)
		{
			s.insert(e);
		}

		set::iterator it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

RBTree.h

#pragma once

//给出枚举变量,以便于方便区分红黑结点
enum Colour
{
	RED,
	BLACK,
};

template
struct RBTreeNode
{
	T _data;
	RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;
	Colour _col;

	RBTreeNode(const T& data)
		:_data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _col(RED)
	{}
};
//template
//struct _RBTreeIterator
//{
//	typedef RBTreeNode Node;
//}
template
struct _RBTreeIterator
{

	typedef RBTreeNode Node;

	typedef _RBTreeIterator Self;

	//无论传过来的是T& T* 还是const T& , const T*  
	//iterator都是普通迭代器 为了满足const迭代器去构造普通迭代器
	typedef _RBTreeIterator iterator;

	Node* _node;//迭代器结构体中存放的只有一个结点的成员变量


	//构造函数
	_RBTreeIterator(Node* node)
		:_node(node)
	{}
	
	//普通迭代器的时候,他是拷贝构造
	//const迭代器的时候,他是构造,支持用普通迭代器构造cosnt迭代器
	_RBTreeIterator(const iterator& s)
		:_node(s._node)
	{}

	// *就是解引用因此返回该结点的成员变量
	Ref operator*()
	{
		return _node->_data;
	}


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

	//typedef _RBTreeIterator Self;
	//重载的是前置++
	Self& operator++()
	{

		//如果该结点的右不为空,那么++就是走到该结点右子树的最左结点
		if (_node->_right)
		{
			Node* min = _node->_right;
			while (min->_left)
			{
				min = min->_left;
			}
			_node = min;
		}

		//如果该结点的右为空,且本身是其父节点的左孩子
		//那么其父节点就是我们需要找的结点
		// 
		//如果其本身是父节点的右孩子
		//那么将顺着根节点往上去找,直到找到其结点是父结点左孩子的结点
		//然后父结点就是我们需要找的结点
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;//this结点其实就是本身
	}


	Self& operator--()
	{
		//如果该结点的左结点不为空,那么就去找左子树的最右结点
		if (_node->_left)
		{
			Node* max = _node->_left;
			while (max->_right)
			{
				max = max->_right;
			}
			_node = max;
		}

		//如果该结点的左结点为空
		//且该结点是父节点的右孩子,那么其父节点就是我们需要找的结点
		//
		//如果该结点是父节点的左孩子,那么需要顺着根节点去找
		//结点是父节点的右孩子的结点
		//该父节点就是我们需要找的结点
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_left == cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	bool operator != (const Self& s) const
	{
		return _node != s._node;//其实_node为this._node只不过this省略了 本意就是返回自己的结点!=传入结构体的结点
	}

	bool operator == (const Self& s) const
	{
		return _node == s._node;//其实_node为this._node只不过this省略了 本意就是返回自己的结点==传入结构体的结点
	}


};


// map->RBTree,MapKeyOfT> _t;
// set->RBTree _t;


//增加一个KeyOfT是为了使用map的时候把pair中的key取出来
//T刚好是从map或者set传进来的VALUE map--pair  set--K
template
class RBTree
{
	typedef RBTreeNode Node;
public:
	typedef _RBTreeIterator iterator;
	typedef _RBTreeIterator const_iterator;


	//提供这个普通迭代器版本是为了与map中的value能改动做照应
	//最左结点作为红黑树的begin
	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
		return iterator(left);
	}

	//最右结点的右结点(即nullptr)作为红黑树的end
	iterator end()
	{
		return iterator(nullptr);
	}

	//const版本的  begin和end 迭代器
	const_iterator begin() const
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
		return const_iterator(left);
	}

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

	//如果这个值在,那么这个insert充当的就是查找我们就返回这个结点的迭代器
	//
	pair Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return make_pair(iterator(_root),true);
		}

		//利用从map或者set中传过来的类定义一个kot对象
		//由于该类中重载了"()" 所以kot()其实就是调用了operator()函数
		//往kot()括号中传递参数就是给operator()()第二个括号里面传递参数
		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->_col = RED;
		if (kot(parent->_data) < kot(data))
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}


		//调整
		while (parent && parent->_col == RED)
		{
			Node* grandfater = parent->_parent;
			if (grandfater->_left == parent)
			{
				Node* uncle = grandfater->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfater->_col = RED;
					cur = grandfater;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_left)//无论是否有uncle 都这样旋转     //直线
					{
						RotateR(grandfater);
						parent->_col = BLACK;
						grandfater->_col = RED;
					}
					else
					{
						RotateL(parent);
						RotateR(grandfater);
						cur->_col = BLACK;
						grandfater->_col = RED;
					}
					break;
				}
			}
			else
			{
				Node* uncle = grandfater->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfater->_col = RED;

					cur = grandfater;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)//无论是否有uncle 都这样旋转     //直线
					{
						RotateL(grandfater);
						parent->_col = BLACK;
						grandfater->_col = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(grandfater);
						cur->_col = BLACK;
						grandfater->_col = RED;
					}
					break;
				}
			}
		}
		_root->_col = BLACK;
		return make_pair(iterator(newnode), true);;
	}

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

			subL->_parent = ppNode;
		}
	}

	void Inorder()
	{
		_Inorder(_root);
	}

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

		_Inorder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_Inorder(root->_right);
	}

	bool Check(Node* root, int blackNum, const int ref)
	{
		if (root == nullptr)
		{
			//cout << blackNum << endl;
			if (blackNum != ref)
			{
				cout << "违反规则:本条路径的黑色节点的数量跟最左路径不相等" << endl;
				return false;
			}

			return true;
		}

		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "违反规则:出现连续红色节点" << endl;
			return false;
		}

		if (root->_col == BLACK)
		{
			++blackNum;
		}

		return Check(root->_left, blackNum, ref)
			&& Check(root->_right, blackNum, ref);
	}

	bool IsBalance()
	{
		if (_root == nullptr)
		{
			return true;
		}

		if (_root->_col != BLACK)
		{
			return false;
		}

		int ref = 0;
		Node* left = _root;
		while (left)
		{
			if (left->_col == BLACK)
			{
				++ref;
			}

			left = left->_left;
		}

		return Check(_root, 0, ref);
	}

private:
	Node* _root = nullptr;
};


template
struct SetKeyOfT
{
	const K& operator()(const K& key)
	{
		return key;
	}
}; 
void testRBTree()
{
	//不能让普通迭代器给给const迭代器 因为这是权限的放大
	/*const RBTree> t;
	RBTree>::iterator it = t.begin();*/




	//可以让const迭代器给给普通迭代器 因为这是权限的缩小
	RBTree> t;
	RBTree>::const_iterator it = t.begin();


	list::iterator sit;
	list::const_iterator cit = sit;
	


}

你可能感兴趣的:(数据结构,c++,算法,数据结构,红黑树)