C++ STL容器有哪些常用成员函数和成员变量? - Dotcpp编程

一、容器

1.访问方式

迭代器、下标[]和at()、指针。

2.常用成员函数和变量

C++ STL容器有哪些常用成员函数和成员变量? - Dotcpp编程

3.向量数组vector

C++ STL vector容器入门 - Dotcpp编程

3.1元素的增删查改

增:尾插法push_back()和emplace_back(),在指定位置前插入元素insert()和emplace()。

删:

函数参数及介绍
pop_back()参数: 无
介绍: 删除向量的最后一个元素,大小减1,容量不变
erase(position)参数: const_iterator position
介绍: 删除指定位置的单个元素,返回指向被删除元素之后元素的迭代器
erase(first, last)参数: const_iterator first, const_iterator last
介绍: 删除[first, last)范围内的元素,返回指向最后一个被删除元素之后元素的迭代器
clear()参数: 无
介绍: 删除所有元素,大小变为0,容量保持不变
resize(new_size)参数: size_type new_size
介绍: 如果new_size小于当前大小,则删除末尾的多余元素

查、改:通过访问方式访问向量中的元素+front()、back()。

3.2向量大小相关成员函数

size()、capacity()、reserve(n)、resize()、swap()和shrink_to_fit()、empty()。

4.deque双端队列

4.1增删查改

增:push_front()、push_back()、emplace_front()、emplace_back()、insert()、emplace()。

删:pop_front()、pop_back()、erase()、clear()、指定元素全清remove()(标准库中的)+erase()。

查、改:通过访问方式访问向量中的元素+front()、back()。

4.2向量大小相关成员函数

size()、max_size()、capacity()、resize()、swap()和shrink_to_fit()、empty(),没有预存函数。

5.list双向列表

5.1访问方式

仅支持迭代器。

5.2增删查改

增:push_front()、push_back()、emplace_front()、emplace_back()、insert()、emplace()、splice()。

删:pop_front()、pop_back()、erase()、clear()、unique()、remove()和remove_if()(这两个remove函数是list容器类中定义的,不是标准库中的)。

查、改:通过访问方式访问向量中的元素+front()、back()。

5.3向量大小相关成员函数

size()、max_size()、capacity()、resize()、swap()和shrink_to_fit()、empty(),没有预存函数。

5.4list迭代器

支持++、--但不支持+n、-n随机访问操作。

5.5forward_list单列表

类比list,但是迭代器仅支持从前往后,仅支持头增头删,没有back()、size()函数等等。

6.关联容器map(自动排序、有序、键值唯一性)

6.1迭代器(相对于序列式特有)(所有map迭代器只能进行++或--操作,不能+5或-8随机访问)

find()、lower_bound()、upper_bound()、equal_range()(equal_range()主要在multimap中用的多,map没啥用)(参数均为Key值,有则返回迭代器,无则返回end())。

6.2访问方式

迭代器(注意获取迭代器的几种方式)、at()、[]、指针,注意迭代器返回的是整个键值对的指针,还需要->second获取value;在知道key值的情况下,我们最好使用at(),其次是find(),最后是'[]',原因在于如果没有存在key="输入参数"的元素,at()会报错而find()会返回容器尾后迭代器end(),而'[]'直接给你创建一个“[输入的key]=默认值的元素(不同数据类型有不同的默认值),虽然不存在报错问题,但是却失去了对数据的绝对控制,破坏数据的完整性。

6.3增删查改

增:[](这里如果已存在key,则进行覆盖)、insert()(可一次插入多个)、emplace()(单个效率高)、emplace_hint()(有返回值,批量插入时效率最高)。

删:erase()、clear()。

查、改:通过访问方式。

7.multimap(自动排序、有序、键值可重复)

类似map,区别在于访问方式只能通过迭代器和指针。

8.set容器(自动排序去重、有序、键值唯一且键值相等且不能直接修改键对应的值)

8.1迭代器(相对于序列式特有)(所有set迭代器只能进行++或--操作,不能+5或-8随机访问)

find()、lower_bound()、upper_bound()、equal_range()、count()。

8.2访问方式

迭代器、指针。

8.3增删查改

