27 map和set封装

map和set可以采用两套红黑树实现,也可以用同一个红黑树,就需要对前面的结构进行修改
迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代器,需要考虑以前问题:

  • begin()和end()

stl明确规定,begin和edn代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一个有序序列,因此:begin可以放在红黑树中最小节点(即最左侧节点)的位置,end放在最大结点(最右侧节点)的下一个位置,关键是最大节点的下一个位置在哪?如果给成nullptr,end的–操作要能找到最后一个元素的位置,最好的方式是将end放在头节点的位置

在这里插入图片描述

迭代器结构

在红黑树中提供一个迭代器类,提供基本的*,->,++,–等运算符重载。变量时一个节点指针,用节点来初始化迭代器
在这里插入图片描述
加入上面构造的好处
固定的普通迭代器初始化这个迭代器类,参数模板都用T,如果T传入的是普通迭代器,就是拷贝构造,如果是cosnt迭代器,就支持用普通迭代器隐式转换常量迭代器,保证set的key不能修改

++和–

迭代器的++是按中序遍历的顺序找到下一个元素,遵循中序的原则。规则是:当前节点判断它的右节点有没有节点,如果有,就找到右子树中最小的,也就是最左的结点。如果是空,就看它是双亲的左还是右,如果是左,按中序原则就到它的父亲位置,如果是右,说明这颗子树遍历完毕,向上重复直到找到cur是par的左节点的时候,如果到end的位置就结束

self& operator++()
{
	//1.右不为空,找右树最左节点
	if (_node->_right != nullptr)
	{
		node* subleft = _node->_right;
		while (subleft->_left)
		{
			subleft = subleft->_left;
		}

		_node = subleft;
	}
	else
	{
		//2.右为空,沿着路径找孩子是父亲左的祖先
		node* cur = _node;
		node* parent = cur->_parent;
		while (parent && parent->_right == cur)
		{
			cur = parent;
			parent = parent->_parent;
		}

		_node = parent;
	}

	return *this;
}

–和++的操作是镜像的,左为空,找是右子树的结点

self& operator--()
{
	//1.左不为空,找左树最右节点
	if (_node->_left != nullptr)
	{
		node* subright = _node->_left;
		while (subright->_right)
		{
			subright = subright->_right;
		}

		_node = subright;
	}
	else
	{
		//2.左为空,沿着路径找孩子是父亲右的祖先
		node* cur = _node;
		node* parent = cur->_parent;
		while (parent && parent->_left == cur)
		{
			cur = parent;
			parent = parent->_parent;
		}

		_node = parent;
	}

	return *this;
}

enum color
{
	RED,
	BLACK
};
template <class T>
struct TreeNode
{
	struct TreeNode<T>* _parent;
	struct TreeNode<T>* _left;
	struct TreeNode<T>* _right;
	T _data;
	color _col;

	TreeNode(T data)
		:_parent(nullptr), _left(nullptr), _right(nullptr)
		, _data(data), _col(RED)
	{}
};
template <class T, class Ref, class Ptr>
struct __RBTreeIterator
{
	typedef TreeNode<T> node;
	typedef __RBTreeIterator<T, Ref, Ptr> self;
	node* _node;
	__RBTreeIterator(node* cur)
		:_node(cur)
	{}
	//普通迭代器,当迭代器是普通时是拷贝构造,是const迭代器时支持普通转换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& x)
	{
		return x._node != _node;
	}

