目录
1.关联式容器与序列式容器
2.pair(键值对)
3.set
构造函数
find函数
count函数:
insert函数
4.multiset
5.map
insert函数
operator[]
1.关联式容器与序列式容器
C++中关联式容器与序列式容器是两种不同的容器
1.关联式容器
关联式容器:
- 关联式容器主要包括 std::set, std::map, std::multiset, std::multimap 等。
- 这些容器是基于键值对(<key, value>结构)的概念,通过键==(key)来唯一标识元素==。
- 关联式容器内部使用二叉搜索树(通常是红黑树)或类似的数据结构,以保持元素的有序性。
- 插入、删除、查找等操作的平均时间复杂度是 O(log n)。
序列式容器:
- 序列式容器包括 std::vector, std::list, std::deque, std::array 等。
- 这些容器是基于线性结构的,元素在容器中的位置是由插入的顺序决定的。
- 插入、删除、查找等操作的平均时间复杂度因容器类型而异,但在最差情况下,可能达到 O(n)。
2.pair(键值对)
C++中有一种数据结构,他能将两种不同的数据类型给强制的绑定,形成相连关系
定义:pair包含在<utility> 的头文件中 ,其中pair中有两个成员变量 , 一个是first , 另一个就是second
STL库中pair的定义(没有具体实现swap,make_pair等函数)
template <class T1, class T2>
struct pair
{T1 first;T2 second;pair(T1 a = T1() , T2 b = T2() ) //构造函数: first(a), second(b){}pair(const T1& a, const T2& b) //拷贝构造: first(a), second(b){}
};
pair的构造函数
1.构造函数
具体代码实现请看上面
实例:
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<queue>
#include<utility>
using namespace std;
int main()
{pair<int, int> t(1, 1);pair<int, int> k;cout << t.first << " " << t.second << endl;cout << k.first << " " << k.second << endl;return 0;
}
2.拷贝构造函数
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<queue>
#include<utility>
using namespace std;
int main()
{pair<int, int> t(1, 1);// 构造函数pair<int, int> k = t;// 拷贝构造函数pair<int, int> s(t);// 拷贝构造函数cout << t.first << " " << t.second << endl;cout << k.first << " " << k.second << endl;cout << s.first << " " << s.second << endl;return 0;
}
3.make_pair函数(函数模版)
传入key , value 生成 pair , 并返回pair
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<queue>
#include<utility>
using namespace std;
int main()
{pair<string, string> t = { "abc" , "def" };t = make_pair<string,string>("afad", "fasd");cout << t.first << " " << t.second << endl;return 0;
}
3.set
- set是按照某一次序存储元素的
- set是key值模型,但也存在value(并且value = key ),set中key(value)值不能修改
- 底层使用红黑树实现的
构造函数
1.迭代器区间构造
2.拷贝构造
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{vector<string> ret = { "a" , "b" , "c" };set<string> ans(ret.begin(), ret.end());set<string> k = ans;for (auto& e : ans)cout << e << endl;return 0;
}
find函数
给定一个key,如果set中存在,返回该节点的迭代器,不存在,返回set.end()
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{vector<string> ret = { "a" , "b" , "c" };set<string> ans(ret.begin(), ret.end());auto it = ans.find("a");if (it != ans.end())cout << *it << endl;elsecout << "不存在" << endl;return 0;
}
count函数:
给定一个key值 ,如果set中存在,返回1 , 不存在,返回0(与find函数相似)
int main()
{vector<string> ret = { "a" , "b" , "c" };set<string> ans(ret.begin(), ret.end());int i = ans.count("a");if (i)cout << i << endl;else cout << i << endl;return 0;
}
insert函数
声明:pair<iterator, bool> insert(const value_type& val);
插入元素到 set 中。
如果插入成功,返回一个迭代器指向插入的位置和 true。
如果元素已经存在,返回一个迭代器指向已存在的元素和 false。
返回一个 pair 对象,包含插入的迭代器和插入是否成功的标志。
int main()
{vector<string> ret = { "a" , "b" , "c" };set<string> ans(ret.begin(), ret.end());ans.insert({ "d" });return 0;
}
- 删除一个迭代器所指向的节点
- 删除某一特定的值
- 删除某一迭代区间(左闭右开)
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{set<string> ret = { {"ab"} , {"cd"} , {"ef"} };ret.erase("ab");// 删除某一特定的值for (auto& e : ret)cout << e << endl;cout << endl;ret.insert({ "ab" });ret.erase(ret.begin());// 删除某一迭代器for (auto& e : ret)cout << e << endl;cout << endl;ret.insert({ "ab" });ret.insert({ "tt" });auto it = ret.find("tt");ret.erase(ret.begin(), it);for (auto& e : ret)cout << e << endl;return 0;
}
4.multiset
- multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。
- 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
- 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
- multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列。
- multiset底层结构为二叉搜索树(红黑树)
注意:
- multiset中再底层中存储的是<value, value>的键值对
- mtltiset的插入接口中只需要插入即可
- 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
- 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
- multiset中的元素不能修改
- 在multiset中找某个元素,时间复杂度为O ( l o g 2 N )
- multiset的作用:可以对元素进行排序
multiset 是 C++ 标准库中的关联式容器之一,属于有序容器。与 set 不同的是,multiset 允许键值重复,即可以包含相同键值的多个元素。
允许重复键值: multiset 允许容器中存在相同的键值,因此可以包含多个相同键值的元素。
有序性: 与 set 类似,multiset 也维护元素的有序性,根据键值进行排序。
当需要允许键值重复,并且希望保持元素有序时,可以选择使用 multiset。
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{vector<int> k = { 2,1,5,6,7,3,1,1,1,90 };multiset<int> ret(k.begin(), k.end());for (auto& e : ret)cout << e << " ";cout << endl;return 0;
}
5.map
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:
- 在内部,map中的元素总是按照键值key进行比较排序的。
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
5.1map 模板参数说明
- key: 键值对中key的类型
- T: 键值对中value的类型
- Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
- Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器
构造函数
1.迭代器区间构造
2.拷贝构造
insert函数
void test()
{map<int,int> ret;ret.insert({1,1});ret.insert(make_pair(1,1));auto tmp = make_pair(1,1);ret.insert(tmp);
}
operator[]
返回的是关于value的引用
1.读取元素:当使用 [] 运算符时
- 如果指定的键存在于 map 中,则返回与该键关联的值
- 如果不存在,则会插入一个新的键值对,键为指定的键,值为默认构造的对应值类型的默认值,并返回该默认值的引用
2.插入元素:当使用 [] 运算符向 map 中插入元素时
- 如果指定的键不存在,则会创建一个新的键值对,键为指定的键,值为指定的值,并返回该值的引用
- 如果键已经存在,则直接返回对应的值的引用。
#include<iostream>
#include<map>
using namespace std;
int main()
{map<int, int> ret;vector<int> ans = { 1, 2, 3, 4, 5,6 ,6,7, };for (auto& e : ans){ret[e]++;// 插入pair}for (auto& e : ret){cout << e.first << " " << e.second << endl;}ret[1] = 10; // 修改pairreturn 0;
}
erase
第一种:删除 key 为某一个值的pair
#include<iostream>
#include<map>
using namespace std;
int main()
{map<int, int> ret;vector<int> ans = { 1, 2, 3, 4, 5,6 ,6,7, };for (auto& e : ans){ret[e]++;}for (auto& e : ret){cout << e.first << " " << e.second << endl;}ret.erase(1);cout << endl;for (auto& e : ret){cout << e.first << " " << e.second << endl;}return 0;
}
第二种:删除某一迭代区间(左闭右开)
#include<iostream>
#include<map>
using namespace std;
int main()
{map<int, int> ret;vector<int> ans = { 1, 2, 3, 4, 5,6 ,6,7, };for (auto& e : ans){ret[e]++;}for (auto& e : ret){cout << e.first << " " << e.second << endl;}auto p1 = ret.find(3);auto p2 = ret.find(6);cout << endl;ret.erase(p1, p2);for (auto& e : ret){cout << e.first << " " << e.second << endl;}return 0;
}
6.multimap
multimap的基本性质
- multimap容器是和map容器相似的关联式容器,所谓“相似”,是指multimap容器具有和map容器相同的特性,即multimap容器也存储pair<const K, T>类型的键值对(其中K表示键的类型,T表示值的类型),其中各个键值对的键的值不能被修改;并且,该容器也会自行根据键的大小对所存储的所有键值对做排序操作。
- multimap容器和map容器的区别在于,multimap容器中可以同时存储多个键相同的键值对。
- multimap容器提供的成员方法,map容器都有提供,并且它们的用法是相同的。详细的用法请参照map的用法及实例详解。本文只是给出了所有在multimap中的成员函数及其实现功能,具体的实例及代码请参照map容器。
- 实现multimap容器的类模板也定义在<map>头文件,并位于std命名空间中,故使用multimap容器前,应该引入头文件:#include<map>
构造函数
创建空的multimap
multimap<int,int> ret;
创建multimap并初始化(注意用{})
multimap<int, int> ret{ { 1,1 }, { 2,3 }, { 5,6 } };
拷贝构造
multimap<int,int> ans(ret);
迭代区间构造
#include<iostream>
#include<map>
#include<climits>
using namespace std;
int main()
{multimap<int, int> ret{ { 1,1 }, { 2,3 }, { 5,6 } };multimap<int, int> ans(++ret.begin(),ret.end());for (auto& e : ans)cout << e.first << " " << e.second << endl;return 0;
}
常见成员函数和使用方法:
注意multimap并没有重载operator[]