Cata1yst's blog

祇今尚有清流月,曾照高王万马过

0%

C++STL笔记

顺序容器

顺序容器的特点是其内部分配地址是连续的,可以轻易通过下标访问。

vector 变长数组

构造函数

  1. 直接赋值

    1
    2
    3
    //vector( std::initializer_list<T> init)
    std::vector<int> v{123};
    std::vector<int> v={123};
  2. 空矢量

    1
    2
    std::vector<int> v;
    std::vector<int> v{};
  3. 赋值为重复数值

    1
    2
    3
    //vector( size_type count,const T& value)
    std::vector<int> v(10,1);//赋10个1
    std::vector<int> v(10);//默认赋值为0
  4. 连续地址赋值

    1
    2
    3
    4
    //template< class InputIt >
    //vector( InputIt first, InputIt last)
    int base[5]={1,2,3,4,5};
    std::vector<int> v(base,base+5);
  5. 已有矢量初始化

    1
    2
    3
    //vector( const vector& other );
    std::vector<int> base(10,1);
    std::vector<int> v(base);
  6. 其他(如插入、复制)

    会在具体函数处说明

访问

  1. 下标直接访问(随机访问)

    1
    cout<<v[i]<<endl;
  2. 内置iterator迭代器访问

    iterator

数据入口函数

函数 作用
front() 返回首元素
back() 返回尾元素

示例

1
2
3
std::vector<char> letters {'a', 'b', 'c', 'd', 'e', 'f'};
std::cout << "The first character is '" << letters.front() << "'.\n";
std::cout << "The last character is '" << letters.back() << "'.\n";

迭代器

函数 作用
begin()/cbegin() 返回指向首元素的迭代器
end()/cend() 返回指向尾元素之后的迭代器
rbegin()/crbegin() 返回指向尾元素的迭代器
rend()/crend() 返回指向首元素之前的迭代器

示例

1
2
3
4
std::vector<double> d={ 1.9, 2.9, 3.9, 4.9, 5.9 };
cout<<"vector size is: "<<(d.end()-d.begin())<<endl;
cout<<"vector size is: "<<(d.rend()-d.rbegin())<<endl;
cout<<"first element is: "<<*d.begin()<<endl;
tips:cbeginbegin

stl容器中,许多返回迭代器的函数都有一个带c前缀的函数,比如begin/cbegin,它们的区别仅仅在于,cbegin返回的是常量迭代器,其内容不可更改;而begin返回的迭代器所指的值可以直接修改。

常用函数

at

原型

1
constexpr reference at( size_type pos );

作用

修改pos处的值

示例

1
v.at(0)=10;
assign

原型

1
2
3
4
5
6
7
8
9
//1
constexpr void assign( size_type count, const T& value );

//2
template< class InputIt >
constexpr void assign( InputIt first, InputIt last );

//3
constexpr void assign( std::initializer_list<T> ilist );

作用

初始化(数据类型不能变)

示例

1
2
3
4
5
6
7
8
9
10
vector<int> v;
vecror<int> v2(10,1)
//1
v.assign(10,1);

//2
v.assign(v2.begin(),v2.end());

//3
v.assign({1,2,3,4,5});
data

原型

1
constexpr T* data() noexcept;

作用

返回容器首元素地址

示例

1
2
std::vector<double> d={ 1.9, 2.9, 3.9, 4.9, 5.9 };
cout<<*d.data();
empty

原型

1
constexpr bool empty() const noexcept;

作用

判断数组是否为空

示例

1
2
std::vector<double> d={ 1.9, 2.9, 3.9, 4.9, 5.9 };
if (not d.empty()) cout<<"not empty\n";
size/max_size

原型

1
2
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;

作用

返回数组大小

返回数组最大限制(要用long long储存)

示例

1
2
3
std::vector<int> v={1,2,3,4,5,6};
cout<<v.max_size()<<endl;
for(int i=0;i<v.size();i++) cout<<v[i]<<" ";
reserve

