C++容器的介绍和使用

一、概述

定义:容器是用来存储和组织数据的类模板
总结:容器-顾名思义就是拿来装东西的。你可以装标准的基本数据类型,如int,double,string等、也可以装复杂的自定义类型,例如class 定义的类的对象,对象指针等复合类型的数据。
        C++ stl标准库提供了多种容器,每种容器都有特定的用途和性能特点。以下是 C++ 标准库中一些常见的容器:

二、容器分类

(1)顺序容器

名称说明头文件
std::vector动态数组,支持快速随机访问和尾部插入/删除<vector>
std::list双向链表,支持快速插入/删除操作<list>
std::deque双端队列,支持在两端进行快速插入/删除操作<deque>
std::array固定大小的数组,提供与 C 风格数组类似的接口,但更安全和易用<array>

(2)关联容器

名称说明头文件
std::map键-值对的关联容器,基于红黑树实现,支持按键进行快速查找<map>
std::multimap允许重复键的键-值对关联容器。<map>
std::set唯一键的集合,基于红黑树实现,支持按值进行快速查找<set>
std::multiset允许重复键的集合容器<set>

(3)无序容器

名称说明头文件
std::unordered_map使用哈希表实现的键-值对关联容器,支持快速的插入/删除/查找操作<unordered_map>
std::unordered_multimap使用哈希表实现的允许重复键的键-值对关联容器<unordered_map>
std::unordered_set使用哈希表实现的唯一键集合,支持快速的插入/删除/查操作<unordered_set>
std::unordered_multiset使用哈希表实现的允许重复键的集合容器<unordered_set>

(4)其他容器

名称说明头文件
std::stack栈,基于其他顺序容器实现的后进先出数据结构<stack>
std::queue队列,基于其他顺序容器实现的先进先出数据结构<queue>
std::priority_queue优先队列,基于堆实现的数据结构,支持高效的最大/最小值检索<queue>
std::bitset固定大小的位集容器,可以高效地存储和操作位数据<bitset>
std::tuple用于存储多个不同类型的值,类似于结构体,但更通用和灵活<tuple>
std::any可以存储任意类型值的容器,类似于动态类型语言中的变量<any>
std::optional表示一个可选的值,可以避免使用空指针或特殊值来表示缺失值<optional>

三、如何选择适合的容器?

3.1 std::vector

  • 应用场景:当需要一个可变大小的数组,并且需要在末尾进行快速插入和删除操作时,std::vector 是一个不错的选择。此外,如果需要通过索引进行快速随机访问,也可以选择 std::vector
  • 注意事项:在中间插入或删除元素时可能会比较慢,因为需要移动后续元素。

3.2 std::list

  • 应用场景:当需要在任意位置进行快速插入和删除操作时,std::list 是一个不错的选择。它是一个双向链表,可以高效地进行插入和删除操作。
  • 注意事项:随机访问性能较差,因此不适合需要频繁随机访问元素的情况。

3.3 std::deque

  • 应用场景:当需要在两端进行快速插入和删除操作时,std::deque 是一个不错的选择。它可以看作是 std::vector 的泛化版本,支持在两端进行高效操作。
  • 注意事项:在中间插入或删除元素时性能可能比较低。

3.4 std::array

  • 应用场景:当需要一个固定大小的数组,并且希望拥有数组的性能和语法上的方便时,std::array 是一个不错的选择。
  • 注意事项:大小固定,不能动态扩展。

3.5 std::map

  • 应用场景:适合需要键-值对映射关系,并且需要基于键进行快速查找的场景。适合需要唯一键和对数级别查找性能的情况。
  • 注意事项:插入和查找的时间复杂度为 O(log n),相较于数组或链表,其常数项略大,因此在小规模数据或性能要求特别高的情况下,可能不是最佳选择。

3.6 std::multimap

  • 应用场景:适合需要键-值对映射关系,并且允许重复键的情况。std::multimap允许多个元素拥有相同的键,因此适合这种需求的场景。
  • 注意事项:通过键进行查找时会返回一个范围,因为可能有多个元素拥有相同的键。

