文章目录
STL介绍
STL Standard template library
------标准模板库
STL
广义划分为: 容器container; 算法algorithm; 迭代器iterator
容器和算法之间通过迭代器进行无缝衔接。
STL几乎所有代码都采用了模板类或者模板函数;
STL分为六大组件:容器,算法,迭代器,仿函数,适配器,空间配置器
容器:各种数据结构:vector,list,deque,set,map;
算法:各种常见算法:sort,find,copy,for_each;
迭代器:扮演容器和算法之间的胶合剂;
仿函数:行为类似函数,可作为算法的某种策略;
//适配器:一直用来修饰容器或者仿函数或迭代器接口的东西;
//空间配置器:负责空间的配置和管理;
STL具有容器概念和容器类型,容器概念是具有名称的(容器,序列容器,关联容器等)的通用类型;容器类型是可以用于创建具体容器对象的模板(deque,list,queue,priority_queue,stack,vector,map,multimap,set,multiset(关联容器),bitset)
;以及c++新添加的forward_list,unordered_map,unordered_multimap,unordered_set,unordered_multiset.
容器
是存储其他对象的对象。被存储的对象必须是同一种类型的。但也不能将任何类型的对象存储在容器中,具体讲:类型必须是可复制构造和可赋值的。基本数据满足这些要求,当没有将复制构造函数和赋值构造函数声明为私有或保护,就可以满足。
序列容器
强调值的顺序,每个元素都有固定的位置;
关联容器
二叉树结构,各个元素没有严格意义上的顺序关系;
----map,multimap,set,multiset
set
的值类型和键相同,这意味着集合中不会有多个相同的键。multiset
和set
类似,但是可能有多个值的键相同。
map
的值和键类型不同,键是惟一的,每个键只对应一个值,同理,multimap
与map
类似,但可以一个键与多个值关联。
仿函数—函数对象—函数符
可以函数方式与()结合使用容易对象。包括了函数名,指向函数的指针和重载()运算符的类对象
迭代器
- 背景:指针可以用来遍历存储空间连续的数据结构,但是对于存储空间非连续的,就需要寻找一个行为类似指针的类,来对非数组的数据结构进行遍历。
定义:迭代器是一种检查容器内元素并遍历元素的数据类型。
迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。
迭代器(iterator)是指针(pointer)的泛化,它允许程序员用相同的方式处理不同的数据结构(容器)。
(1)迭代器类似于C语言里面的指针类型,它提供了对对象的间接访问。
(2)指针是C语言中的知识点,迭代器是C++中的知识点。指针较灵活,迭代器功能较丰富。
(3)迭代器提供一个对容器对象的访问方法,并定义了容器范围。 - 迭代器和指针的区别:
容器有迭代器类型同时拥有返回迭代器的成员。如:容器有成员begin和end,其中begin成员复制返回指向第一个元素的迭代器,而end成员返回指向容器尾元素的下一个位置的迭代器,也就是说end指示的是一个不存在的元素,所以end返回的是尾后迭代器。可以通过迭代器访问容器中的元素。
//example
vetor<int> v(10,1);
vector<int>::iterator first = v.begin();
vector<int>::iterator second = v.begin()+1;
*(first+1) == *second; //true ,指向同一个
- 容器迭代器的使用
每种容器类型都定义了自己的迭代器类型,简单说就是容器类定义了自己的iterator类型,用于访问容器内的元素。每个容器定义了一种名为iterator的类型,这种类型支持迭代器的各种行为。
常见容器:
容器类型 | 迭代器类型 |
---|---|
vector | 随机 |
deque | 随机 |
list | 双向 |
set | 双向 |
multiset | 双向 |
map | 双向 |
multimap | 双向 |
迭代器操作 | 双向 | 随机 |
---|---|---|
it++/++it/it–/–it | 支持 | 支持 |
it[n] | 不支持 | 支持 |
it+n / it-n | 不支持 | 支持 |
it+=n / it-=n | 不支持 | 支持 |
*it | 支持 | 支持 |
map虽然也支持[],但是[]内部是键,得到的是值。string也支持[]
1、array
array<int, 35> arr{3};//一个3,其他为0;
array<int, 35> ar;//35个不确定的值;{} 全为0
//arr.assign(5);
int b1 = arr.at(12);//返回容器中 n(12) 位置处元素的引用,该函数自动检查 n(12)是否在有效的范围内,如果不是则抛出 out_of_range 异常。
int b2 = arr.back();//返回容器中最后一个元素的直接引用,该函数同样不适用于空的 array 容器。
arr.begin();//返回指向容器中第一个元素的随机访问迭代器。
arr.cbegin();//和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
arr.cend();
arr.crbegin();
arr.crend();
auto b3 = arr.data();//返回一个指向容器首个元素的指针。利用该指针,可实现复制容器中所有元素等类似功能。
arr.empty();
arr.end();//返回指向容器最后一个元素之后一个位置的随机访问迭代器,通常和 begin() 结合使用。
arr.fill(2);//将 val(2) 这个值赋值给容器中的每个元素。
int b5 = arr.front();//返回容器中第一个元素的直接引用,该函数不适用于空的 array 容器。
arr.max_size();// 返回容器可容纳元素的最大数量,其值始终等于初始化 array 类的第二个模板参数 N。
arr[1];
arr.rbegin();//返回指向最后一个元素的随机访问迭代器。
arr.rend();//返回指向第一个元素之前一个位置的随机访问迭代器。
arr.size();
arr.swap(ar);//交换 array1 和 array2 容器中的所有元素,但前提是它们具有相同的长度和类型。
2、vector
//vector
//初始化方法
vector<int> v1;
vector<int> v2(10,1);
vector<int> v3(v2.begin(),v2.begin()+3);
vector<int> v5{1,2,3,4,5};
//其他
v2.assign(2,6); //重新分配,2个6
v2.at(1); //等价与v2[1]
v2.back();//返回v2的最后一个元素
v2.begin();//返回v2的开始迭代器
v2.capacity();//返回容量---容量的意思是,当容器中元素个数大于容量时,会自动进行扩容。
v2,cbegin();
v2.cend();
v2.clear();//清除v2所有元素
v2.crbegin();
v2.crend();
auto *p =v2.data();//返回一个指针指向容器第一个元素所在的内存。
v2.emplace(v2.begin(),1);
v2.emplace_back(2);//尾部插入
v2.empty();//判断是否为空
v2.end();//v2的尾迭代器,指向最后一个元素的后面一个
v2.erase(v2.begin());//删除迭代器指向元素
v2.erase(v2.begin()+1,v2.begin()+3);//删除迭代器区间元素[a,b)
v2.front();//返回第一个元素
//v2.get_allocator();
v2.insert(v2.begin(),3);//在指定位置插入指定元素
v2.max_size();//返回最大可能的容器大小
vector<int> v4 = v2;
v2[1];
v2.pop_back();//删除最后一个元素
v2.push_back(11);//在末尾添加指定元素
v2.rbegin();//返回的是一个反向的随机访问迭代器。指向最后一个元素的迭代器,即 v2.rbegin()+1 ---指向倒数第二个元素的迭代器
v2.rend();//返回的是一个反向的随机访问迭代器。指向第一个元素前一个位置的迭代器,即 v2.rbegin()-3 ---指向第三个元素的迭代器
v2.reserve(20);//容器预留len个元素长度,预留位置不初始化,元素不可访问。在调用默认构造函数后,就使用。
v2.resize(11);//重新制定容器长度为num。若容器长度变长,则以默认值0填充新位置,若变短,删除超出元素。
v2.resize(19,99);//若变长,以99填充
v2.shrink_to_fit();//收缩到合适大小
v2.size();//返回容器大小
v2.swap(v1);//互换
3、string
//string
//初始化方法
string s1("abcd");
char c[] = "bcd";
string s2(c);
string s3(c,2);//c的前两个字符
string s3(s1);
string s33(s1.begin(),s1.end());
string s4(5,'a');
//其他
string s = "abcdefabcdef";
s.append("gh");//s后面追加dsdd
s.assign("abcdefabcdef");
s += "sdd";
cout << s << endl;
s.at(1);
s[1];
s.back();//返回最后一个元素
s.begin();
s.c_str();//返回char *
s.capacity();
s.clear();
s.compare("abc");//比较大小,s大返回值大于0,s小返回值小于0,相等返回0
s.copy(c,3,2);//将s的第2个位置开始的3个元素copy给c的开始3个位置上,若c的这些位置有元素,则覆盖。
s.cbegin();
s.cend();
s.crbegin();
s.crend();
s.data();//Return const pointer to contents. This is a handle to internal data. Do not modify or dire things may happen.即返回s最开始元素的地址;注意不等于s的地址,是索引0的地址
s.empty();
s.end();
s.erase(s.begin());
s.erase(s.begin(),s.begin()+1);
s.find('s',0);
s.find("bcdef",0,4);//从s的0索引开始,寻到“bcdef”的前四个组成的子串;找到返回子串的首字符索引,否则,返回npos。
s.find_first_not_of("mn",2);//从 pos=2开始,在此字符串中查找不包含在"mn"中的字符首次出现的位置。如果未找到,则返回npos。
s.find_first_of("def",1);//从pos开始,在s中查找"def"中任何一个字符首次出现的位置
s.find_last_not_of("defs",2);//从pos开始,在此字符串中查找不包含在"defs"中的字符最后一次出现的位置。
s.find_last_of("de",1);//从pos开始,在s中查找"de"中任何一个字符最后一次出现的位置。
s.front();
//s.get_allocator();
s.insert(3,"s");//在s的索引3处插入s
s.insert(2,5,'s');//在s的索引2插入5个s
s.insert(2,s1);//在s的索引2插入s1
s.length();//返回字符串中的字符数
s.max_size();//返回最大可能的容器大小
s.npos;//18446744073709551615UL,一般在函数失败,返回该值,最大允许长度
//++,=,[]
s.pop_back();
s.push_back('s');
s.rbegin();//返回指向字符串的最后一个字符。迭代是在反向元素中完成的命令
s.rend();//返回指向字符串中的第一个字符前一个位置。迭代是反向进行的元素顺序。
s.replace(1,2,"aaa");//替换从s的索引1开始的两个元素为aaa,相当于删除索引1开始的2个元素,然后在索引1处插入aaa
s.reserve(100);//尝试为指定数量的字符预先分配足够的内存,与容量挂钩
s.resize(10);
s.rfind("cd",8);//从索引0开始到8结束,向后搜索此字符串。如果找到,则返回字符串索引0的元素在s中对应子串最后一次结果的索引。即在s中找到cd的话,返回最后一次结果的字母c在s中的索引,不写后面的8,就是在整个s上搜索
s.shrink_to_fit();//收缩大小到合适
s.size();
s.substr(1,3);//返回子串从索引1开始的3个,
s.swap(s1);//交换两者内容
4、deque
//deque 双端数组
//初始化方法
deque<int> deq1;
deque<int> deq2(5,2);
deque<int> deq3(deq2.begin(),deq2.begin()+3);
deque<int> deq4(deq2);
//其他
deque<int> deq(10,1);
deq.assign(9,2);//相当于=,赋值
deq.at(1);
deq.back();//返回最后一个元素值
deq.begin();//返回第一个元素的迭代器
deq.clear();//删除所有元素
deq.empty();//判断是否为空
deq.end();
deq.erase(deq.begin());
deq.erase(deq.begin(),deq.begin()+2);
deq.front();//返回第一个元素
deq.insert(deq.begin(),3);
deq.insert(deq.begin(),3,5);//在指定迭代器出插入3个5;
deq.insert(deq.begin(),deq2.begin(),deq2.begin()+3);//在指定迭代器位置插入deq2的前3个元素;
deq.max_size();//返回容器容量
deq.pop_back();//删除最后一个元素
deq.pop_front();//删除第一个元素
deq.push_back(3);//在尾部添加元素3
deq.push_front(1);//在头部添加元素1
deq.rbegin();//指向最后一个元素的迭代器,方向从后往前
deq.rend();//指向第一个元素的前一个位置的迭代器,方向从后往前
deq.resize(7);//重定size,大于原来的补0,多了删尾;
deq.size();
deq.swap(deq2);//交换
deq=deq2;
deq[2];
5、queue
//queue
//初始化方法
queue<int> que1;
queue<int> que2(que1);
//其他
que1.back();//返回队列的最后一个元素,前提非空
que1.emplace(1);//类似于push,但是也有细微区别。
que1.empty();//判断队列是否为空
que1.front();//返回队列最前面的元素
que1.pop();//弹出队列最前面的元素
que1.push(1);//向队列末尾加入元素
que1.size();//队列大小
que1.swap(que2);//交换两个队列
6、priority_queue
//优先队列默认从大到小
//包含在queue中,没有priority_queue头文件
priority_queue<int,vector<int>,std::greater<int>> p;//从小到大
//第一个int是数据类型,第二个vector<int>是实现类型,第三个是优先级,less<int>实现从大到小(默认)
//这里的从大到小或者是从小到大,是出队列的顺序。
priority_queue<int> pd(2, 1);
priority_queue<int> pdd(pd);
pd.emplace(3);
pd.empty();
pd.pop();
pd.push(0);
pd.size();
pd.swap(pdd);
pd.top();
7、stack
//stack
//初始化
stack<int> sta1;
stack<int> sta2(sta1);
//其他
sta1.emplace(1);//类似于push
sta1.empty();
sta1.pop();//弹出栈顶元素
sta1.push(2);//入栈
sta1.size();
sta1.swap(sta2);
sta1.top();//返回栈顶元素
8、list
双向链表
//list
//初始化
list<int> lis1;
list<int> lis2(3,5);
list<int> lis3(lis1);
//其他
lis1.assign(4,3);
lis1.assign(lis2.begin(), lis2.end());//重新分配值
lis1.back();//返回最后一个元素,前提容器非空
lis1.begin();//返回第一个元素的迭代器
lis1.cbegin();//返回指向起始的常量迭代器---常量迭代器相对于原来的对应迭代器,就是不能使用* 来修改值
lis1.cend();//返回指向末尾的常量迭代器
lis1.clear();//清空
lis1.crbegin();//返回指向起始的逆向常量迭代器
lis1.crend();//返回指向末尾的逆向常量迭代器
lis1.emplace(lis1.begin(),2);//有点等价insert(),不同在于:若链表存储的是一些对象之类的,emplace()可以直接传入参数,不需要像insert插入对象,需要先创建对象,在传给insert,
lis1.emplace_back(1);//同上,等价于push_back()
lis1.emplace_front(3);//同上,等价于push_front()
lis1.empty();//判断是否为空
lis1.end();//返回指向末尾的迭代器
lis1.erase(lis1.begin());//删除指定迭代器位置的节点
lis1.front();//返回第一个节点的元素值
lis1.insert(lis1.begin(),1);//在指定位置插入指定节点
lis1.max_size();// //返回list能容纳的最大元素数量
lis1.merge(lis2);将lis2 合并在lis1后面(lis2为空)
lis1.pop_back();//删除最后一个元素
lis1.pop_front();//删除第一个元素
lis1.rbegin();//返回指向起始的逆向迭代器--即指向最后一个元素,++方向是向链表前移动,即++一次,指向倒数第二个元素
lis1.remove(1);//删除元素值为1的节点
lis1.remove_if([](int i) { return (i > 5 || i < 3); });//删除大于5或者小于3的节点
lis1.rend();//返回指向末尾的逆向常量迭代器--即指向第一个元素前一个位置,--,即按链表向后移动一个,指向第一个元素
lis1.resize(20);//重新指定容器大小,若大于原来大小,则大于部分默认值填充,若小于原来大小,删除多的部分节点
lis1.reverse();//翻转容器
lis1.size();//返回容器大小
lis1.sort();//进行排序,可以传入参数(Lambda表达式,仿函数),实现从大大到小,或者从小到大
lis1.splice(lis1.begin(), lis2);//执行完后,在lis1 插入lis2,lis2 为空;即将原始数据加入,insert是副本加入
lis1.splice(lis1.begin(), lis2, ++lis2.begin());//将lis2的指定节点剪切到lis1的指定位置,lis2的指定节点会被删除;
lis1.splice(lis1.begin(), lis2, ++lis2.begin(),lis2.end());//将lis2的指定区间节点剪切到lis1的指定位置,lis2的指定区间节点会被删除;
lis1.swap(lis2);//容器交换
lis1.unique();删除list中相邻重复的元素,若不相邻,不会删除,可以先排序,在使用该函数;因为涉及判断是否相等,故对于保存自定义类型的,需要传入比较方法,
9、forward_list
单向链表
forward_list<int> l1;
forward_list<int> l2(3,4);
forward_list<int> l3(l1);
l1.assign({1,2,3,4,5});
auto a1 = l1.before_begin();//返回一个随机访问迭代器,它指向 forward_list 的第一个元素之前的位置
auto a2 =l1.begin();//返回一个随机访问迭代器,它指向 forward_list 的第一个元素
auto a3 = l1.cbefore_begin();//返回一个常量随机访问迭代器,它指向 forward_list 的第一个元素之前的位置。不能用于修改它所指向的对象的内容
auto a4 = l1.cbegin();
auto a5 = l1.cend();
l1.clear();
l1.emplace_after(l1.cbefore_begin(), 1);//l1是空的时候,使用l1.begin()会报错
l1.emplace_front(0);//在 forward_list 的开头构造并插入新元素,并将列表的大小增加 1
l1.empty();
l1.end();
l1.erase_after(l1.begin(),l1.end());// ,(]区间。从 forward_list 中删除元素范围并修改 forward_list 的大小。
l1.front();
//l1.get_allocator(); //返回与 forward_list 关联的分配器
l1.insert_after(l1.begin(),1);//通过在后面插入新元素来扩展迭代器位置在 forward_list。该成员函数增加了 forward_list 的大小。
l1.max_size();//返回 forward_list 可以容纳的最大元素数。此值取决于系统或库实现。
//void merge (forward_list&& x, Compare comp);
l1.merge({1,2});
l3 = l2;
l1.pop_front();
l1.push_front(6);
l1.remove(1);//从 forward_list 中删除与值匹配的元素,并通过删除的元素数减小 forward_list 的大小。
l1.remove_if([](int a) {return a % 3==0; });//从满足条件的 forward_list 中删除元素。它删除所有元素谓词返回真。
l1.resize(10,5);//改变 forward_list 的大小。如果n小于当前大小,则额外的元素被销毁。如果n大于当前容器大小,则在列表末尾插入新元素。如果值指定然后新元素被初始化值。
l1.reverse();//颠倒 forward_list 中存在的元素的顺序。
l1.sort();
l1.splice_after(l1.begin(),l3,l3.begin(),l3.end());//(]
l1.swap(l2);
l1.unique();//从 forward_list 中删除所有连续的重复元素。它用二元谓词用于比较。
10、map/multimap
//map/multimap ----二叉树实现,自动根据键排序
//初始化
map<int, int> m1;
map<int, int> m2(m1);
map<int, int> m3(m1.begin(), m1.end());
//其他
m1[1] = 20;//添加键值对<1,20>
int num = m1[2];//如果键2不存在,会自动添加,并会返回默认值
//使用[]注意事项:[]中的是键,假设是m2是是<string,string>类型的键值对,则m2["d"] = "ewew";使用[]来查看值,也是一样的道理,若查询的键不存在,会赋值给该键以默认的值,重点就是,使用[]查询,可能就往容器添加了新的键值对
m1.at(1) = 100;
m1.at(0);
//对at而言,若at里的参数是不存在,就会报异常,无论是赋值还是查询。故at只能修改和查询已经存在的键对应的值
m1.begin();//返回指向map头部的迭代器
m1.cbegin();//返回指向map中第一个元素的const迭代器。
m1.cend();//返回指向末尾的常量迭代器。
m1.clear();
m1.count(1);//返回指定元素出现的次数(0 or 1)
m1.crbegin();//返回指向末尾的常量反向迭代器。
m1.crend();//返回指向起点的常量反向迭代器。
auto n1 = m1.emplace(3,300);//n1.first是插入键值对的,n1.second 是bool值,表示插入有没有成功,若没有成功,则说明已经存在相同键的键值对,first就返回这个已经存在键值对的迭代器;见下面:
auto n1 = m1.emplace(make_pair(6, 600));//等价于auto n1 = m1.emplace(make_pair(int(6), int(600)));
auto n2 = m1.emplace_hint(m1.end(),7,700);//基本同上
auto n4 =m1.try_emplace(1,111);//try_emplace若键不存在则插入,若键存在则不做任何事,感觉和emplace()没区别
//会用emplace()就可以了吧!!
//仅当键不存在时才进行插入
//这两种函数直接在 map 容器中的指定位置构造该键值对。
m1.insert(m1.begin(),pair<int, int>(4, 200));
m1.insert(pair<int, int>(4, 200));//先创建该键值对,然后再将该键值对复制或者移动到 map 容器中的指定位置;但是map是有序的,所以指定位置其实没有用
//比较之下,emplace的效率更高,都会返回一个对组,第一个是插入值的迭代器,第二个是表示是否成功
m1.empty();
m1.end();//返回指向map末尾的迭代器
auto n3 = m1.equal_range(5);//equal_range根据键值,返回一对迭代器的pair对象。如果该键值在容器中存在,则pair对象中的第一个迭代器指向该键关联的第一个实例,第二个迭代器指向该键关联的最后一个实例的下一位置。如果找不到匹配的元素,则pair对象中的两个迭代器都将指向此键应该插入的位置。n3.first,n3.second都是iterator
m1.erase();
auto tem = m1.find(1);//查找键是给定值得键值对,若查询到,则返回对应键值对的iteratior,若没找到,返回end();
//m1.get_allocator();//返回用于构造map的分配器对象。
m1.insert_or_assign(3);//插入元素,或若键已存在则赋值给当前元素
m1.key_comp();//返回比较键的仿函数
m1.lower_bound(2);//返回键>=给定元素的第一个位置的迭代器
m1.max_size();//返回map的最大容量。
m2 = m1;
m1.rbegin();//返回一个指向map尾部的逆向迭代器
m1.rend();//返回一个指向map头部的逆向迭代器
m1.size();
m1.swap(m2);
m1.upper_bound(3);//返回键>给定元素的第一个位置的迭代器
m1.value_comp();//返回值比较的仿函数。
//m1._Unchecked_begin();
//m1._Unchecked_end();
//m1._Unchecked_end_iter();
//multimap相比于map区别在于,multimap可以插入重复键的键值对,map有的函数,multimap基本都有,因为multimap有重复键,故不能使用[];
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
int main() {
unordered_map<int, string> hash;
auto n1 = hash.emplace(1, "sas");
auto n2 = hash.emplace(1, "sas1");
cout << "n1.first->first: " << n1.first->first << endl;//1
cout << "n1.first->second: " << n1.first->second << endl;//"sas"
cout << "n2.first->first: " << n2.first->first << endl;//1
cout << "n2.first->second: " << n2.first->second << endl;//"sas"
cout << "n1.second: " << n1.second << endl;//1
cout << "n2.second: " << n2.second << endl;//0
return 0;
}
11、unordered_map
//unordered_map
//初始化
unordered_map<int, int> m1;
unordered_map<int, int> m2(m1);
unordered_map<int, int> m3{ {1,100},{2,200} };//或者使用键值对p1,p2初始化
unordered_map<int, int> m4 = m1;
m1[1] = 100;
m1[2] = 200;
int n1 = m1[3];
//对[]来说,[]里是键,查询时,若查询的键不存在,则会自己添加默认值的键值对,即执行完,容器内就多了这样一个键值对
auto n2 = at(2);
m1.at(2) = 20;//对at而言,不能查询和修改不存在的键,若不存在,会警告
//其他
m1.begin();//迭代器,不在注释
auto n2 = m1.bucket(1);
auto n3 = m1.bucket_count();
auto n4 = m1.bucket_size(4);
//对bucket而言,返回给定值的对应哈希值;bucket_count()是返回有多少个bucket,bucket_size(),是返回给定值对应bucket的大小;
m1.cbegin();
m1.cend();
m1.clear();
auto n5 = m1.count(1);//返回指定元素出现的次数
m1.emplace(4,400);
m1.emplace_hint();
m1.try_emplace();
//emplace的使用方法和上面的map基本相同,直接对应map里面使用即可。
m1.empty();
m1.end();
m1.equal_range();//同map
m1.erase();//同map
auto n6 = m1.find(1);//查找键是给定值得键值对,若查询到,则返回对应键值对的iteratior,若没找到,返回end();
//m1.get_allocator();//返回用于构造map的分配器对象。
m1.hash_function();//返回哈希函数
m1.insert();//(iterator,待插入的pair),因为unordered_map无序,故指定迭代器位置可以。
m1.insert_or_assign();//插入元素,或若键已存在则赋值给当前元素
m1.key_eq();//返回key的相等性谓词
m1.load_factor();//返回load factor,即容器当前元素数量与桶数量之比
//m1.lower_bound();//没有提供,不能使用
m1.max_bucket_count();//返回桶的最大数量
auto m7 = m1.max_load_factor();//管理每个桶的平均元素数量的最大值
m1.max_size();//容量
m1.rehash();//设置桶的数量,并重新对元素进行哈希映射
m1.reserve();//请求保留桶的数量至给定值
m1.size();//容器大小
m1.swap(m2);//交换
//m1.upper_bound();//没有提供,不能使用
//m1._Unchecked_begin();
//m1._Unchecked_end();
总结:map/multimap/unordered_map选择:
容器 | 底层实现 | 数据是否有序 | 数据是否重复 | 是否可以修改 | 查询效率 | 删除效率 |
---|---|---|---|---|---|---|
map | 红黑树 | key有序 | 否 | 键不可修改,值可以 | O(logn) | O(logn) |
multimap | 红黑树 | key有序 | 是 | 键不可修改,值可以 | O(logn) | O(logn) |
unordered_map | 哈希表 | key无序 | 否 | 键不可修改,值可以 | O(1) | O(1) |
12、set/multimset
//set/multimset
//初始化
set<int> s1;
set<int> s2(s1);
set<int> s3(s1.begin(),s1.end());
//其他
s1.begin();
s1.cbegin();
s1.cend();
s1.clear();
s1.count(1);//统计指定元素个数,set不能出现重复的元素,故只能0 or 1
s1.crbegin();
s1.crend();
s1.emplace(1);//类似于insert,作用和前面容器一样
s1.emplace_hint();
s1.empty();
s1.end();
auto n3 = s1.equal_range();//equal_range根据给定值,返回一对迭代器的pair对象n3。如果该给定值在容器中存在,则pair对象n3中的n3.first指向该元素值的迭代器,n3.second指向该元素的下一位置迭代器。如果找不到匹配的元素,则pair对象中的两个迭代器都将指向此键应该插入的位置。first,second都是iterator
s1.erase(1);//括号里面就是待删除的值
s1.find(2);//查找指定元素,若没找到,返回end(),找到就返回对应迭代器
//s1.get_allocator();
s1.insert();//类似map
s1.key_comp();//返回key比较谓词的吧!
s1.lower_bound();//二分查找一个有序数列,返回第一个大于等于x的数,如果没找到,返回末尾的迭代器位置
s1.max_size();
s1.rbegin();
s1.rend();
s1.size();
s1.swap();
s1.upper_bound();//二分查找一个有序数列,返回第一个大于x的数,如果没找到,返回末尾的迭代器位置
s1.value_comp();//返回value比较谓词的吧!
13、unordered_set
//unordered_set
//初始化
unordered_set<int> us1;
unordered_set<int> us2(us1);
//其他
us1.begin();
us1.bucket(1);
us1.bucket_count();
us1.bucket_size(3);
//对bucket而言,返回给定值的对应哈希值;bucket_count()是返回有多少个bucket,bucket_size(),是返回给定值对应bucket的大小;
us1.cbegin();
us1.cend();
us1.clear();
us1.count(1);
us1.emplace();
us1.emplace_hint();
us1.empty();
us1.end();
us1.equal_range();//
us1.erase(1);//括号里是待删除的值
us1.find(2);//括号里是待查找的值
//us1.get_allocator();
us1.hash_function();//返回哈希函数
us1.insert();//
us1.key_comp();//
us1.key_eq();//返回key的相等性谓词
us1.load_factor();///返回load factor,即容器当前元素数量与桶数量之比
us1.lower_bound();//
us1.max_bucket_count();//返回桶的最大数量
us1.max_load_factor();//返回load factor,即容器当前元素数量与桶数量之比
us1.max_size();
us1.rehash();//设置桶的数量,并重新对元素进行哈希映射
us1.reserve();//请求保留桶的数量至给定值
us1.size();
us1.swap(us2);
us1.upper_bound();//
us1.value_comp();
总结:set/multiset/unordered_set选择:
容器 | 底层实现 | 数据是否有序 | 数据是否重复 | 是否可以修改 | 查询效率 | 删除效率 |
---|---|---|---|---|---|---|
set | 红黑树 | 有序 | 否 | 不可修改 | O(logn) | O(logn) |
multiset | 红黑树 | 有序 | 是 | 不可修改 | O(logn) | O(logn) |
unordered_set | 哈希表 | 无序 | 否 | 不可修改 | O(1) | O(1) |
14、函数对象(仿函数)
重载函数调用操作符的类,其对象称为函数对象----原因在于,函数对象使用重载()时,行为类似函数,本质是一个类,不是一个函数。
–函数对象使用时,可以像普通函数那般调用,可以有参数,返回值。
class ADD {
public:
int operator()(int a, int b) {
return a + b;
}
};
main(){
ADD add;
int sum = add(10, 10);
}
函数对象超过普通函数的概念,函数对象可以有自己的状态----利用类成员记录状态;
class myadd{
public:
myadd(){ count = 0};
int operator()(int a,int b){
count++;
return a+b;
}
private:
int count;
};
–函数对象可以作为参数传递
int doadd(myadd& ad,int v1,int v2){
return ad(v1,v2);
}
15、Lambda
谓词
—即返回值类型为bool的函数对象—若operator()接受一个参数,称为一元谓词,,两个,称为二元谓词;一般用于比较大小,相等的算法时,当做参数传入。如判断struct的大小,这种自定义的类型判断时,需要自己定义比较函数即谓词即仿函数。
Lambda函数:用途类似函数对象,
vector<int> a{ 1,2,3,4,5,6,7,8 };
auto sum = count_if(a.begin(), a.end(), [](int x) -> bool {return x % 3 == 0; });
Lambda函数格式:
[capture](parameters) multable ->return-type{statement}
仅当Lambda表达式只有一条返回语句,不用写返回类型,可以自动类型推导,否则使用返回类型后置 ->return-type
。
Lambad 函数的 [ ]
功能:在[]
中 ,使用[z]
,Lambad可以按值访问
变量z;[&z]
, 则可以按引用访问
;[&]
,可以按引用访问所有
的动态变量,[=]
,可以按值访问所有
的动态变量;所有指的是代码前面出现的变量,当然也可以结合起来用,[z,&] —即按值访问z,按引用访问其他变量。
multable 位置,若不写,则默认Lambda函数是const,mutable可以取消常量性。在使用multable时,必须有参数;
vector<int> a{ 1,2,3,4,5,6,7,8 };
int count3 = 0;
std::for_each(a.begin(), a.end(), [&count3](int x) { count3 += (x % 3 == 0); });
//现在 count3 = 2
16、STL中的常见算法
#include<algorithm>
vector<int> v1{ 2,1,3,5,9,6,4,2,1 };
auto a = find_if(v1.begin(), v1.end(), [](int a) {return a >3;}); //vector<int>::iterator a
auto b = find(v1.begin(), v1.end(), 9);
auto c = adjacent_find(v1.begin(), v1.end());//查找到相等的相邻元素
sort(v1.begin(), v1.end());
auto d = binary_search(v1.begin(), v1.end(), 3);//二分查找某个元素是否存在,返回bool值,只能在有序数组进行使用。
int e = count(v1.begin(), v1.end(), 2);//返回待查找元素出现的次数
auto f = count_if(v1.begin(), v1.end(), [](int a) {return a % 3 == 0; });//按条件统计满足条件的元素个数
sort(v1.begin(), v1.end(), [](int a, int b) {return a > b; });//现在是从大到小排列,对于自定义类型的数据,排序方式要自己写;
random_shuffle(v1.begin(), v1.end());//随机调整次序
reverse(v1.begin(),v1.begin()+4);//翻转指定范围的元素