原型

1
constexpr void reserve( size_type new_cap );

作用

为数组申请(保留)存储空间,如果new_cap小于当前存储空间,则函数不进行任何操作。

如果可以预先估计数组所需存储,利用该函数可以减少动态申请次数以节约时间。

示例

1
2
3
4
std::vector<int> v={1,2,3,4,5,6};
v.reserve(10);
cout<<v.size()<<endl;
cout<<v.capacity();
capacity

原型

1
constexpr size_type capacity() const noexcept;

作用

返回数组当前申请(保留)的空间大小

注意区分sizecapacity

示例

1
2
3
4
std::vector<int> v={1,2,3,4,5,6};
v.reserve(10);
cout<<v.size()<<endl;
cout<<v.capacity();
shrink_to_fit

原型

1
constexpr void shrink_to_fit();

作用

将数组动态申请的空间大小删减为当前存储数据的大小,即释放多余空间,可在数组数据存储完之后节约空间。

示例

注意与上例对比输出结果

1
2
3
4
5
std::vector<int> v={1,2,3,4,5,6};
v.reserve(10);
v.shrink_to_fit();
cout<<v.size()<<endl;
cout<<v.capacity();
clear

原型

1
constexpr void clear() noexcept;

作用

删除所有元素但保留申请的空间

示例

1
2
3
4
std::vector<int> v={1,2,3,4,5,6};
v.clear();
cout<<v.size()<<endl;
cout<<v.capacity();
insert

原型

1
2
3
4
5
6
7
8
constexpr iterator insert( const_iterator pos, const T& value );

constexpr iterator insert( const_iterator pos, size_type count, const T& value );

template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );

constexpr iterator insert( const_iterator pos,std::initializer_list<T> ilist );

作用

pos插入数值

注意一次插入后pos的值会改变,如果第二次还想继续插入,需要重新获取pos的值。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::vector<int> v={1,2,3};
std::vector<int> base={6,7};
auto pos=v.begin()+3;
// way 1
v.insert(pos,4);
pos=v.begin()+4;
//way 2
v.insert(pos,1,5);
pos=v.begin()+5;
//way 3
v.insert(pos,base.begin(),base.end());
pos=v.begin()+7;
//way 4
v.insert(pos,{8,9});
for(int i=0;i<v.size();i++) cout<<v[i]<<" ";
emplace

原型

1
2
template< class... Args >
constexpr iterator emplace( const_iterator pos, Args&&... args );

作用

pos插入一个元素

示例

1
2
3
std::vector<int> v={1,2,3};
auto pos=v.begin()+3;
v.emplace(pos,4);
tips: insert和emplace的区别
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <vector>
using namespace std;
struct _int64_{
int data;
_int64_(int num):data(num){
cout<<"构造函数\n";
}
_int64_(const _int64_& other):data(other.data){
cout<<"拷贝构造函数\n";
}
_int64_& operator =(const _int64_& other){
this->data=other.data;
return *this;
}
};
int main(){
vector<_int64_> v1{};
vector<_int64_> v2{};
v1.insert(v1.begin(),1);
v2.emplace(v2.begin(),1);
return 0;
}
/*
output:
构造函数
拷贝构造函数
构造函数
*/

从上面的例子中可以看出,调用insert时,新元素会依次调用其构造函数和拷贝构造函数,也就是说,insert的内部原理是先生成一个数据类型的临时结构体,再将该结构体拷贝进形参后进行插入;而emplace只执行了构造函数,之后直接进行插入。这个区别来源于C++11的可变参数模板,比较复杂。

总而言之,emplace及其类似函数在插入时时间开销较少,可以优先考虑,但如果希望一次性插入多个元素,则只能使用insert及其类似函数。

push_back/emplace_back

原型

1
2
constexpr void push_back( const T& value );
constexpr reference emplace_back( Args&&... args );

作用

在末尾插入一个元素

示例