3.7 std::set

  • 应用场景:适合需要一个有序、不重复元素集合的情况。std::set中的元素是按照严格弱序排列的,且集合中不允许重复元素。
  • 注意事项:插入和查找操作的时间复杂度为O(log n),具有较高的性能。

3.8 std::multiset

  • 应用场景:适合需要一个有序元素集合,并且允许重复元素存在的情况。std::multiset允许集合中存在相同的元素。
  • 注意事项:与std::set类似,但允许重复元素存在。

3.9 std::unordered_map

  • 应用场景:适合需要键-值对映射关系,并且对于查找操作有较高性能要求的情况。std::unordered_map基于哈希表实现,具有常数时间复杂度的查找操作。
  • 注意事项:相较于std::map,哈希冲突可能会影响性能,同时不保证元素的顺序。

3.10 std::unordered_multimap

  • 应用场景:适合需要键-值对映射关系,并且允许重复键存在,同时对于查找操作有较高性能要求的情况。std::unordered_multimap基于哈希表实现,允许重复键存在。
  • 注意事项:同样可能存在哈希冲突和无序性的问题。

3.11 std::unordered_set

  • 应用场景:适合需要一个无序、不重复元素集合,并且对于查找操作有较高性能要求的情况。std::unordered_set基于哈希表实现,具有常数时间复杂度的查找操作。
  • 注意事项:不保证元素的顺序,可能存在哈希冲突。

3.12 std::unordered_multiset

  • 应用场景:适合需要一个无序元素集合,并且允许重复元素存在,同时对于查找操作有较高性能要求的情况。std::unordered_multiset基于哈希表实现,允许重复元素存在。
  • 注意事项:同样可能存在哈希冲突和无序性的问题。

3.13 std::stack

  • 应用场景:适合需要“后进先出”(LIFO)数据结构的情况。std::stack基于其他容器(默认为std::deque)实现,提供了栈的基本操作。

3.14 std::queue

  • 应用场景:适合需要“先进先出”(FIFO)数据结构的情况。std::queue基于其他容器(默认为std::deque)实现,提供了队列的基本操作。

3.15 std::priority_queue

  • 应用场景:适合需要按照一定顺序动态获取最大(或最小)值的情况。std::priority_queue通常基于堆实现,可以高效地获取当前堆中的最大(或最小)值。

3.16 std::bitset

  • 应用场景:适合需要高效存储位信息的情况。std::bitset是一个固定大小的位集合,支持进行位操作,并且在存储和查询位信息方面具有较高的性能。

3.17 std::tuple

  • 应用场景:适合需要将多个值作为一个整体处理的情况。std::tuple可以看作是一个通用的轻量级结构体,用于将若干个值组合成一个整体。

3.18 std::any

  • 应用场景:适合需要在运行时存储和访问任意类型的值的情况。std::any可以存储任何类型的值,提供了一种通用的值容器。

3.19 std::optional

  • 应用场景:适合表示可能不存在值的情况。std::optional可以包含一个值或者为空,用于代表一个可能缺失的值。

四、关键容器的对比

        以上列出了所介绍的容器的应用场景和注意事项,有的容器,对于应用场景不同的容器,选择起来很容易,对于应用场景相同的场景,选择起来需要考虑性能,以下对几个比较特殊的容器进行详细对比:

4.1 std::mapstd::unordered_map

主要区别在于底层实现和查找性能。

std::map

  • std::map 是基于红黑树实现的关联容器,它将键-值对按照键的大小进行排序存储。这意味着在使用 std::map 时,元素是按照键值的大小有序排列的。
  • 查找、插入和删除操作的平均时间复杂度为 O(log n),具有较好的有序性能。

std::unordered_map

  • std::unordered_map 是基于哈希表实现的关联容器,它使用键的哈希值来组织和快速查找元素。这意味着在使用 std::unordered_map 时,元素是无序存储的。
  • 查找、插入和删除操作的平均时间复杂度为 O(1),具有非常高的查找性能,但不保证元素的顺序。