	self& operator++()
	{
		//1.右不为空,找右树最左节点
		if (_node->_right != nullptr)
		{
			node* subleft = _node->_right;
			while (subleft->_left)
			{
				subleft = subleft->_left;
			}

			_node = subleft;
		}
		else
		{
			//2.右为空,沿着路径找孩子是父亲左的祖先
			node* cur = _node;
			node* parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

	self& operator--()
	{
		//1.左不为空,找左树最右节点
		if (_node->_left != nullptr)
		{
			node* subright = _node->_left;
			while (subright->_right)
			{
				subright = subright->_right;
			}

			_node = subright;
		}
		else
		{
			//2.左为空,沿着路径找孩子是父亲右的祖先
			node* cur = _node;
			node* parent = cur->_parent;
			while (parent && parent->_left == cur)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

};

begin和end

红黑树提供begin和end功能,begin返回最左的元素,也就是最小的值。end返回空迭代器

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);
}

const_iterator begin() const
{
	//中序第一个,最左节点
	node* cur = _root;
	while (cur && cur->_left)
	{
		cur = cur->_left;
	}
	return const_iterator(cur);
}

iterator end()
{
	return iterator(nullptr);
}

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

insert返回值

insert的返回值返回pair,第一个参数是iterator,第二个参数插入成功或失败,如果插入成功,就返回插入位置,插入失败,就返回已经存在的数据位置

insert比较

set是比较key的值,而map传入的值是pair,pair本身的比较规则是先比较first,first相等比较second。而我们想要的是只比较first,所以要统一两个的比较方法
在这里插入图片描述
在这里插入图片描述

模板里传入一个KeyOfT,是一个仿函数,根据不同的T的类型,取到set和map用于比较的元素

std::pair<iterator, bool> insert(const T& data)
{
	KeyOfT kot;
	if (_root == nullptr)
	{
		_root = new node(data);
		_root->_col = BLACK;
		return std::make_pair(iterator(_root), true);
	}

	node* parent = nullptr;
	node* cur = _root;
	while (cur)
	{
		parent = cur;
		if (kot(data) < kot(cur->_data))
		{
			cur = cur->_left;
		}
		else if (kot(data) > kot(cur->_data))
		{
			cur = cur->_right;
		}
		else
		{
			return std::make_pair(iterator(cur), false);;
		}
	}
	//插入
	cur = new node(data);
	node* newnode = cur;
	cur->_parent = parent;
	if (data < parent->_data)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}

	//父节点是红色调整
	while (parent && parent->_col == RED)
	{
		node* gdparent = parent->_parent;
		node* uncle;

		if (gdparent->_left == parent)
		{
			uncle = gdparent->_right;
			//第一种情况 叔叔节点是红色,变色
			if (uncle && uncle->_col == RED)
			{
				parent->_col = uncle->_col = BLACK;
				gdparent->_col = RED;
			}
			//第二种情况 分左右
			//     g
			//  par  un
			// cur
			else
			{
				if (cur == parent->_left)
				{
					RotateRight(gdparent);
					parent->_col = BLACK;
					gdparent->_col = RED;
				}
				//     g
				//  par  un
				//    cur
				else
				{
					RotateLeft(parent);
					RotateRight(gdparent);
					cur->_col = BLACK;
					parent->_col = RED;
					gdparent->_col = RED;
				}

				break;
			}
		}
		else
		{
			uncle = gdparent->_left;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = uncle->_col = BLACK;
				gdparent->_col = RED;
			}
			else
			{
				if (cur == parent->_right)
				{
					RotateLeft(gdparent);
					parent->_col = BLACK;
					gdparent->_col = RED;
				}
				//     g
				//  par  un
				//    cur
				else
				{
					RotateRight(parent);
					RotateLeft(gdparent);
					cur->_col = BLACK;
					//parent->_col = RED;
					gdparent->_col = RED;
				}

				break;
			}
		}

		cur = gdparent;
		parent = cur->_parent;
	}

	//根必须是黑色
	_root->_col = BLACK;
	return std::make_pair(iterator(newnode), true);;
}

set和map的仿函数如下:

struct SetOfK
{
	const K& operator()(const K& key)
	{
		return key;
	}
};
struct SetOfV
{
	const K& operator()(const std::pair<const K, V>& kv)
	{
		return kv.first;
	}
};

#pragma once
#include <iostream>
#include <assert.h>
#include <queue>

