C C++最新C++ map的简单实现_c++ map实现,2024大厂C C++面试必问题目

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

			Node\* uncle = gfather->_right;
			//情况1.uncle存在且为红
			if (uncle && uncle->_color == RED)
			{
				parent->_color = uncle->_color = BLACK;
				gfather->_color = RED;
				//向上追溯
				cur = gfather;
			}
			else
			{
				if (parent->_right == cur)//情况3
				{
					RotateL(parent);
					swap(cur, parent);
				}
				//情况2.uncle不存在或者uncle为黑
				RotateR(gfather);
				parent->_color = BLACK;
				gfather->_color = RED;
				break;
			}
		}
		else
		{
			Node\* uncle = gfather->_left;
			if (uncle && uncle->_color == RED)
			{
				parent->_color = uncle->_color = BLACK;
				gfather->_color = RED;
				//向上追溯
				cur = gfather;
			}
			else
			{
				if (parent->_left == cur)
				{
					RotateR(parent);
					swap(cur, parent);
				}

				RotateL(gfather);
				parent->_color = BLACK;
				gfather->_color = RED;
				break;
			}
		}
	}

	//根节点为黑色
	_header->_parent->_color = BLACK;
	//更新头结点的左右指向
	_header->_left = leftMost();
	_header->_right = rightMost();
	return true;
}

void RotateL(Node\* parent)
{
	Node\* subR = parent->_right;
	Node\* subRL = subR->_left;

	parent->_right = subRL;
	if (subRL)
		subRL->_parent = parent;
	if (parent == _header->_parent)
	{
		_header->_parent = subR;
		subR->_parent = _header;
	}
	else
	{
		Node\* gfather = parent->_parent;
		if (gfather->_left == parent)
			gfather->_left = subR;
		else
			gfather->_right = subR;
		subR->_parent = gfather;
	}
	subR->_left = parent;
	parent->_parent = subR;
}

void RotateR(Node\* parent)
{
	Node\* subL = parent->_left;
	Node\* subLR = subL->_right;

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

	if (parent == _header->_parent)
	{
		_header->_parent = subL;
		subL->_parent = _header;
	}
	else
	{
		Node\* gfather = parent->_parent;
		if (gfather->_left == parent)
			gfather->_left = subL;
		else
			gfather->_right = subL;
		subL->_parent = gfather;
	}
	subL->_right = parent;
	parent->_parent = subL;
}

Node\* leftMost()
{
	Node\* cur = _header->_parent;
	while (cur && cur->_left)
	{
		cur = cur->_left;
	}
	return cur;
}

Node\* rightMost()
{
	Node\* cur = _header->_parent;
	while (cur && cur->_right)
	{
		cur = cur->_right;
	}
	return cur;
}

private:
Node* _header;
};

template<class K, class T>
class Map
{
struct MapKeyOfValue
{
const K& operator()(const pair<K, T>& val)
{
return val.first;
}
};
public:
bool insert(const pair<K, T>& kv)
{
return _rbt.insert(kv);
}

T& operator[](const K& key)
{
	bool ret = _rbt.insert(make\_pair(key, T()));
}

private:
typedef RBTree<K, pair<K, T>, MapKeyOfValue> rbt;
rbt _rbt;
};

template
class Set
{
struct SetKeyOfValue
{
const K& operator()(const K& val)
{
return val;
}
};

public:
bool insert(const K& val)
{
return _rbt.insert(val);
}

private:
typedef RBTree<K, K, SetKeyOfValue> rbt;
rbt _rbt;
};


### 迭代器


我们原生的Node结点迭代器是无法实现迭代器的普通操作的,所以我们必须要对结点进行另一层的封装,重载对应的操作运算符。在该类中只有一个成员变量,就是Node结点。


对迭代器的解引用,就是获得迭代器的val值



V& operator\*()
{
	return _node->_val;
}

对迭代器的箭头操作,就是获得迭代器值的地址



V\* operator->()
{
	return &_node->_val;
}

两个迭代器的判等操作就是结点的地址是否相同



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

迭代器的++和- -是要符合中序遍历的有序遍历,下面我们来一起分析  
 迭代器的begin()位置应该是树中最小的结点,而树中最小的结点就是树的最左结点;迭代器的end()位置应该是树中最大的结点,而树中最大的结点就是树的最右结点  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210523105853197.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)  
 迭代器的++操作分为两种情况,第一种是存在右子树的情况,第二种是不存在右子树的情况


