探索STL中的set及map的定位原理

本文通过分析C++ STL源码,详细解释了使用自定义双CString键值在set容器中出现计数阻塞的原因,并展示了如何正确实现比较运算符以避免此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章的由来是由于今天自己的一个非常低级的错误,我需要以一个双CString作为key来插入到set中,所以自己定义了了如下:

struct MsgSubscribeName
{
	MsgSubscribeName(){}
	MsgSubscribeName(CString _systemName, CString _msgName):SystemName(_systemName), MsgName(_msgName)
	{}
	bool operator< (const MsgSubscribeName& right)const
	{		if(SystemName != right.SystemName || MsgName != right.MsgName)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	CString SystemName;
	CString MsgName;
};

 

之所以那么去定义operator < 是由于如果不定义这个,很抱歉,是没有办法插入的,因为无法为operator <(const set& XX,const set& XXXX)操作进行模板推演的,当时没也没考虑到判等操作,想反正operator只用来定位插入位置,那么大小也没关。。。结果插入正常,开心,运行起后,发现代码居然阻塞在set<MsgSubscribeName>::count。。。悲剧了,第一反应是死循环了,但是比较纳闷为什么count会死循环。

开始怀疑set和map之类的定位判等操作,网上搜索,无过,问好友set如何利用less进行key的判等定位,也是表示不清楚,只好硬着头皮看STL的源码。。。

 

 

 
size_type count(const _K& _Kv) const
{return (_Tr.count(_Kv)); }

size_type count(const _K& _Kv) const
{
_Paircc _Ans = equal_range(_Kv);
size_type _N = 0;
_Distance(_Ans.first, _Ans.second, _N);
return (_N); }  
_Pairii equal_range(const _K& _Kv)
       {return (_Pairii(lower_bound(_Kv), upper_bound(_Kv))); } 
const_iterator upper_bound(const _K& _Kv) const
                {return (iterator(_Ubound(_Kv))); }  
_Nodeptr _Ubound(const _K& _Kv) const
                {_Nodeptr _X = _Root();
                _Nodeptr _Y = _Head;
                while (_X != _Nil)
                        if (key_compare(_Kv, _Key(_X)))
                                _Y = _X, _X = _Left(_X);
                        else
                                _X = _Right(_X);
                return (_Y); }  
const_iterator lower_bound(const _K& _Kv) const
 {return (const_iterator(_Lbound(_Kv))); }

 


这是整个调用栈,可以清晰的看出,count是基于UBound和LBound来进行断定,根据我手工模拟草算结果Ubound相当于标定了end迭代的效果,而LBound相当于标定beign迭代的效果,此时,计算这对所谓的迭代器就可以得到当前count的元素的个数,在set和map中,这个显然是0或1.UBound == Lbound时,就相当于标定了一对end迭代器效果。

重点就放在_Ubound函数,看看这个函数是如何推到出_Kv的最大下标(即end迭代器),首先我们必须要明白一个众所周知的基本,STL中的set以及map在多数STL版本中是基于RBTree实现的,那么此时看这个代码,就相当明晰,_X定位到Root,进入while后,如果_Kv小于_X,则_X置为左子树根节点,因为所有的左子树节点均要小于根,这个是排序二叉树的基本常识,此时,继续往下走,如果大于则去右子树。这样就能得到end迭代。 同理推导_Lbound得到begin迭代

 

最后总结一下,根据源码分析可以看出,其实count的计算是基于一组迭代器的减法操作,而这组迭代器的获取是基于上述的_Lbound和_Ubound得出,可以看出,set和map利用RBTree是十分高效的进行二分查找定位,因为RBTree是平衡树!!

擦,8点了,要回去了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值