总结:

  • std::map 保持元素的有序性,适合需要有序访问的场景,而 std::unordered_map 不保证元素的顺序,但提供了更快的查找性能。
  • 在对有序性要求不高,但对查找性能有较高要求的情况下,可以选择 std::unordered_map 来获得更好的性能。

4.2 std::multimap与std::unordered_multimap

std::multimap

  • std::multimap 是基于红黑树实现的关联容器,允许多个元素拥有相同的键。它按照键的大小进行排序存储,因此在使用 std::multimap 时,元素是按照键值的大小有序排列的。
  • 查找、插入和删除操作的平均时间复杂度为 O(log n),并且保持元素的有序性。

std::unordered_multimap

  • std::unordered_multimap 是基于哈希表实现的关联容器,同样允许多个元素拥有相同的键。它使用键的哈希值来组织和快速查找元素,因此在使用 std::unordered_multimap 时,元素是无序存储的。
  • 查找、插入和删除操作的平均时间复杂度为 O(1),具有非常高的查找性能,但不保证元素的顺序。

 4.3 std::set 与 std::unordered_set

  std::set:

  • std::set 是基于红黑树实现的集合容器,用于存储不重复的元素,并按照元素的大小进行排序存储。这意味着在使用 std::set 时,元素是按照大小有序排列的。
  • 查找、插入和删除操作的平均时间复杂度为 O(log n),并且保持元素的有序性。

std::unordered_set

  • std::unordered_set 是基于哈希表实现的集合容器,用于存储不重复的元素,但不保证元素的顺序。它使用元素的哈希值来组织和快速查找元素,因此在使用 std::unordered_set 时,元素是无序存储的。
  • 查找、插入和删除操作的平均时间复杂度为 O(1),具有非常高的查找性能,但不保证元素的顺序。

因此,主要区别可以总结如下:

  • std::set 保持元素的有序性,适合需要有序访问的场景,而 std::unordered_set 不保证元素的顺序,但提供了更快的查找性能。
  • 在对有序性要求不高,但对查找性能有较高要求的情况下,可以选择 std::unordered_set 来获得更好的性能

4.4 总结

         对于map,set,multimap,multiset,当对顺序有要求时候,选择这些,对顺序无要求时候,可以选择带unordered_前缀的容器,以提高性能。

五、总结

        本文介绍了C++11 stl常见的容易得分类,应用场景以及性能对比,仔细阅读本文,你应该可以选择出合适的容易用于你的项目中。

        后续章节将详细介绍本文所提到的所有的容器的使用方法,代码示例,将详细介绍每一种容器的:增、删、改、查、遍历。

  • 28
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中的vector是一个动态数组,可以根据需要随时调整大小。它是标准库中最常用的容器之一,提供了许多方便的成员函数和操作符重载。 使用vector容器需要包含头文件`<vector>`。 下面是一些vector容器的特点和常用操作: 1. 动态大小:vector可以根据需要动态调整大小,可以在任意位置插入或删除元素。 2. 快速随机访问:vector支持通过索引快速访问元素,时间复杂度为O(1)。 3. 连续存储:vector的元素在内存中是连续存储的,这样可以提高访问效率。 4. 自动内存管理:vector会自动管理内部的动态内存分配和释放,无需手动管理。 5. 范围检查:vector会在访问操作时进行边界检查,确保不越界。 以下是一些常用的vector操作: - `push_back(value)`:在vector末尾添加一个元素。 - `pop_back()`:删除vector末尾的元素。 - `size()`:返回vector中元素的个数。 - `empty()`:判断vector是否为空。 - `clear()`:清空vector中的所有元素。 - `at(index)`:返回指定索引位置的元素,并进行范围检查。 - `front()`:返回第一个元素。 - `back()`:返回最后一个元素。 - `insert(iterator, value)`:在指定位置插入一个元素。 - `erase(iterator)`:删除指定位置的元素。 - `begin()`和`end()`:返回指向vector第一个元素和最后一个元素之后的迭代器,用于循环遍历。 vector容器提供了丰富的功能,并且易于使用,适合在需要动态大小和快速访问的情况下使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值