**当存在右子树时,我们需要遍历到右子树的最左结点,然后访问该结点**。例如我们现在的迭代器在8的位置,根据中序遍历的条件,我们应该访问的是10号结点,所以我们先走到8结点的右子树11号结点,然后遍历11的最左结点,该结点为10,也正是我们要访问的结点  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210523110553326.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210523110828936.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)



	if (_node->_right)
	{
		//右子树的最左结点
		_node = _node->_right;
		while (_node->_left)
		{
			_node = _node->_left;
		}
	}

第二种情况是不存在右子树。当不存在右子树,我们需要向上回溯,中序遍历的遍历规则就是左孩子、根、右孩子。所以我们要判断当前节点是父节点的左孩子还是右孩子,**如果是左孩子则表示父节点还未访问,此时需要访问父节点;如果是右孩子则表示父节点也访问过了,需要向上回溯,直至该结点不为父节点的右孩子。**例如我们节点在5号结点的位置,需要判断该结点父节点6号结点的左边还是右边,此时5号结点再6号结点的左边,可以表示6号结点也未访问,此时将迭代器更新的父节点的位置即可。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210523111623362.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)  
 当我们迭代器在7号结点时,7号结点时在6号结点的右边,此时需要向上回溯,让结点更新置父节点,然后父节再向上回溯至其父节点的位置,再判断当前节点的位置是否为父节点的右边,此时6号结点是8号结点的左边,表示8号结点还未访问,此时访问8号结点即可  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210523112003654.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)  
 但是我们需要考虑到一种特殊的情况,就是该树的根节点没有右孩子时  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210523112436112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)


正常来说,我们对迭代器的++操作应该会移动到空的头结点的位置,但是我们再回溯的过程中会出现问题。此时因为it没有右结点,需要判断该结点是在父节点的左边还是右边,此时是在右边,就会向上回溯  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021052311294850.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)  
 这样子对迭代器的++是一个死操作,永远不会走到空的位置。所以我们需要再跟结点处做特殊的处理。当node结点的右孩子为自己的父亲时,就不用更新结点了,此时已经走到end()的了,如果还更新置parent结点,则该++操作就没有发生改变


我们现在进行测试  
 迭代器部分代码



template
struct RBTreeIterator
{
typedef RBTreeNode Node;
typedef RBTreeIterator Self;
Node* _node;

RBTreeIterator(Node\* node)
	:\_node(node)
{}

//解引用
V& operator\*()
{
	return _node->_val;
}

V\* operator->()
{
	return &_node->_val;
}

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

Self& operator++()
{
	if (_node->_right) //存在右节点
	{
		//右子树的最左结点
		_node = _node->_right;
		while (_node->_left)
		{
			_node = _node->_left;
		}
	}
	else //不存在右节点
	{
		Node\* parent = _node->_parent;
		while (_node == parent->_right)//回溯
		{
			_node = parent;
			parent = parent->_parent;
		}
		//特殊情况:根节点没有右孩子,则不需要更新结点
		if (_node->_right != parent) 
			_node = parent;
	}
	return \*this;
}

};


红黑树添加迭代器代码



typedef RBTreeIterator<V> iterator;

iterator begin()
{
	return iterator(_header->_left);
}
iterator end()
{
	return iterator(_header);
}

map中添加红黑树迭代器代码



typedef typename RBTree<K, pair<K, T>, MapKeyOfValue>::iterator iterator;

iterator begin()
{
	return _rbt.begin();
}
iterator end()
{
	return _rbt.end();
}

测试结果:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210523120144722.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)  
 这里直接给出迭代器- -的代码,原理和++类似


在迭代器类中



Self& operator--()
{
	if (_node->_left)
	{
		//右子树的最左结点
		_node = _node->_left;
		while (_node->_right)
		{
			_node = _node->_right;
		}
	}
	else
	{
		Node\* parent = _node->_parent;
		while (_node == parent->_left)
		{
			_node = parent;
			parent = parent->_parent;
		}
		if (_node->_left != parent)
			_node = parent;
	}
	return \*this;
}

在红黑树类中添加反向迭代器用于测试



iterator rbegin()
{
return iterator(_header->_right);
}


map中也添加反向迭代器



![img](https://img-blog.csdnimg.cn/img_convert/7437148d85369655baba72f88f62759f.png)
![img](https://img-blog.csdnimg.cn/img_convert/cbda64ff3988ca19a5923600c438460d.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

用于测试



iterator rbegin()
{
return iterator(_header->_right);
}


map中也添加反向迭代器



[外链图片转存中...(img-4b5CJ5uR-1715712509328)]
[外链图片转存中...(img-ZywjI8NO-1715712509328)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值