C++容器常用方法简单总结

共同方法

顺序容器

关联容器

iterator

迭代器  注意vector,array,deque的迭代器可以iter+1,关联容器和链表的不能!只能自增,即iter++ (因为除链表外的顺序容器的内存地址是连续的,而链表和关联容器存储元素的地址是分散的)

const_iterator

const迭代器

value_type

元素类型

reference

元素左值类型,意同value_type&

const_reference

const元素左值类型

构造函数

C c

  1. 只有顺序容器的构造函数能接受大小参数n

C seq(n)

C seq(n, t)  //包含nt

  1. 用一个容器初始化另一个容器时容器类型和元素类型都必须相同!但范围初始化时可以不同(只要元素能相互转换)eg:
    vector<const char*> ar = {“a”, “ab”};

forward_list<string> br(ar.begin(), ar.end());

  1. 特有的类型:

key_type

value_type // set: key_type一样,

map: pair<const k,v>,注意这个const
map_type  //只有map才有,即v

eg:

map<string, int>::value_type v3;

  1. 注意虽然set的迭代器类型为分为iterator, const_iterator,但实际上两者都是只读类型!

(所以一般关联容器都不用泛型算法,原因之一:多数泛型算法都要向元素写值,P383)

C c1(c2)

C c(b, e)

C c{a,b,c,...}

C c = {a,b,c,...}

赋值与交换

c1 = c2

  1. 特有的函数:
    seq.assign(b, e)  //seq的所有元素替换为迭代器b,e范围中的元素(不用管seq原来有多少元素)

seq.assign(il)  //全部替换为初始化列表il

seq.assgin(n, t)  // 全部替换为nt

 

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)  //插入nt

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不用指定插入位置(因为相对于无序容器他们本来就是有序的,会自动插入到正确的位置),对于mapset,只有当元素key不在c中时才会插入!所以为了同只插入是否成功,它要返回一个bool值来表示插入是否成功(无论是否插入成功都返回一个pair<iter, bool>,前者为指向该元素 的迭代器,后者为是否插入成功的bool值)

c.insert(v)  //vvalue_type对象

eg: word.insert(make_pair(a, b))

上面插入单个元素insert会返回一个pair,但下面2种方法插入多个元素时,insert返回void(因为插入的元素会在c中重新排序,散落在不同的位置)

c.insert(b, e) //对于mapset只插入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)  //如果kc中,返回指向k的迭代器,否则返回的迭代器指向c.end()

c.count(k)  //统计有多少个kc

对于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)

将区间[beg,end)内的元素全部逆序(用于顺序容器):

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

next_permutation(beg, end)
 
prev(it,n)   // 返回距离迭代器it前n个位置的迭代器(如果不填n则默认为1)  常常这样用: prev(s2.end())   // 表示指向最后一个元素的迭代器,相当于s2.rbegin()
next(it,n)  // 返回距离迭代器it后n个位置的迭代器(如果不填n则默认为1)
begin(c)   //返回指向数组的第一个元素的指针
end(c)    //返回指向数组的最后一个元素的下一个位置指针
 
count_if(beg, end, lambda)  // 返回序列中使lambda为true的元素的数量,如果找不到则返回end
find(beg, end, target)   //若找不到target则返回end迭代器
find_if(beg, end, lambda)  //返回第一个使lambda为true的元素
accumulate(beg, end, 0)  //0表示设置初始累加值为0
sort(beg, end, lambda)    //按照lambda表达式为true排序
 unique(beg, end)
 for_each...
fill(beg, end, val)  // 将beg到end(不含end)的元素替换为val
fill_n(beg, n, val)  // 将beg开始的n个元素全部替换为val,注意beg后(包括beg在内)必须至少有n个元素空间
copy(beg, end, beg2)   // 将beg到end范围内的元素拷贝到从迭代器beg2开始的另一个容器中(注意该容器要容得下这么多元素)
replace(beg, end, val1, val2)  //将beg到end范围内的元素中值为val1的元素替换为val2
c.erase(remove_if(c.begin(), c.end(), lambda), c.end())   // remove_if去除指定的字符,剩余字符往前靠.注意他实际上没有删除元素,而是返回指向第一个应被删除的元素的迭代器,所以后面要使用erase删掉,这样比用for循环去一个个删除快得多,而且还不容易错乱
 
用于顺序容器(必须先排好序):
lower_bound(beg, end, val)  // “小于val的边缘”,也就是beg到end第一个小于等于val的元素,返回他的迭代器,如果没有则返回end
upper_bound(beg, end, val)  //“大于val的边缘”,也就是beg到end第一个大于等于val的元素,返回他的迭代器,如果没有则返回end
 
用于关联容器(相当于二分查找的找左右端点):
c.lower_bound(k)  // 返回第一个关键字大于等于k的元素的迭代器 (注意和上面的含义完全相反!!) (相当于二分查找左端点)
c.upper_bound(k)  // 返回第一个关键字大于k的元素的迭代器                                                                  (相当于二分查找右端点)
例如:
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提供的其他方法:

  1. 除了迭代器版本的构造函数、增/删函数外,string还提供接收下标版本的函数(由下标来指明位置,而不是迭代器)

构造函数:

string s(n, c)  //n个c字符

string s(cp, n)  // cp是一个指向字符数组的c指针(或数组名/c字符串名),用该数组中的前n个字符初始化scp至少要包含n个字符)

string s(s2, pos2)  //注意pos2是下标,从string s2[pos2]开始到末尾来拷贝初始化s (pos2 < s2.size()否则抛出异常)注意s2cp的区别!!如果是c指针(cp)则是拷贝前n个字符,如果是string(s2)则是用从pos2开始的后面的字符来进行初始化,npos一个是个数一个是下标

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)

 

容器适配器:stackqueuepriority_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)  //同上(itemargs构造)

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为迭代器)

 

posted @ 2021-02-02 01:00  大黑耗  阅读(486)  评论(0编辑  收藏  举报