template <class K, class T, class KeyOfT>
class RBTree
{
	typedef TreeNode<T> node;
public:
	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);
	}

	const_iterator begin() const
	{
		//中序第一个,最左节点
		node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return const_iterator(cur);
	}

	iterator end()
	{
		return iterator(nullptr);
	}

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

	node* find(const K& key)
	{
		KeyOfT kot;
		if (_root == nullptr)
		{
			return nullptr;
		}

		node* cur = _root;
		while (cur)
		{
			if (kot(key) < kot(cur->_data))
			{
				cur = cur->_left;
			}
			else if (kot(key) > kot(cur->_data))
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}

		return nullptr;
	}

	std::pair<iterator, bool> insert(const T& data)
	{
		KeyOfT kot;
		if (_root == nullptr)
		{
			_root = new node(data);
			_root->_col = BLACK;
			return std::make_pair(iterator(_root), true);
		}

		node* parent = nullptr;
		node* cur = _root;
		while (cur)
		{
			parent = cur;
			if (kot(data) < kot(cur->_data))
			{
				cur = cur->_left;
			}
			else if (kot(data) > kot(cur->_data))
			{
				cur = cur->_right;
			}
			else
			{
				return std::make_pair(iterator(cur), false);;
			}
		}
		//插入
		cur = new node(data);
		node* newnode = cur;
		cur->_parent = parent;
		if (data < parent->_data)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}

		//父节点是红色调整
		while (parent && parent->_col == RED)
		{
			node* gdparent = parent->_parent;
			node* uncle;

			if (gdparent->_left == parent)
			{
				uncle = gdparent->_right;
				//第一种情况 叔叔节点是红色,变色
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					gdparent->_col = RED;
				}
				//第二种情况 分左右
				//     g
				//  par  un
				// cur
				else
				{
					if (cur == parent->_left)
					{
						RotateRight(gdparent);
						parent->_col = BLACK;
						gdparent->_col = RED;
					}
					//     g
					//  par  un
					//    cur
					else
					{
						RotateLeft(parent);
						RotateRight(gdparent);
						cur->_col = BLACK;
						parent->_col = RED;
						gdparent->_col = RED;
					}

					break;
				}
			}
			else
			{
				uncle = gdparent->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					gdparent->_col = RED;
				}
				else
				{
					if (cur == parent->_right)
					{
						RotateLeft(gdparent);
						parent->_col = BLACK;
						gdparent->_col = RED;
					}
					//     g
					//  par  un
					//    cur
					else
					{
						RotateRight(parent);
						RotateLeft(gdparent);
						cur->_col = BLACK;
						//parent->_col = RED;
						gdparent->_col = RED;
					}

					break;
				}
			}

			cur = gdparent;
			parent = cur->_parent;
		}

		//根必须是黑色
		_root->_col = BLACK;
		return std::make_pair(iterator(newnode), true);;
	}

	void RotateLeft(node* parent)
	{
		node* sub = parent->_right;
		node* subl = sub->_left;

		sub->_left = parent;
		parent->_right = subl;

		//父节点修改
		node* Pparent = parent->_parent;
		parent->_parent = sub;
		//有子节点改变指向
		if (subl)
		{
			subl->_parent = parent;
		}

		if (parent == _root)
		{
			_root = sub;
		}
		else
		{
			//原parent在父节点的左右
			if (Pparent->_left == parent)
			{
				Pparent->_left = sub;
			}
			else
			{
				Pparent->_right = sub;
			}
		}

		sub->_parent = Pparent;

	}

	void RotateRight(node* parent)
	{
		node* sub = parent->_left;
		node* subr = sub->_right;

		sub->_right = parent;
		parent->_left = subr;

		if (subr)
		{
			subr->_parent = parent;
		}

		node* Pparent = parent->_parent;
		parent->_parent = sub;

		if (parent == _root)
		{
			_root = sub;
		}
		else
		{
			if (Pparent->_left == parent)
			{
				Pparent->_left = sub;
			}
			else
			{
				Pparent->_right = sub;
			}
		}

		sub->_parent = Pparent;
	}

	bool IsBalance()
	{
		if (_root->_col == RED)
		{
			std::cout << "根节点是红色" << std::endl;
			return false;
		}

		int refVal = 0;  //记录最左路径黑色节点的数量,用来参考
		node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				refVal++;
			}

			cur = cur->_left;
		}

		return _IsBalance(_root, 0, refVal);
	}

	bool _IsBalance(node* cur, int blackNum, int refVal)
	{
		if (cur == nullptr)
		{
			//判断每条路径黑色节点数量正常
			if (blackNum != refVal)
			{
				std::cout << "黑色节点数量不相等" << std::endl;
				return false;
			}
			return true;
		}

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

		if (cur->_col == RED && cur->_parent->_col == RED)
		{
			std::cout << cur->_kv.first << " 连续红色节点" << std::endl;
		}

		return _IsBalance(cur->_left, blackNum, refVal)
			&& _IsBalance(cur->_right, blackNum, refVal);
	}

	void layer()
	{
		if (_root == nullptr)
		{
			return;
		}

		std::queue<node*> q;
		q.push(_root);
		int lay = 1;

		while (!q.empty())
		{
			std::cout << "第" << lay << "层: ";
			int num = q.size();
			while (num--)
			{
				node* cur = q.front();
				q.pop();
				std::cout << cur->_kv.first << " 颜色:" << cur->_col << "  ";
				if (cur->_left != nullptr)
				{
					q.push(cur->_left);
				}
				if (cur->_right != nullptr)
				{
					q.push(cur->_right);
				}
			}

			lay++;
			std::cout << std::endl;
		}
		std::cout << std::endl;
	}

	void inorder()
	{
		_inorder(_root);
		std::cout << std::endl;
	}
	void _inorder(node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_inorder(root->_left);
		std::cout << root->_kv.first << " ";
		_inorder(root->_right);
	}

	int size()
	{
		return _size(_root);
	}

	int _size(node* node)
	{
		if (node == nullptr)
		{
			return 0;
		}

		return _size(node->_left) + _size(node->_right) + 1;
	}

	int TreeHeight()
	{
		return _TreeHeight(_root);
	}

	int _TreeHeight(node* node)
	{
		if (node == nullptr)
		{
			return 0;
		}

		int lhight = _TreeHeight(node->_left);
		int rhight = _TreeHeight(node->_right);

		return lhight > rhight ? lhight + 1 : rhight + 1;
	}

