STL 使用问题 -- 理解相等和等价的区别

本章主要理解在比较相同,stl使用的“相等” 和“等价”的两种机制。

理解相等和等价的区别
对两个对象进行比较,看它们的值是否相同,比如,通过算法库中的find在某个区间中寻找第一个等于某个值的元素时,find必须能够比较两个对象。当使用set::insert插入一个新元素到集合中,这是也许能能够确定该元素是否已经在该set中。

上面的find和insert虽然都是确定两个值是否相同,但却用的是不同的方式判断。find对相同的定义是“相等”,是以operator==为基础的;set::insert对相同的定义是“等价”,是以oparator<为基础的。因为定义不同所以用不同的方式判断两个对象是否相同,得到的结果可能是不一致的。
 

emplate<
 
class Key,
 
class Compare=std::less<Key>,
 
class Allocator=std::allocator<Key>
 
>class set;

看看set的模板怎么定义的。第一个参数使我们要存的元素的类型,第二个参数是一个比较函数对象,第三个是分配器(虽然我们可以指定,但基本上都是用默认的allocator)

这里主要看第二个参数。 当然我们在自定义key 的类中也可以重写这个oparator<。关联容器的比较函数class Compare=std::less<Key>,默认的std::less<Key>只是简单的调用了元素对象的oparator<,如果两个对象W1、W2中任何一个都不比另一个的小,则认为等价。下面时等价判断:

!(W1<W2)//W1不小于W2

&& //并且

!(W2<W1)//W2不小于W1

在一般情况下,一个关联容器的比较函数不是oparator<,甚至也不是std::less<Key>,而是使用用户定义的判别式,而是使用Compare这个用户自定义的判别式。每个标准关联容器都通过key_comp成员函数外部使用,所以如果下面的表达式为true,则按照关联容器排序准则,两个对象W1,W2是等价的:

!C.key_comp()(W1,W2)&&!C.key_comp()(W2,W1)

key_comp()是一个回调函数。两个C.key_comp()(,)函数都返回false,即是等价。

举个栗子:

为了领会这两者的区别,我们考虑一个不区分大小写的set<string>,即当set的比较函数忽略字符串中字符的大小写。

我们准备一个函数把“STL”,“stl”看作是等价的。这里我们准备一个函数类替换Set中用到的Compare。

先准备一个比较函数,不区分大小写,相等返回false, 则这里两个只有大小写不同的而字符串使用这个 !C.key_comp()(W1,W2)&&!C.key_comp()(W2,W1) 过后返回的结果是true。
 

class CIStringCompare
{
	public:
	bool operator()(const string& lhs, const string& rhs)
	{
		//int strcmp(char *s1, char *s2); 用来比较字符串,不区分大小写, 相同为0
		return stricmp(lhs.c_str(), rhs.c_str()); //不区分大小写
	}
};
 
std::set<std::string, CIStringCompare> ciss; //不区分大小写的字符串集合
//我们把字符串"STL" 和 "stl" 使用insert 插入到集合中
ciss.insert("STL");
ciss.insert("stl");
 
std::cout<<"insert:" << ciss.size()<<std::endl;
if(ciss.find("STL") != ciss.end())
{
    std::cout<<"find:"<<"STL"<<std::endl;
}
if(std::find(ciss.begin(), ciss.end(), "STL") != ciss.end())
{
    std::cout<<"std::find:"<<"STL"<<std::endl;
}
 
if(ciss.find("stl") != ciss.end())
{
    std::cout<<"find:"<<"stl"<<std::endl;
}
if(std::find(ciss.begin(), ciss.end(), "stl") != ciss.end())
{
    std::cout<<"std::find:"<<"stl"<<std::endl;
}
 
if(ciss.find("sTL") != ciss.end())
{
    std::cout<<"find:"<<"sTL"<<std::endl;
}
if(std::find(ciss.begin(), ciss.end(), "sTL") != ciss.end())
{
    std::cout<<"std::find:"<<"sTL"<<std::endl;
}

我们构造了一个存储字符串的set,然后插入“STL” 和“stl”,然后打印出set中的元素个数,同时使用是set::find 和 std::find 去在容器中查找,其 输出结果:

可以看出这里插入了一个元素,同时set::find和std::find结果不一致(所以也印证了容器的同名函数优先于同名的算法)。

排序的关联容器总是保持排列顺序的,所以每一个容器都必须有一个比较函数(默认是less)来决定顺序。因此使用者要为关联容器指定一个比较函数。对于哈希表实现的关联容器,有两种设计,一种是基于相等的,一种是基于等价的。下面看的这种是相等。

template<
    class Key,
    class Hash = std::hash<Key>,
    class KeyEqual = std::equal_to<Key>,
    class Allocator = std::allocator<Key>
> class unordered_set;


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

u010787096

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值