1
2
3
4
5
//_int64_结构体见上文
vector<_int64_> v1{};
vector<_int64_> v2{};
v1.push_back(1);
v2.emplace_back(1);
erase

原型

1
2
constexpr iterator erase( const_iterator pos );
constexpr iterator erase( const_iterator first, const_iterator last )

作用

删除pos元素或删除firstend的所有元素(左闭右开

示例

1
2
3
vector<int> v{1,2,3,4,5,6,7,8,9};
v.erase(v.begin(),v.begin()+3);
cout<<v;
pop_back

原型

1
constexpr void pop_back();

作用

从末尾弹出一个元素(没有返回值)

示例

1
2
3
vector<int> v{1,2,3,4,5,6,7,8,9};
v.pop_back();
cout<<v;
resize

原型

1
2
constexpr void resize( size_type count );
constexpr void resize( size_type count, const value_type& value );

作用

修改容量至count

如果当前容量大于count,则向后删除多余元素

如果当前容量小于count,则增加的容量填充value(没有该参数时填充0

如果当前容量等于count,则不进行任何操作

示例

1
2
3
vector<int> v{1,2,3,4,5,6,7,8,9};
v.resize(20,1);
cout<<v;
swap

原型

1
constexpr void swap( vector& other ) noexcept

作用

交换两个数值元素,容量可以不同。

交换后各自begin()迭代器不变。

交换双方数据类型必须一致。

示例

1
2
3
4
5
vector<int> v1{1,2,3,4,5};
vector<int> v2{6,7,8,9};
v1.swap(v2);
cout<<v1;
cout<<v2;

queue 队列

priority_queue优先队列

deque 双向队列

构造函数

  1. 直接赋值

    1
    2
    3
    //deque( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
    deque<int> d={1,2,3,4};
    deque<int> d{1,2,3,4};
  2. 用另一个队列构造

    1
    2
    3
    //deque( const deque& other, const Allocator& alloc );
    deque<int> d1{1,2,3};
    deque<int> d2(d1);
  3. 连续空间赋值

    1
    2
    3
    4
    //template< class InputIt >
    //deque( InputIt first, InputIt last, const Allocator& alloc = Allocator() );
    deque<int> d1{1,2,3};
    deque<int> d2(d1.begin(),d1.end());
  4. 容量和重复赋值

    1
    2
    3
    //deque( size_type count, const T& value, const Allocator& alloc = Allocator());
    deque<int> d1(10,2);
    deque<int> d2(10);//默认赋值为0

访问

vector

常用函数

STL容器在很多方面具有相似性,因此这里只给出deque独特的成员函数

push_front/pop_front

原型

1
2
void push_front( T&& value );
void pop_front();

作用

在队列开头加入/删除元素(pop函数没有返回值)

示例

1
2
3
deque<int> d{1,2,3,4,5};
d.push_front(0);
d.pop_front();
emplace_front/emplace_back

原型

1
2
3
4
5
template< class... Args >
reference emplace_front( Args&&... args );

template< class... Args >
reference emplace_back( Args&&... args );

作用

在队列前(末)端插入一个元素

示例

相较于vector所没有的成员函数
  1. data
  2. capacity
  3. reserve

forward_list单向链表

构造函数

构造函数

访问

不支持随机访问,只能通过迭代器访问。

数据入口函数

函数 作用
front() 返回首元素

迭代器函数

函数 作用
begin()/cbegin() 返回指向首元素的迭代器
end()/cend() 返回指向尾元素之后的迭代器
before_begin()/cbefore_begin() 返回指向首元素之前的迭代器(head)

示例

1
2
3
4
forward_list<int> l{1,2,3,4,5};
auto iter=l.before_begin();
iter++;
cout<<*(iter);
tips:为什么list/forward_list的迭代器不支持加减运算

这个问题要从list数据结构的角度思考,与vector不同,list是由链表构成的,其储存单元的内存并不是连续的。

因此想要访问list的某一个单元,就必须从头开始进行一个O(n)的查找,也即不支持随机访问。

list的每个迭代器相当于一个指向链表节点的”指针“,节点中只保存了下一个节点的相关信息(next),因此迭代器只支持自增运算,而不能进行自减--、加+、减-运算。

同理,vector等连续储存的容器则支持加减运算,其本质是在当前地址的基础上加上存储单元大小的若干倍。

常用函数

assign
empty
max_size
clear
insert_after

在指定位置之后插入值

1
2
3
4
5
6
7
8
iterator insert_after( const_iterator pos, T&& value );

iterator insert_after( const_iterator pos, size_type count, const T& value );

template< class InputIt >
iterator insert_after( const_iterator pos, InputIt first, InputIt last );

iterator insert_after( const_iterator pos, std::initializer_list<T> ilist );
1
2
3
4
5
6
7
8
9
10
11
12
13
forward_list<int> l{1,2,3,4,5};

auto iter=l.before_begin();
l.insert_after(iter,114);

iter=l.before_begin();
l.insert_after(iter,1,514);

iter=l.before_begin();
l.insert_after(iter,l.begin(),l.end());

iter=l.before_begin();
l.insert_after(iter,{1919,810});
erase_after

删除pos之后一个元素或是删除从firstend的所有元素(不包括边界)

1
2
iterator erase_after( const_iterator pos );
iterator erase_after( const_iterator first, const_iterator last );
1
2
3
4
5
forward_list<int> l1{1,2,3,4,5};
l1.erase_after (l1.before_begin());
auto end=l1.begin();
for(int i=0;i<3;i++) end++;
l1.erase_after(l1.begin(),end);
emplace
  1. emplace_after

    pos之后的位置插入一个元素

    1
    2
    template< class... Args >
    iterator emplace_after( const_iterator pos, Args&&... args );
    1
    2
    forward_list<int> l1{1,2,3,4,5};
    l1.emplace_after(l1.before_begin(),0);
  2. emplace_front

push_front/pop_front
resize
swap
merge

合并两个已排序序列。

完成后,other序列被清空。

对于没有比较运算的数据结构,需要自定义comp函数,函数结构如下:

1
bool cmp(const Type1& a, const Type2& b);

要求当第一个参数小于第二个时,返回true

1
2
void merge( forward_list&& other );
void merge( forward_list&& other, Compare comp );
1
2
3
4
5
6
7
8
9
10
11
//_int64_前面有
bool comp(_int64_& a,_int64_& b){
return a.data<b.data;
}
int main(){
forward_list<_int64_> l1={1,3,5,7,9};
forward_list<_int64_> l2={2,4,6,8,10};
l1.merge(l2,comp);
cout<<l1;
return 0;
}
splice_after

other中部分元素转移到当前序列pos之后的位置

第一种重载模式表示将other序列全部转移

第二种重载模式表示将otherit之后一个元素转移

第三种重载模式表示将otherfirstend中的元素转移(不包括边界

1
2
3
4
5
void splice_after( const_iterator pos, forward_list&& other );

void splice_after( const_iterator pos, forward_list&& other, const_iterator it );

void splice_after( const_iterator pos, forward_list&& other, const_iterator first, const_iterator last );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
forward_list<int> l1(10);
forward_list<int> l2{1,2,3,4,5};

//将1移入最前面
auto pos1=l1.before_begin();
auto index=std::next(pos1,1);
auto pos2=std::next(l2.before_begin(),0);
l1.splice_after(pos1,l2,pos2);

//将3、4移入第一个0之后
pos1=std::next(pos1,2);
auto first=std::next(l2.before_begin(),1);
auto end=std::next(first,3);
l1.splice_after(pos1,l2,first,end);

//将2、5移入第二个0之后
pos1=std::next(pos1,3);
l1.splice_after(pos1,l2);
cout<<l1;
cout<<l2;
return 0;
remove&remove_if

删除等于value或使得p返回true的元素

1
2
3
4
void remove( const T& value );

template< class UnaryPredicate >
void remove_if( UnaryPredicate p );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool d2(int a){
return a%2;
}
int main(){
forward_list<int> l;
auto pos=l.before_begin();
for(int i=0;i<100;i++){
l.emplace_after(pos,i);
pos++;
}
l.remove_if(d2);
cout<<l;
return 0;
}

reverse

反转序列

1
void reverse() noexcept;
1
2
3
4
5
6
7
8
9
forward_list<Type> l;
auto pos=l.before_begin();
for(int i=0;i<10;i++){
l.emplace_after(pos,i);
pos++;
}
cout<<"original sequence: "<<l;
l.reverse();
cout<<"reserved sequence: "<<l;
unique

删除连续出现的重复元素,只保留每个重复序列的第一个元素。

其内部默认使用==运算判断相同元素,对于不能直接判断的数据结构,要么重载其==运算;要么传入比较函数pp的规范如下

1
bool p(const Type1 &a, const Type2 &b);

当且仅当ab相等时返回true

1
2
3
4
size_type unique();

template< class BinaryPredicate >
size_type unique( BinaryPredicate p );
1
2
3
forward_list<Type> l{1,1,2,2,3,3,4,1,1,5,5,6};
l.unique();
cout<<l;
sort

从小到大排序。

对于不能直接进行<运算的数据结构,需要重载运算符或者传入函数comp

1
bool cmp(const Type1& a, const Type2& b);

当且仅当a<b时,函数返回true

1
2
3
4
void sort();

template< class Compare >
void sort( Compare comp );
1
2
3
4
5
6
7
8
9
bool mycmp(int a,int b){
return a>b;
}
int main(){
forward_list<Type> l{1,1,2,2,3,3,4,1,1,5,5,6};
l.sort(mycmp);
cout<<l;
return 0;
}

list 双向链表

listforward_list的很相似,因此这里只给出它们的区别,不再一一展示list的成员函数。

  1. 数据入口

    list是双向的,因此它在forward_listfront()的基础上多了back()接口。

  2. 迭代器

    list没有before_begin()这一迭代器。

    相应的,forward_list中所有xxxx_after函数也都退化成了xxxx

  3. 插入位置

    除了上面所说的list中插入位置都在pos之后(即函数不带after后缀)以外,由于容器的开口是双向的,list多了emplace_backpush_backpoo_back这三个函数以对应front函数。

array 定长数组

构造函数

与其他容器初始化稍有不同,array只有两种初始化方式。你需要在声明模板的同时声明大小,比如

1
2
array<int 6> arr={1,2,3};
array<int 6> arr_(arr);

另外,初始化参数数目可以小于声明的大小,这时多余的空间会用0填充。

访问

  1. 随机访问
  2. 迭代器访问

数据入口函数

函数 作用
front() 返回首元素
back() 返回尾元素

迭代器

函数 作用
begin()/cbegin() 返回指向首元素的迭代器
end()/cend() 返回指向尾元素之后的迭代器
rbegin()/crbegin() 返回指向尾元素的迭代器
rend()/crend() 返回指向首元素之前的迭代器

常用函数

at
data
empty
size
max_size
fill

value替换数组内所有元素

1
void fill( const T& value );
1
2
3
array<int,5> a={1,2,3};
a.fill(3);
cout<<a;
swap

关联容器

关联容器的内部结构往往是树,因此其单元地址并不是连续的,不支持下标访问;同时,这类容器支持在插入时自动排序。

set 集合

set是一类有序集合,其内部结构是二叉排序树。

构造函数

1
2
3
4
5
6
7
8
9
10
std::set<Key,Compare,Allocator>

template< class InputIt >
set( InputIt first, InputIt last,const Compare& comp = Compare());

set( const set& other, const Allocator& alloc );

set( std::initializer_list<value_type> init, const Compare& comp = Compare());


set模板如上,一般只用到KeyCompare两项,即数据类型和比较函数

如果数据结构重载了比较运算符,那么Compare也可以省略。需要注意的是,重载运算符的函数必须是常函数

set有没有赋重复值的构造函数,这是因为set本身不允许出现重复元素。

除此之外,set的构造函数都可以参考其他容器

访问

由于二叉树也是节点结构,因而set没有随机访问,只能迭代器访问。

迭代器

array

集合的迭代器只有++--两种运算。

常用函数

empty
size
max_size
clear
insert
1
2
3
4
5
6
7
8
std::pair<iterator, bool> insert( value_type&& value );

iterator insert( const_iterator pos, const value_type& value );

template< class InputIt >
void insert( InputIt first, InputIt last );

void insert( std::initializer_list<value_type> ilist );

集合的插入函数有所不同。

插入元素不需要指定位置(可以指定但是集合的有序组合,并不影响最终插入的位置,可能影响执行速度)

当不指定插入位置且插入单个元素时返回pair,它有firstsecond两个成员。前者是插入元素的迭代器;后者是bool类型,表示插入成功与否。

其他情况与其他迭代器基本一致。

1
2
3
4
5
6
7
8
9
10
11
12
int main(){ 
set<int64> s{1,2,3,5,6};
auto ret=s.insert(4);
cout<<(ret.second==1?"success":"default")<<endl;
ret.first++;
cout<<"the next element of the inserted one is : "<<(ret.first)->num<<endl;
s.insert({7,8,9});
auto ret_=s.insert(s.begin(),10);
cout<<"the previous element of the inserted one is : "<<(--ret_)->num<<endl;
s.insert(s.begin(),s.end());
for(auto it=s.begin();it!=s.end();it++) cout<<(*it).num<<" ";
}
emplace

emplace无需指定插入位置,返回值是pair

emplace_hint
1
2
template <class... Args>
iterator emplace_hint( const_iterator hint, Args&&... args );

集合容器用此函数来指定位置插入元素,插入位置是hint之前(最后集合内顺序还是排序后的)

函数返回最终新元素位置的迭代器;如果插入失败,则返回已存在元素位置的迭代器。

erase
swap
count
1
size_type count( const Key& key ) const;

该函数返回集合中key出现的次数(其实就是在不在集合中)

find
1
const_iterator find( const Key& key ) const;

该函数返回key所在位置的迭代器

1
2
3
4
5
6
7
8
int main(){ 
set<int64> s{1,2,3,5,6};
if(s.count(5)){
auto it=s.find(5);
cout<<"the element after 5 is : "<<(++it)->num<<endl;
}
for(auto it=s.begin();it!=s.end();it++) cout<<(*it).num<<" ";
}
equal_range
1
std::pair<const_iterator,const_iterator> equal_range( const Key& key ) const;

返回一个包含两个迭代器的pair,前者是值为key 的迭代器的下界,后者是上界。

注意区间是左闭右开,即前者是第一个不小于key 的元素的迭代器,后者是第一个大于key元素的迭代器。

1
2
3
4
5
6
int main(){ 
set<int64> s{1,2,3,5,6};
auto its=s.equal_range(5);
cout<<"iterators of 5 from "<<(its.first)->num<<" to "<<(its.second)->num<<endl;
for(auto it=s.begin();it!=s.end();it++) cout<<(*it).num<<" ";
}
lower_bound
1
const_iterator lower_bound( const Key& key ) const;

返回第一个不小于key 的元素的迭代器。

upper_bound
1
const_iterator upper_bound( const Key& key ) const;

返回第一个大于key元素的迭代器。

key_comp
1
key_compare key_comp() const;

返回当前集合的比较函数,即初始化时的Compare

1
2
3
4
5
6
7
8
9
10
struct cmp{
bool operator () (const int64& a,const int64& b) const{
return a.num%3<b.num%3;
}
};
int main(){
set<int,cmp> s{1,2,3,5,6};
auto cmp_fun=s.key_comp();
cout<<(cmp_fun(1,3)==1?"1 mod 3 is less than 3 mod 3":"3 mod 3 is less than 1 mod 3")<<endl;
}

map 字典

构造函数

1
std::map<Key,T,Compare,Allocator>

字典的模板如上,在使用时我们需要指定键(key)、值(T)的数据类型以及比较函数Compare

1
2
3
4
5
6
template< class InputIt >
map( InputIt first, InputIt last, const Compare& comp = Compare(), const Allocator& alloc = Allocator() );

map( const map& other, const Allocator& alloc );

map( std::initializer_list<value_type> init,const Compare& comp = Compare(),const Allocator& alloc = Allocator() );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct cmp{
bool operator () (const string& a,const string& b) const{
return a<b;
}
};
int main(){
map<string,int,cmp> m1{
{"s",1},
{"f",2},
{"w",3}
};
map<string,int,cmp> m2(m1.begin(),m1.end());
map<string,int,cmp> m3(m2);
for(auto p=m1.begin();p!=m1.end();p++) cout<<p->first<<":"<<p->second<<endl;
}

访问

  1. 迭代器访问

  2. 通过key访问

    字典重载了[]运算符,可以通过关键词直接访问。

    通过该运算符读时,对于存在于字典的key,函数返回其值value;否则返回0

    通过该运算符写时,对于存在于字典的key,将修改器值;否则插入其中。

    1
    T& operator[]( Key&& key );
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int main(){ 
    map<string,int> m{
    {"c",1},
    {"b",2},
    {"d",3}
    };
    m["a"]=4;
    m["b"]=114;
    for(auto p=m.begin();p!=m.end();p++) cout<<p->first<<" : "<<p->second<<endl;
    }

迭代器

set相同

常用函数

at

用法同[]

empty
size
max_size
clear
insert

和集合的插入类似

1
2
3
4
5
6
template< class P >
std::pair<iterator, bool> insert( P&& value );

iterator insert( const_iterator pos, const value_type& value );

void insert( std::initializer_list<value_type> ilist );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main(){ 
map<string,int> m{
{"c",1},
{"b",2},
{"d",3}
};
//without pos
auto ret=m.insert({"e",7});
cout<<(ret.second?"success":"default")<<endl;
ret=m.insert({"e",6});
cout<<(ret.second?"success":"default")<<endl;
//with pos
auto it=m.insert(m.end(),{"a",10});
cout<<"insert pair ("<<it->first<<" : "<<it->second<<")"<<endl;
it=m.insert(m.end(),{"b",10});
cout<<"insert pair ("<<it->first<<" : "<<it->second<<")"<<endl;
//insert more than one
m.insert({{"f",11},{"k",12}});
//print map
for(auto p=m.begin();p!=m.end();p++) cout<<p->first<<" : "<<p->second<<endl;
}
emplace/emplace_hint

参考insert以及集合的同名函数

erase
swap
count
find
equal_range
lower_bound
upper_bound
key_comp
value_comp

类似key_comp,返回一个比较函数,该函数有两个pair型参数,函数返回key_comp(pair1.first,pair2.first)的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct comp{
bool operator () (Key a,Key b) const{
return abs(a-4)<abs(b-4);
}
};
int main(){
map<Key,Value,comp> m{
{1,"one"},
{2,"two"},
{4,"four"},
{8,"eight"}
};
auto cmp=m.value_comp();
pair<Key,Value> p{6,"six"};
for(auto _p_: m){
bool res=cmp(_p_,p);
cout<<"4 is closer to "<<(res?_p_.second:p.second)<<" than "<<(res?p.second:_p_.second)<<endl;
}
}

multiset

顾名思义,multisetset的类似物,它允许其中出现重复的元素。它的操作几乎和原型相同。不过在这里,set中看似无用的equal_rangelower_boundupper_bound等函数就有了独特的用处。

multimap

它是和multiset类似的map变形。