C++容器常用方法简单总结
共同方法 |
顺序容器 |
关联容器 |
iterator |
迭代器 注意vector,array,deque的迭代器可以iter+1,关联容器和链表的不能!只能自增,即iter++ (因为除链表外的顺序容器的内存地址是连续的,而链表和关联容器存储元素的地址是分散的) |
|
const_iterator |
const迭代器 |
|
value_type |
元素类型 |
|
reference |
元素左值类型,意同value_type& |
|
const_reference |
const元素左值类型 |
|
构造函数 |
||
C c |
C seq(n) C seq(n, t) //包含n个t
forward_list<string> br(ar.begin(), ar.end()); |
key_type value_type // set: 和key_type一样, map: pair<const k,v>,注意这个const eg: map<string, int>::value_type v3;
(所以一般关联容器都不用泛型算法,原因之一:多数泛型算法都要向元素写值,P383) |
C c1(c2) |
||
C c(b, e) |
||
C c{a,b,c,...} |
||
C c = {a,b,c,...} |
||
赋值与交换 |
||
c1 = c2 |
seq.assign(il) //全部替换为初始化列表il seq.assgin(n, t) // 全部替换为n个t |
|
c1 = {a,b,c} |
||
a.swap(b) |
||
swap(a, b) |
||
大小: c.size(); c.empty() |
||
增/删元素 |
||
c.insert() |
1. 特有的函数: c.push_back(t) //返回void(forward_list不支持) c.emplace_back(args) c.push_front(t) //vector, string不支持 c.emplace_front(t) 2. insert的用法(需要指明插入位置p): c.insert(p, t) //在迭代器p前插入t,返回指向第一个新插入的值的迭代器 c.insert(p, n, t) //插入n个t c.insert(p, b, e) c.insert(p, il) c.at(n) // 返回下标为n的元素引用 emplace也一样:c.emplace(p, args) 3. 删除方法: c.pop_back() // forward_list不支持 c.pop_front() //vector, string不支持 c.erase(p); c.erase(b, e) //返回指向被删元素之后的元素的迭代器,注意不删e(此外还有泛型算法的erase) |
1. 区别于顺序容器,insert不用指定插入位置(因为相对于无序容器他们本来就是有序的,会自动插入到正确的位置),对于map和set,只有当元素key不在c中时才会插入!所以为了同只插入是否成功,它要返回一个bool值来表示插入是否成功(无论是否插入成功都返回一个pair<iter, bool>,前者为指向该元素 的迭代器,后者为是否插入成功的bool值) c.insert(v) //v是value_type对象 eg: word.insert(make_pair(a, b)) 上面插入单个元素insert会返回一个pair,但下面2种方法插入多个元素时,insert返回void(因为插入的元素会在c中重新排序,散落在不同的位置) c.insert(b, e) //对于map和set只插入key不在c中 的元素 c.insert(il) c.emplace(args) 2. 删除: c.erase(k) // 删除每个关键字为k的元素,返回一个size_type类型的值:被删除的元素的数量 c.erase(p) // 删除迭代器p指定的元素,返回指向p之后的元素的迭代器 c.erase(b, e) //返回e 取下标操作:c[k] //返回关键字为k 的元素的引用(注意!如果k不在c中,则会添加一个关键字为k的元素!) c.at(k) // 访问关键字为k的元素,若k不在c中,抛出一个out_of_range异常 3. 所以我们如果要判断一个元素是否在容器中,最好使用find: c.find(k) //如果k在c中,返回指向k的迭代器,否则返回的迭代器指向c.end() c.count(k) //统计有多少个k在c中 对于map的for循环,可以这样: map<string, int> mp; for (auto &[_, time] : mp){...} |
c.emplace() |
||
c.erase() |
||
c.clear() |
顺序容器访问首尾元素的引用:
c.front() //c为空时行为未定义
c.back()
求两个迭代器b,e区间最大/最小值(不包括e在内)(返回指向第一个该最值的迭代器) (需要#include <algorithm>)
max_element(b ,e)
min_element(b, e)
取2个变量的最大/最小值:max(a,b) min(a,b)
1.reverse(str.begin(),str.end()) //反转字符串
2.reverse(vector.begin(),vector.end()) //反转向量
3.reverse(a,a+strlen(a)) //反转数组
求一个序列的上一个/下一个字典序异位序列(可用于string,vector,其他容器没试过,且不但是数字、字母,其他符号也可以用,例:leetcode 22. 括号生成 ):
prev_permutation(beg, end) //如果存在下一个/上一个,则在原beg到end的序列修改,返回true,否则返回false
set<int> st = {1,2,3,4,5,6}; auto iter1 = st.lower_bound(3); auto iter2 = st.upper_bound(3); cout << *iter1 << " " << *iter2 <<endl;
结果为: 3 4
swap不仅可以用来交换两个容器,还可以交换容器中某两个元素(可用于string, vector, array。链表能不能用?):
swap(s[i], s[j]);
string提供的其他方法:
- 除了迭代器版本的构造函数、增/删函数外,string还提供接收下标版本的函数(由下标来指明位置,而不是迭代器):
构造函数:
string s(n, c) //n个c字符
string s(cp, n) // cp是一个指向字符数组的c指针(或数组名/c字符串名),用该数组中的前n个字符初始化s(cp至少要包含n个字符)
string s(s2, pos2) //注意pos2是下标,从string s2[pos2]开始到末尾来拷贝初始化s (pos2 < s2.size()否则抛出异常)(注意s2和cp的区别!!如果是c指针(cp)则是拷贝前n个字符,如果是string(s2)则是用从pos2开始的后面的字符来进行初始化,n和pos一个是个数一个是下标)
string s(s2, pos2, len2) //从s2[pos2]开始拷贝len2个字符来初始化s (不管len2多长,最多只拷贝到s2结尾)
eg:
const char * cp = “hello world!!!”;
char noNull[] = {‘H’, ‘i’};
string s1(cp); // s1 == “hello world!!!”
string s2(noNull, 2); // s2 == “Hi”
string s3(noNull); // 异常!如果noNull不是以’\0’为最后一个字符,则必须像s2那样传入一个长度参数来确定要拷贝的长度!
string s4(cp + 6, 5); // s4 == “world”
string s5(s1, 6, 5); // s5 == “world”
string s6(s1, 6); // s6 == “world!!!”
string s7(s1, 6, 20); // s7 == “world!!!” (最多只拷贝到末尾)
string s8(s1, 16); // 抛出out of range异常
substr操作:
s1 = s.substr(pos1) //从s[pos1]开始拷贝到末尾(pos1 < s.size())
s1 = s.substr(pos, n) // 从s[pos]开始拷贝n个字符(pos默认为0,n默认为s.size()-pos,即默认拷贝所有字符)
增/删元素方法:
s.insert(pos, args) //在pos前插入args指定的字符(pos可以是下标或迭代器,如果是下标则返回指向s的引用)
s.erase(pos, len) //删除从pos开始的len个字符(如果没有len则删掉pos后面所有的字符),返回指向s的引用
s.assign(args) //将s中的字符替换为args指定的字符,返回指向s的引用
s.append(args) //将args追加到s,返回指向s的引用
s.replace(range, args) //替换range中的字符为args(range可以是下标+长度或者一对迭代器),返回指向s的引用
上面的args可以是:
str
str, pos, len
cp, len
n, c //n个c字符
b, e
初始化列表
s.insert(s.size(), 5, ‘!’) //在s尾部插入5个!号
s.erase(s.size() - 5, 5) //删除s最后5个字符
接受c风格数组/字符串的insert/assign版本:
const char *cp = “stately, plump buck”
s.assign(cp, 7) // s==”stately”
s.insert(s.size(), cp+7) // s==”stately, plump buck”
string的搜索函数(如果没找到,则返回string::npos)、数值转换、compare函数(p325-328)
s.find(args) //找args第一次出现的位置 (第一个字符位置为0,如:string name = "AnnaBelle"; auto pos1 = name.find("Ann"); //pos1=0)
s.rfind(args) //找args最后一次出现的位置
s.find_first_of(args) //找args中任何一个字符第一次出现的位置
s.find_last_of(args) //找args中任何一个字符最后一次出现的位置
s.find_first_not_of(args) //找第一个不在args中的字符
s.find_last_not_of(args) //找最后一个不在args中的字符
args是以下形式之一:
c, pos //从s中位置pos开始查找字符c,pos默认值为0
s2, pos //从s中位置pos开始查找字符串s2,pos默认值为0
cp, pos //从s中位置pos开始查找指针cp指向的一空字符结尾的C风格字符串,pos默认值为0
cp, pos, n //从s中位置pos开始查找指针cp指向的数组的前n个字符。pos和n无默认值
string的比较函数(两个string相同返回0,左边大于右边返回正数,反之负数)(此外,C库函数strcmp也可)
s.compare(args)
args是以下形式之一:
s2 比较s,s2
pos1, n1, s2 将s从pos1开始的n1个字符与s2比较
pos1, n1, s2, pos2, n2 将s从pos1开始的n1个字符与s2中从pos2开始的n2个字符比较
cp 将s与cp指向的以空字符结尾的字符数组比较
pos1, n1, cp 将s从pos1开始的n1个字符与cp指向的以空字符结尾的字符数组比较
pos1, n1, cp, n2 将s从pos1开始的n1个字符与cp指向的地址开始的n2个字符比较
数值转换函数(还有一个比较土的方法,使用 stringstream 对象写入再写出(注意写出后要对对象进行clear操作),在一个长字符串里用空格符分隔子字符串时,stringstream特别有用)
to_string(val) 返回数值val的string表示(浮点型也可以转)
stoi(s, p, b) 返回s的起始子串的数值,p是size_t指针,用来保存s中第一个非数值字符的下标,默认为0,b表示转为几进制(默认为10,即默认转为十进制数)(一般p和b都不用管)
stol(s, p, b) 例如: double s = 3.14; string ss = to_string(s); // ss = "3.140000"
stoul(s, p, b) string a = "3.14"; int aa = stoi(a); //aa = 3
stoll(s, p, b)
stoull(s, p, b)
stof(s, p)
stod(s, p)
stold(s, p)
容器适配器:stack,queue,priority_queue
size_type
value_type
container_type
A a;
A a(c); //c类型必须为A
a.empty()
a.size()
swap(a, b)
a.swap(b)
stack操作:
s.pop() //删除栈顶元素(注意不返回该元素!)
s.push(item) //将item压入栈
s.emplace(args) //同上(item由args构造)
s.top() //返回栈顶元素(注意不弹出元素!)
queue, priority_queue操作:
priority_queue的初始化: priority_queue<int, vector<int>, greater<int>> //第一个int表示
定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(即用什么容器类型来实现这个queue,Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式(指定大的还是小的放在前面),当需要用自定义数据类型或时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆(大的放在前面,也就是栈顶元素最大,越往栈低越小)
(https://blog.csdn.net/weixin_36888577/article/details/79937886)
注意,greater/less在栈和在顺序容器中的含义是不一样的!
对栈而言,greater/less意思是从栈顶到栈低升序/降序排列,把大的放在前面,less是小的放在前面!
对顺序容器而言,greater/less意思把大的/小的放在前面!所以从begin()到end()是降序/升序排列,正好跟栈反过来!
例如: sort(vt.begin(), vt.end(), greater<int>()); // 从begin()到end()降序排列
priority_queue<int, vector<int>, greater<int>> pq; // pq从栈顶到栈低升序排列
q.pop() //priority_queue, queue都有 ( 对queue而言是删除q.front(), 先进先出 )
q.front() //仅queue有
q.back() //仅queue有
q.top() //最高优先级元素(仅priority_queue有,表示排在最前面的元素,如果存储的是自定义的结构,则需要在结构里定义operator<,对于a<b,a是排在前面,也就是a更靠近栈顶 1792. 最大平均通过率)
q.push(item) //priority_queue, queue都有 (item排在队尾)
q.emplace(args) //例如需要把另一个序列中的元素全都push近队列的时候,就不用一个一个push,直接q.emplace(b, e)即可(b,e为迭代器)