1.什么是map和set
map和set
就是二叉树的value和key模型
map是value模型 set是key模型
map和set都是基于红黑树实现的
红黑树具有平衡性质
那么思考一下 算法库里面的find函数和STL里面的find函数有什么区别
2.函数find
iterator find( const Key& key ); const_iterator find( const Key& key ) const;
算法里面的find是暴力搜索 一个一个搜索 时间复杂度是O(n)
但是STL的find只用搜索高度次就可以了实践复杂度是O(logn)(红黑树具有平衡性质)
参数:key 是要查找的元素的值。 返回值: 如果找到与 key 相等的元素,返回指向该元素的迭代器。 如果未找到,返回指向 std::set 容器末尾的迭代器(即 end())。
set可以实现去除(把重复的数据剔除)
map可以实现重复出现的数据统计次数
此外set的迭代器遍历默认是中序遍历
3.函数lower_bound
用于在 std::set 中查找第一个不小于给定值的元素。
参数:key 是用于查找的参考值。 返回值: 如果 std::set 中存在不小于 key 的元素,返回指向第一个这样元素的迭代器。 如果 std::set 中所有元素都小于 key,则返回 std::set::end()
4.函数upper_boundhan
用于在 std::set 中查找第一个大于给定值的元素。
参数:key 是用于查找的参考值。 返回值: 如果 std::set 中存在大于 key 的元素,返回指向第一个这样元素的迭代器。 如果 std::set 中所有元素都小于等于 key,则返回 std::set::end()。
为啥lower_bound是找<=
而upper_boundhan是找>
这样设计的好处是什么
好处是我如果erase的区间是(itlow,itup)
刚好涵盖了25到60(包括25和60)的全部数
5.函数equal_range
参数:key 是要查找的键值。 返回值:返回一个 std::pair 对象
其中 first 是指向第一个不小于 key 的元素的迭代器(等同于 lower_bound(key) 的返回值)
second 是指向第一个大于 key 的元素的迭代器(等同于 upper_bound(key) 的返回值)。
在 std::set 中,如果 key 存在,first 指向该元素,second 指向该元素的下一个位置;
如果 key 不存在,first 和 second 相等,都指向第一个大于 key 的元素(或者在没有更大元素时指向 std::set::end())。
这个接口在set上是没有意义的 但是为了保持统一就保留了 但是在multiset上是有意义的
6.multiset
multiset和普通set的区别在哪?
普通set是排序+去重的功能
而multiset是排序的功能
那么思考一下 如果multiest可以插入多个同样的值
那么我们find函数找到的是第一个insert的吗?
答案不一定
find找到的是中序遍历第一个找到的
multiset其他接口和set是一样的
7.map和set区别
map和set的key都是不可以被修改的
但是map的value是可以被修改的!
map和set处理方式是iterator和const_iterator的是实现都是const_iterator
那么map是怎么处理的呢?
但是区别是map的value_type是pair类型的
pair的定义
放在map中 first就是const key_type second就是mapped_type
first代表的就是key key是不能改变的 second就是value是可以改变的
这个地方为什么不弄两个模板参数 而是要把key和value单独放到一个类里面呢?
当我们去写operator*的时候 我们返回值要写*得到的东西
但是这个地方应该返回key和value 但是C++只能返回一个值啊!
所以我们就把它们封装起来放到pair这个类里面去了
同理 我们发现pair也没有重载流插入和流提取
我们无法直接打印pair对象
但是可以这样写用.或者→
8.如何使用map
那我们再来思考一下怎么使用map(以insert为例子 其他同理)
(1)make_pair
既然要传pair类型过去
我就直接通过make_pair这个函数造一个pair传过去
map<string, string> aaa;
aaa.insert(make_pair("abc", "def"));
那么这个地方make_pair会产生效率问题吗?
不会 因为make_pair会被编译器处理成内联函数
(2) pair
我们自己写一个pair传过去也可以
map<string, string> aaa;
pair<string, string> bbb("abc","abc");
aaa.insert(bbb);
(3)匿名对象
当然匿名对象也可以
map<string, string> aaa;
aaa.insert(pair<string, string> ("abc", "abc"));
(4)隐式类型转换也可以
map<string, string> aaa;
aaa.insert({ "abc", "abc" });
这个地方为什么可以?
C++11增加了可以多参数的构造函数类型转换 但是前提是要加{}
这个地方原本是构造函数+拷贝构造
编译器直接优化成了构造函数了
但是+了引用就不能隐式类型转换了
为什么?
因为隐式类型转换会产生临时变量
临时变量具有常性
但是引用权限不能放大
一定要+引用必须在前面加上一个const
const pair<string, string>& bbb = {"abc","abc"};
此外
记得区分具有常性的int类型和const int类型!
当然上面的几种方法 pair函数中我们传进去的key可以不是const的 编译器会帮我们处理成const类型的