private:
	node* _root = nullptr;
};

set

在这里插入图片描述
两个参数都用K初始化,传入仿函数
在这里插入图片描述
普通迭代器也用const,保证key不被修改,typename用来区分是一个类还是变量类型

#pragma once
#include "RBTree.h"

template <class K>
class set
{
	struct SetOfK
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};

public:
	//typename 区分是类还是变量
	typedef typename RBTree<K, K, SetOfK>::const_iterator iterator;
	typedef typename RBTree<K, K, SetOfK>::const_iterator const_iterator;


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

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

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

private:
	RBTree<K, K, SetOfK> _t;
};

map

在这里插入图片描述
map第一个是K,用来erase,find等函数接口是key,它的数据类型是pair

V& operator[](const K& key)
{
	std::pair<iterator, bool> ret = _t.insert(make_pair(key, V()));
	return ret.first->second;
}

map提供[]操作,返回key位置的值,并可以对自身修改

#pragma once
#include <iostream>
#include "RBTree.h"

template <class K, class V>
class map
{
	struct SetOfV
	{
		const K& operator()(const std::pair<const K, V>& kv)
		{
			return kv.first;
		}
	};

public:

	typedef typename RBTree<K, std::pair<const K, V>, SetOfV>::iterator iterator;
	iterator begin()
	{
		return _t.begin();
	}

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

	std::pair<iterator, bool> insert(const std::pair<const K, V> kv)
	{
		return _t.insert(kv);
	}

	V& operator[](const K& key)
	{
		std::pair<iterator, bool> ret = _t.insert(make_pair(key, V()));
		return ret.first->second;
	}

private:
	RBTree<K, std::pair<const K, V>, SetOfV> _t;
};

整体结构

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值