vector
用途
vector可以理解成可以变长的数组;也就是数组的长度是可以动态变化的。
vector常用于需要存储内容大小不确定,用普通数组存储会超内存的情况。
使用需添加
#include<vector>
基本操作
定义
vector< type > name;
type可以是任何数据类型(int,struct,class…),甚至可以是STL。
例如,定义一个可以保存int类型的vector的vector:
vector< vector<int> > v;
这个时候,vector就相当于两个维度都可以变化的数组。
元素访问
使用下标
和普通数组一样,假设有一个vector变量名为v,那么访问使用v[i]就可以访问v种第i个元素。
注意这里下标的范围是0 - v.size() - 1,其中size()函数是返回STL中元素的个数。
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > v = {1,2,4,5};
for( int i = 0; i < v.size(); ++ i ) cout << v[i] << endl;
}
输出:
1
2
4
5
使用迭代器
迭代器可以类比成指针,定义为
STL<typename>::iterator iterator_name;
其中STL是所用STL的名称,如vector,以及后面要介绍到的map,set等。
如定义一个vector类型的迭代器,则可以使用以下语句:
vector<int>::iterator it;
使用迭代器来遍历元素:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > v = {1,2,4,5};
for( vector< int >::iterator it = v.begin(); it != v.end(); ++ it )
cout << *it << endl;
}
输出:
1
2
4
5
这种写法与下面这种写法等价:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > v = {1,2,4,5};
vector< int >::iterator it = v.begin();
for(int i = 0; i < v.size(); ++ i)
cout << *(it + i) << endl;
}
可以看到:
- v[i]与*(it + i)作用相同
- 迭代器实现了自增和自减的操作,与指针类似。
- begin()函数返回首元素迭代器,end()返回尾元素的下一个迭代器而不是首元素,左闭右开,其实后面有很多函数都是按照左闭右开的方式来定义的。
注意:
- 迭代器的类型必须和定义的类型一致,即我不能用vector< double >类型的迭代器访问vector< int >型的vector
- 只有vector和string才能使用it+i这种写法
当然迭代器需要写这么长,不太方便,我们可以使用auto改写上述代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > v = {1,2,4,5};
for( auto it = v.begin(); it != v.end(); ++ it )
cout << *it << endl;
}
使用auto遍历
如果仅仅需要遍历所有元素,那么我们可以使用如下方式:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > v = {1,2,4,5};
for( int i: v ) cout << i << endl;
}
或者更简单一点,使用auto:
int main()
{
vector< int > v = {1,2,4,5};
for( auto i: v ) cout << i << endl;
}
需要注意的一点是,如果需要修改其中的每个元素,那么需要这样写:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > v = {1,2,4,5};
for( auto &i: v )
{
cout << i << " ";
i = i + 1;
}
cout << endl;
for( auto i : v ) cout << i << " ";
}
输出:
1 2 4 5
2 3 5 6
而如果不使用引用:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > v = {1,2,4,5};
for( auto i: v )
{
cout << i << " ";
i = i + 1;
}
cout << endl;
for( auto i : v ) cout << i << " ";
}
则会输出:
1 2 4 5
1 2 4 5
原因是如果不适用引用,相当于对其中的每个元素建立了一个拷贝,而引用则是对其中的每个元素建立一个引用,当然可以修改真正的值。
常用函数
push_back()与pop_back()
push_back()故名思意,就是再当前vector的后边添加一个元素,而pop_back()就是再vector后边删除一个元素。
#include <bits/stdc++.h>
using namespace std;
void Print( vector<int> &v )
{
cout << "size = " << v.size() << ", elements = [ ";
for( auto i : v ) cout << i << " ";
cout << "]" << endl;
}
int main()
{
vector< int > v;
for( int i = 1; i < 5; ++ i )
v.push_back(i);
Print(v);
v.pop_back();
Print(v);
}
输出:
size = 4, elements = [ 1 2 3 4 ]
size = 3, elements = [ 1 2 3 ]
clear()与empty()
clear()用于清空STL,empty()是用于判断STL是否为空,如果为空返回1,否则返回0;
#include <bits/stdc++.h>
using namespace std;
void Print( vector<int> &v )
{
cout << "size = " << v.size() << ", elements = [ ";
for( auto i : v ) cout << i << " ";
cout << "]" << endl;
}
int main()
{
vector< int > v;
for( int i = 1; i < 5; ++ i )
v.push_back(i);
Print(v);
v.clear();
Print(v);
}
输出:
size = 4, elements = [ 1 2 3 4 ]
size = 0, elements = [ ]
clear()的功能这种写法与以下写法相同:
while( !v.empty() ) v.pop_back();
insert()
insert()有三种形式:
函数 | 作用 |
---|---|
v.insert(it, val) | 向迭代器it指向的元素前插入新元素val |
v.insert(it, n, x) | 向迭代器it指向的元素前插入n个x |
v.insert(it, first, last) | 将由迭代器first和last所指定的序列[first, last)插入到迭代器it指向的元素前面 |
举几个例子: | |
插入一个元素: |
#include <bits/stdc++.h>
using namespace std;
void Print( vector<int> &v )
{
cout << "size = " << v.size() << ", elements = [ ";
for( auto i : v ) cout << i << " ";
cout << "]" << endl;
}
int main()
{
vector< int > v, v1;
for( int i = 1; i < 5; ++ i )
v.push_back(i), v1.push_back(i + 100);
Print(v);
auto it = v.begin() + 1;
v.insert( it, 1E9);
Print(v);
}
输出:
size = 4, elements = [ 1 2 3 4 ]
size = 5, elements = [ 1 1000000000 2 3 4 ]
插入序列:
#include <bits/stdc++.h>
using namespace std;
void Print( vector<int> &v )
{
cout << "size = " << v.size() << ", elements = [ ";
for( auto i : v ) cout << i << " ";
cout << "]" << endl;
}
int main()
{
vector< int > v;
for( int i = 1; i < 5; ++ i )
v.push_back(i);
Print(v);
auto it = v.begin() + 1;
v.insert( v.begin(), it, it + 2 );
Print(v);
}
输出:
size = 4, elements = [ 1 2 3 4 ]
size = 6, elements = [ 2 3 1 2 3 4 ]
当然也可以是其他vector的迭代器,不过类型要一致。
#include <bits/stdc++.h>
using namespace std;
void Print( vector<int> &v )
{
cout << "size = " << v.size() << ", elements = [ ";
for( auto i : v ) cout << i << " ";
cout << "]" << endl;
}
int main()
{
vector< int > v, v1;
for( int i = 1; i < 5; ++ i )
v.push_back(i), v1.push_back(i + 100);
Print(v);
auto it = v1.begin() + 1;
v.insert( v.begin(), it, it + 2 );
Print(v);
}
结果:
size = 4, elements = [ 1 2 3 4 ]
size = 6, elements = [ 102 103 1 2 3 4 ]
erase()
erase()有两种形式:
函数 | 作用 |
---|---|
v.erase(it) | 删除由迭代器it所指向的元素 |
v.erase(first, last) | 删除由迭代器first和last所指定的序列[first, last) |
例如: |
#include <bits/stdc++.h>
using namespace std;
void Print( vector<int> &v )
{
cout << "size = " << v.size() << ", elements = [ ";
for( auto i : v ) cout << i << " ";
cout << "]" << endl;
}
int main()
{
vector< int > v, v1;
for( int i = 1; i < 5; ++ i )
v.push_back(i), v1.push_back(i + 100);
Print(v);
auto it = v.begin() + 1;
v.erase( it);
Print(v);
}
结果:
size = 4, elements = [ 1 2 3 4 ]
size = 3, elements = [ 1 3 4 ]
常见使用情况
用邻接表的形式存储图
例如用以下形式给出一个图:
n
n
n
m
m
m
a
1
a_1
a1
b
1
b_1
b1
c
1
c_1
c1
⋮
\vdots
⋮
a
m
a_m
am
b
m
b_m
bm
c
m
c_m
cm
其中n是节点数,m是边数,下面有m行,表示从
a
i
a_i
ai到
b
i
b_i
bi有一条权值为
c
i
c_i
ci的边。
假设n,m很大,1E5左右,那么就不能使用邻接矩阵来存储,而是用vector则可以办得到。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1E5 + 5;
struct edge { int to, weight; };
vector< edge > v[maxn];
int main()
{
int n, m; cin >> n >> m;
while( m -- )
{
int a, b, c; cin >> a >> b >> c;
v[a].push_back( {b, c} );
}
}
存储输入个数不定的数据
如输入许多字符串,直到遇到end时停止,那么可以使用vector将这些数据保存起来:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string tmp;
vector< string > v;
while( cin >> tmp, tmp != "end" )
v.push_back(tmp);
}
模拟stack(vector速度比stack要快)
stack是一种后进先出的数据结构,在实现Tarjan或者递归时会经常用到。因为vector速度要比真正的stack要快,所有常常使用vector来模拟stack。
如stack的push()可以用vector的push_back(),而pop()则可以用pop_back();
时间复杂度
- 在vector后插入和删除、以及元素访问是 O ( 1 ) O(1) O(1)
- 在任意位置插入时 O ( k ) O(k) O(k),k是插入位置之后的元素个数。
map
用途
map翻译为映射。实际上数组也相当于映射,如double a[100],则是建立100个从int到double的映射。但是数组如果要实现从字符串到int的映射,或者实现从一个结构体到另一个结构体的映射则就不那么方便了。而map就是为了解决这种情况而产生的。
使用需添加
#include<map>
基本操作
定义
map< type1, type2 > name;
map可以实现从任意基本类型到任意基本类型。
但需要注意的一点是,如果type1要使用字符串的话,则必须使用string而不能使用char数组,因为数组不能作为键。但是type2则可以是数组。
元素访问
通过键访问
通过之前插入元素时候的键来访问相应的值。
#include <bits/stdc++.h>
using namespace std;
int main()
{
map< string ,int > age;
age["张三"] = 12;
age["小王"] = 23;
cout << age["小王"] << endl;
}
输出:
23
通过迭代器访问
迭代器定义
map< type1, type2 >::iterator iterator_name;
当然也可以使用auto自动推断类型。
map的迭代器既可以使用iterator -> first的方式访问键,也可以通过iterator -> second的方式访问值。
#include <bits/stdc++.h>
using namespace std;
int main()
{
map< string ,int > age;
age["San Zhang"] = 12;
age["Wang Xiao"] = 23;
age["Ann Xia"] = 128;
for( map<string, int>::iterator it = age.begin(); it != age.end(); ++ it )
cout << it->first << " " << it->second << endl;
}
输出:
Ann Xia 128
San Zhang 12
Wang Xiao 23
发现输出的顺序和输入顺序不一样。其实map是自动按照字典序从小到大进行的排序。事实上,map是将type1相应的大小比较规则来进行排序。那么可以推知,如果是自定义结构体,那么就需要重载 < 号之后才可以使用map。
使用auto遍历
#include <bits/stdc++.h>
using namespace std;
void Print( map< string, int > &mp )
{
for( auto &i : mp )
cout << "Key = " << i.first << ", Value = " << i.second << endl;
}
int main()
{
map< string ,int > age;
age["San Zhang"] = 12;
age["Wang Xiao"] = 23;
Print(age);
}
输出:
Key = San Zhang, Value = 12
Key = Wang Xiao, Value = 23
这里可以发现auto和迭代器有些许不同,在auto中访问元素使用的 “.” 而在迭代其中是用的 -> 。这是因为auto返回的是元素本身,而迭代器相当于指针。就像是结构体,使用auto返回的是结构体的元素,而迭代器返回的是指向元素的指针。
常用函数
用法 | 含义 |
---|---|
mp[key] = x | 利用数组方式插入数据,key是键,x是值 |
mp.at(key) = x | 利用at执行插入操作 |
mp.insert(make_pair(key,x)) | 利用insert插入pair(键,值)数据 |
mp.emplace(make_pair(key,x)) | 在映射中不存在主键key时执行插入操作 |
mp.size() | 返回mp的大小 |
mp.count(key) | multimap中返回键为key的元素存在的映射数。map中存在key返回1,不存在返回0 |
mp.erase(it) | 根据迭代器删除元素 |
mp.erase(key) | 根据键删除元素 |
mp.clear() | 清空映射 |
mp.empty() | 判断映射是否为空 |
mp.find(key) | 根据键key查找元素,找到以后返回迭代器,不存在返回end |
mp.rbegin() | 返回反向迭代器 |
mp.rend() | 返回反向迭代器 |
mp.swap(mp2) | 将mp和mp2进行交换 |
mp.lower_bound(key) | 返回map中第一个大于或等于key的迭代器指针 |
mp.upper_bound(key) | 返回map中第一个大于key的迭代器指针 |
map的键值对是唯一的,如果如果出现重复的键,那么后来者居上,后来的键值对会替换之前的。 |
常见使用情况
字符串,结构体与其他数据类型的映射
#include <bits/stdc++.h>
using namespace std;
struct A
{
int a, b;
bool operator < ( const A &b) const
{
return a == b.a ? ( b < b.b ) : ( a < b.a );
}
};
int main()
{
map< A, int > mp;
mp[{1,2}] = 3;
mp[{-1, 4}] = 1;
cout << mp.begin() -> first.a << endl;
}
可以看到,map按照重载的规则自动进行了排序。
可以当作bool数组用
例如:
map< string ,bool > age;
这样就可以判断某个字符串是否出现过。
可以实现离散化
离散化就是说,将一些浮点值,通过一个映射操作,使他们的值映射成整数,但相对大小不变。
离散化同样也可以,将数据范围较大但是个数比较小的序列映射成数据范围比较小的序列。
以上两点在线段树中体现比较明显。
#include <bits/stdc++.h>
using namespace std;
int main()
{
map< double, int > mp;
double a[] = { 1.1, 1.1, -10023, 123123, 12.23124 };
for( auto &i : a ) mp.emplace( make_pair( i, 1) );
int order = 0;
for( auto &i : mp ) i.second = order ++;
for( auto i : a )
cout << "before = " << i << ", after = " << mp[i] << endl;
}
输出:
before = 1.1, after = 1
before = 1.1, after = 1
before = -10023, after = 0
before = 123123, after = 3
before = 12.2312, after = 2
可见a数组中的数实现了离散化。
时间复杂度
插入、查找、删除的时间复杂度都是 O ( l o g n ) O(logn) O(logn), n n n是map的大小。
multimap
使用需添加
#include<map>
与map的区别
- map的键值对唯一,而multi_map不唯一。
- multimap不能通过键访问元素,因为键值对不唯一([],at等均不可以);只能通过迭代器访问。
- multimap不能使用mp[key] = value的形式添加元素,只能使用insert()
unordered_map
使用需添加
#include <unordered_map>
与map的区别
- map会自动排序,unordered_map不会
- map用红黑树实现,而unordered_map使用散列。
- unordered_map平均搜索插入复杂度为 O ( 1 ) O(1) O(1),即不需要排序时,使用unordered_map会快一些。
set
用途
set译作集合,set可以实现内部元素自动排序并自动去重。
使用需添加
#include <set>
基本操作
定义
set< type > name;
同map一样,因为他会自动排序,所以类型为自定义结构体的时候需要重载 < 。
访问元素
只能通过迭代器访问!!
#include <bits/stdc++.h>
using namespace std;
int main()
{
set<int> s;
s.insert(1);
s.insert(2);
s.insert(1);
auto it = s.begin();
cout << *(++ it) << " " << *( -- it ) << endl;
}
输出:
2 1
通过迭代器或auto遍历
#include <bits/stdc++.h>
using namespace std;
int main()
{
set<int> s;
s.insert(1);
s.insert(2);
s.insert(1);
for( auto i : s ) cout << i << endl;
}
常用函数
函数 | 含义 |
---|---|
s.begin() | 返回指向第一个元素的迭代器 |
s.end() | 返回指向最后一个元素的迭代器 |
s.clear() | 清除所有元素 |
s.empty() | 如果集合为空,返回true |
s.count(val) | 返回值为val的元素的个数 |
s.erase(val) | 删除集合中所有值为val的元素 |
s.erase(it) | 删除集合中迭代器it指向的元素 |
s.erase(first,last) | 删除由迭代器first和last所指定的子集[first, last) |
s.equal_range(val) | 返回有序/升序集合中val元素第一次和最后一次出现的位置 |
s.find() | 返回一个指向被查找到元素的迭代器 |
s.insert(val) | 在集合中插入值为val的元素 |
s.max_size() | 返回集合能容纳的元素的最大限值 |
s.rbegin() | 返回指向集合中最后一个元素的反向迭代器 |
s.rend() | 返回指向集合中第一个元素的反向迭代器 |
s.size() | 集合中元素的数目 |
s.swap(s2) | 交换两个集合变量 |
s.upper_bound(val) | 返回大于val值元素的迭代器 |
s.lower_bound(val) | 返回指向大于(或等于)val值的第一个元素的迭代器 |
注意使用内置的lower_bound()函数会比algorithm中的lower_bound()函数快,因为后者会重建一遍set。 |
常见使用情况
- 去重,排序
- 也可以用来实现离散化
时间复杂度
插入删除查找都是 O ( l o g n ) O(logn) O(logn), n n n为set大小。
multiset
使用需添加
#include <set>
与set的区别
- 可以出现重复元素,能用来在保持原序列时钟保持顺序的情况下实现快速插入和快速查找。
unordered_set
使用需添加
#include <unordered_set>
与set的区别
- 使用散列实现,不可以排序,仅能用来去重。
- 均摊复杂度 O ( 1 ) O(1) O(1)
bitset
用途
类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间。用它存储数据回比用数组省空间。
使用需添加
#include <bitset>
基本操作
定义
bitset<length> name;
即定义有length位的bitset。
元素访问
通过下标访问某一位
左边位低位,右边为高位。
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
bitset<8> bit(25);
cout << bit[0] << endl;
}
输出
1
直接输出全部位数
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
bitset<8> bit(25);
cout << bit << endl;
}
输出:
00011001
构造函数
构造函数 | 作用 |
---|---|
bitset< length > bit | 无参构造函数,默认全为0 |
bitset< length > bit(string) | 将string转换成二进制,要求string必须由01构成,长度不足定义长度时,按照放在低位 |
bitset< length > bit( char[] ) | 同上 |
bitset< length > bit(val) | 将val转化成二进制放在bitset中 |
常用函数
函数 | 作用 |
---|---|
bit.size() | 返回大小(位数) |
bit.count() | 返回1的个数 |
bit.any() | 返回是否有1 |
bit.none() | 返回是否没有1 |
bit.set() | 全都变成1 |
bit.set§ | 将第位置p变成1 |
bit.set(p, x) | 将位置p变成x |
bit.reset() | 全都变成0 |
bit.reset§ | 将位置p变成0 |
bit.flip() | 全都取反 |
bit.flip§ | 将位置p取反 |
bit.to_ulong() | 返回它转换为unsigned long的结果,如果超出范围则报错 |
bit.to_ullong() | 返回它转换为unsigned long long的结果,如果超出范围则报错 |
bit.to_string() | 返回它转换为string的结果 |
常见使用情况
- 二进制相关操作
- 节省空间
queue
用途
是一个先进先出的数据结构,与stack正好相反。
使用需添加
#include <queue>
基本操作
定义
queue<type> name;
元素访问
queue的访问比较特殊,queue没有迭代器,每次只能访问队首元素,即使用front()函数。
如果要遍历则需要像这样使用:
#include <iostream>
#include <queue>
using namespace std;
int main()
{
queue< int > q;
q.push(1);
q.push(2);
q.push(3);
while( !q.empty() )
{
cout << q.front() << " ";
q.pop();
}
}
常用函数
函数 | 作用 |
---|---|
q.push() | 入队 |
q.pop() | 出队 |
q.front() | 返回首元素 |
q.back() | 返回末元素 |
q.size() | 输出现有元素的个数 |
q.empty() | 队列为空返回1,反之返回0 |
常见使用情况
bfs
假设以邻接表的形式存图。
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 1E5;
bool vis[maxn];
vector<int> G[maxn];
void BFS()
{
int s;
queue< int > q;
q.push(s);
while( !q.empty() )
{
int ft = q.front(); vis[ft] = 1; q.pop();
for( auto to : G[ft] )
if( !vis[to] ) q.push(to);
}
}
最原始的Bellman-Fold
struct node
{
int to;
long long val;
node( int to = 0, long long val = 0 ) : to(to), val(val) {}
};
vector< node > G[maxn];
long long dis[maxn];
bool inq[maxn];
void SPFA( int s )
{
memset( inq, 0, sizeof( inq ) );
for( int i = 1; i < maxn; ++ i) dis[i] = 1E18;
dis[s] = 0, inq[s] = 1;
queue< int > q; q.push(s);
while( !q.empty() )
{
int x = q.front(); q.pop();
inq[x] = 0;
//这里和堆优化的区别就显现出来了,堆优化版本只会入队一次,而SPFA则不是
for( auto to : G[x] )
{
if( dis[to.to] > dis[x] + to.val )
{
dis[to.to] = dis[x] + to.val;
if( !inq[to.to] ) q.push(to.to), inq[to.to] = 1;
}
}
}
}
时间复杂度
push和pop均为 O ( 1 ) O(1) O(1)
priority_queue
用途
保证队首元素优先级最大,相当于大根堆。
使用需添加
#include <queue>
常见操作
定义
priority_queue< type > name;
常用函数
- 基本与queue相同,只不过priority_queue始终保证队首元素优先级最大,而不是先进先出。
- 队首元素需要使用top()而不是front()
优先级的设置
同map类似,需要重载 < 号。
但是,排序结果时相反的,因为他是按照优先级来的,所以越大的数,优先级越大,会排在前边。
#include <iostream>
#include <queue>
using namespace std;
struct pet
{
string species;
int price;
bool operator < ( const pet& b ) const
{
return price < b.price;
}
};
int main()
{
priority_queue< pet > q;
q.push({"cat",100} );
q.push({"dog", 50 } );
q.push({"Tarjan", 10000} );
while( !q.empty() )
{
cout << q.top().species << endl;
q.pop();
}
}
输出:
Tarjan
cat
dog
而如果时int等基本类型需要设置越小的数优先级越高,则需要添加
#include <functional>
并用如下定义方式:
priority_queue< int, vector<int>, greater<int> > q;
如:
#include <iostream>
#include <queue>
#include <functional>
using namespace std;
int main()
{
priority_queue< int, vector<int>, greater<int> > q;
q.push(2);
q.push(50);
q.push(1);
while( !q.empty() )
{
cout << q.top() << endl;
q.pop();
}
}
输出:
1
2
50
常见使用情况
堆优化的Dijkstra和Bellman-Fold
struct edge
{
int pos, val;
edge( int pos = 0, int val = 0 ) : pos(pos), val(val) {}
bool operator < ( const edge &e ) const
{
return val > e.val;
}
};
vector< edge > G[maxn];
int dis[maxn];
bool vis[maxn];
void Dijkstra( int s )
{
memset( dis, 0x3f, sizeof( dis ) );
priority_queue< edge > q;
dis[s] = 0; q.push({s,dis[s]});
while( !q.empty() )
{
auto tp = q.top( ); q.pop( );
if ( vis[tp.pos] ) continue;
inq[tp.pos] = 1;
for ( auto v : G[tp.pos] )
{
if( dis[v.pos] > dis[tp.pos] + v.val )
{
dis[v.pos] = dis[tp.pos] + v.val;
q.push( {v.pos, dis[v.pos]} );
}
}
}
}
一些需要贪心的情况
list
用途
就是链表,当需要快速 O ( 1 ) O(1) O(1)的时间插入或者删除时需要使用。
使用需添加
#include <unordered_set>
基本操作
定义
list< type > name;
访问元素
仅能使用迭代器访问
#include <iostream>
#include <list>
using namespace std;
int main()
{
list< int > l;
l.push_back(1);
auto it = l.begin();
cout << *it << endl;
}
输出:
1
常用函数
函数 | 含义 |
---|---|
l.begin() | 返回链表首地址 |
l.end() | 返回链表尾地址 |
l.front() | 返回首元素 |
l.back() | 返回尾元素 |
l.push_back(elem) | 插入元素到链表尾部 |
l.push_front(elem) | 插入元素到链表头部 |
l.empty() | 判断链表是否为空 |
l.insert(it, val1, val2)) | 在指定位置插入一个或多个元素 |
l.resize(n) | 调整链表大小为n,超出n删除,少于n补0 |
l.clear() | 清除 |
l.assign(len, val) | 替换所有元素 |
l.assign(l2.begin(), l2.end()) | 替换所有元素为链表l2 |
l.swap(l2) | 交换链表 |
l.merge(l2) | 合并两个有序链表中的元素,调用后l2为空,可用greater() |
l.erase(it) | 删除(区域中的)元素 |
l.remove(val) | 删除值为val 的元素 |
常见使用情况
- 需要快速插入删除。
- 节省存储空间
- 模拟双端队列
时间复杂度
- 插入删除 O ( 1 ) O(1) O(1)
- 查找 O ( n ) O(n) O(n), n n n为链表长度