增:insert()(可一次插入多个)、emplace()(单个效率高)、emplace_hint()(插入时注意set会自动排序和去重)。

删:erase()、clear()。

查、改:通过访问方式,修改只能先删除原有键值对,在增加修改的键值对。

9.multiset(自动排序、有序、键值可重复且键值相等)

可通过仿函数修改排序顺序,标准库<functional>。

10.无序关联容器底层逻辑

哈希表:

  • 核心思想是键值对;
  • 创建过程:通过哈希算法将任意输入转为统一形式输出(如数组下标),并在对应数组下标(该存放数组称为桶数组)位置存放该输入值;
  • 使用方式:类似创建过程,通过哈希表能实现高效查询,而避免遍历查询。

无序关联容器可视为基于哈希表的数组+链表:

创建过程:向堆区开辟了一段连续空间(可理解为数组),空间大小为n,每个单位空间被称为“桶”且能够存储一个头指针,头指针“牵引"着一个单向链表(双向链表太费内存了)。当我们输入一个键值对时,键会被哈希函数转变成哈希值hash,随后由hash&(n-1)找到在桶数组中对应的下标以及数组中存放的头指针,将键值对作为一个整体被封装在该头指针指向的链表的节点中。

无序关联式容器内都维护着一个重要的成员变量——load_factor(),它叫做负载因子,数据类型为float,其值=插入键值对总量/桶数量,功能是分析键值对的分布情况,当负载因子<0.5时,说明不管是空间利用率还是访问效率都比较高,反之。下面我们通过代码来分析插入键值对对负载因子的影响。

在存储基本数据类型时,键(key)能够通过哈希函数转为哈希值(数据类型为size_t),当我们的键为自定义数据类型时,就需要我们重新定义哈希函数和重载operator'=='运算符。

11.unordered_map(无序,键值对唯一)

11.1迭代器

由于哈希表的特性,使得unordered_map容器变得“无序”,所以它不在乎“顺序”没有“反向”这个概念,属于前向迭代器,只能进行++操作。

unordered_map容器有正向迭代器begin()、end(),常量迭代器cbegin()、cend()。

11.2访问方式

迭代器(获取迭代器的方式如find())、at()、[]。

11.3增删查改

增:[]、insert()、emplace()、emplace_hint()。

删:erase()、clear()。

查改:访问方式。

12.unordered_multimap(无序,键值可重复)

类似unordered_map(),区别在于访问方式只能通过迭代器和指针,且重点使用equal_range()。

13.unordered_set(去重,无序,键值一体且唯一因此不能直接修改键值对)

类似set()。

14.unordered_multiset(无序,键值一体可重复且因此不能直接修改键值对)

类似multiset()。

15.容器的选择

通常情况下,我们一般会面对以下四种需求:

1. 随机访问。

2. 频繁增删。

3. 查找且有序。

4. 快速查找。

面对第一种需求,我们尽量选择vector容器,因为它既拥有数组的连续访问性又能够“动态扩展”,其次再选择array容器或是deque容器。面对第二种需求,我们不用多想,肯定选择list容器,因为我们需要频繁对元素进行增删,如果你选vector这种容器,又要扩容又要复制,得多费时间啊。面对第三种需求,用map容器就最为合适了,就像我们查字典一样,根据拼音或部首进行字的查询,直接跳到对应的地方查字,就不用一页一页地找。最后一种数据库里最常见,比如银行系统就需要根据用户账户快速定位用户全部信息,及时更新数据。

二、迭代器

注意迭代器是由容器类型定义的,不是由容器对象定义,begin()、end()、rbegin()、rend()、cbegin()、cend()、crbegin()、crend()。
迭代器的类型由功能决定而不是函数决定,即map容器的begin()返回的是双向迭代器,而unordered_multimap的begin()返回的是前向迭代器。

反向迭代器的移动,从rbegin到rend也是++操作(前向++)。

vector是动态数组,增减元素都会导致位置变化,所以在使用迭代器时要及时更新迭代器,否则导致迭代器失效,造成程序崩溃等未定义行为,vector和deque均需要及时更新迭代器。但list通过指针连接上下节点,即使增减元素也不会改变原来元素的位置,因此不用更新迭代器。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