set/map浅谈

set/map浅谈

前言

  • STL中的容器主要分成序列式容器以及关联式容器
  • 序列式容器主要包括vector, deque, list, stack, queue等等
  • 关联式容器主要包括了set, map等等
  • 关联式容器的显著特征是每个元素都对应着一个键值对, 一个key, 一个value, 关联式容器没有所谓的头部和尾部, 所以自然也就没有front, back等方法

set

  • STL之中的set作为有序的集合, key具有唯一性, key会被自动排序
  • set的key就是value, value也就是key
  • STL之中专门为set提供了一些算法 —— 求交集, 并集, 差集等
  • set的底层采用红黑树, 几乎所有set的方法都是在调用底层rbtree的方法实现
  • set的迭代器有点意思, 定义为如下:
typedef typename rep_type::const_iterator iterator;
  • set的迭代器是将红黑树的const迭代器定义之, 所以我们不能通过set的迭代器来改变set的元素值
  • set的insert方法实际上就是在调用底层红黑树的insert_unique方法

注:
红黑树提供了2种插入方法:

  1. insert_unique:
    插入的节点必须在元素节点中唯一, 不然插入操作无法进行
  2. insert_equal:
    插入的节点的key可以重复, 这个适用于multiset/multimap
  • 对于insert, 返回值其实也是蛮有意思的, 看代码:
set<int> s = { 1, 2, 3 };
auto res = s.insert(1); // 返回的是一个pair<iterator, bool>, 插入成功返回true并且iterator指向插入的元素, 失败返回false并且iterator指向set中与这个插入值相同的那个元素, 这一点可以有时候简化我们的编程
cout << res.second << endl; // false
  • 对于指定位置的insert和插入一段区间的insert返回值则不是pair, 注意区分
  • 对于multiset插入基本上总能成功, 所以insert返回值并不会带有bool值
  • 对于set内部也实现了find, count, lower_bound等方法, 使用set内部的方法会比泛型算法中的执行更有效率

map

  • map也是一种会自动按照key排序的容器, map不允许存在2个一样的key
  • map的底层采用的也是红黑树, map的迭代器并不像set的迭代器一样被定义成const, 所以map的迭代器可以修改value, 但是通过迭代器也无法修改map的key

注:
因为map的元素需要按照key进行排列, 如果可以通过iterator修改key就会破坏map的排列

  • 对于map其实很多地方和set很相似, 同样的insert(pair)会返回一个pair<iterator, bool>, 也定义了find, count等方法
  • 对于multimap由于总能插入成功, 所以insert的返回值不带有bool值
  • map和set都无法通过下标遍历, 如果想要遍历, 要么通过iterator, 要么使用auto c++11的语法
  • 要说map和set显著的一个区别就是map重载了[]运算符
T& operator[] (const key_type& k) {
	return (*((insert(value_type(k, T()))).first)).second;
}
  • 下面是我对于[]运算符的解释:
	[]实际上就是调用了insert方法, 之前说过map的insert(pair)返回一个pair<iterator, bool>,
	并且map不允许key重复
	因此分2种情况:
	1. key不在map的keys中:
		和set类似, 插入会成功, 迭代器指向插入的那个元素, bool为true, 源代码中的first实际上就是取出了这个元素的迭代器, 之后解引用取second, 由于返回值是T&, 故通过右值可以进行增加value
	2. key已经和map的keys重复:
		和set类似, 插入会失败, 迭代器指向map中已经存在的那个元素, 这个时候解引用取second, 同样因为返回值是T&, 但此时由于内部元素已经存在, 实际上就是在更改key所对应的value

注意

  • 由于set和map都是底层使用红黑树, 内部都有自动排序, 所以我们的key必须是可排序的类型才行
  • 举个栗子, 如果我们自己定义了一个class, 我们将其作为map的key此时是会出错的
  • 为了可以正确编译, 我们可以自己写一个仿函数即函数对象, 重载operator()自定义排序的规则, 下面举个栗子:
class P {
public:
	int parama = 1;
	int paramb = 1;
};

class CMP {
public:
	bool operator()(const P& pa, const P& pb) const{
		return pa.parama < pb.parama;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值