当前位置: 首页 > news >正文

C++之STL--list

list

  • list
    • 一、`std::list` 的构造方法
      • 1. 默认构造
      • 2. 指定大小构造
      • 3. 从其他容器构造
      • 4. 使用初始化列表构造
    • 二、`std::list` 的迭代器
      • 1. 迭代器的获取
      • 2. 迭代器的使用
      • 3. 常量迭代器
    • 三、`std::list` 的容量
      • 1. 检查是否为空
      • 2. 获取元素数量
      • 3. 清空列表
    • 四、`std::list` 的元素访问
    • 五、`std::list` 的元素修改
      • 1. 添加元素
      • 2. 删除元素
      • 3. 修改元素
    • 六、`std::list` 的迭代器失效问题
      • 1. 何时迭代器会失效
      • 2. 如何避免迭代器失效
  • `std::list` 与 `std::vector` 的对比
    • 一、数据结构
      • 1. `std::list`:双向链表
      • 2\. `std::vector`:动态数组
    • 二、内存分配
      • 1. `std::list`
      • 2. `std::vector`
    • 三、插入和删除操作
      • 1. `std::list`
      • 2. `std::vector`
    • 四、随机访问
      • 1. `std::list`
      • 2. `std::vector`
    • 五、迭代器
      • 1. `std::list`
      • 2. `std::vector`
    • 六、性能对比
      • 1. 时间复杂度
      • 2. 内存使用
    • 七、适用场景
      • 1. `std::list` 适用场景
      • 2. `std::vector` 适用场景

在这里插入图片描述

list

在 C++ 标准模板库(STL)中,std::list 是一个非常灵活且强大的双向链表容器。它提供了高效的插入和删除操作,非常适合需要频繁动态调整元素的场景。

一、std::list 的构造方法

std::list 提供了多种构造方法,以满足不同的初始化需求:

1. 默认构造

std::list<int> myList;

这会创建一个空的 std::list,不包含任何元素。

2. 指定大小构造

std::list<int> myList(5); // 创建一个包含 5 个默认初始化为 0 的 int 元素的 list

你可以指定初始大小,并且可以为元素提供默认值:

std::list<int> myList(5, 10); // 创建一个包含 5 个值为 10 的 int 元素的 list

3. 从其他容器构造

你可以使用另一个容器的内容来初始化 std::list

std::vector<int> vec = {1, 2, 3, 4, 5};
std::list<int> myList(vec.begin(), vec.end()); // 从 vector 的内容构造 list

4. 使用初始化列表构造

std::list<int> myList = {1, 2, 3, 4, 5};

这种方式简洁明了,非常适合快速初始化。

二、std::list 的迭代器

std::list 是一个双向链表,因此它提供的是双向迭代器。这意味着你可以通过迭代器向前或向后遍历列表。

1. 迭代器的获取

std::list<int>::iterator it = myList.begin(); // 获取指向第一个元素的迭代器
std::list<int>::iterator end = myList.end(); // 获取指向最后一个元素之后的迭代器

begin()end() 分别返回指向第一个元素和最后一个元素之后的迭代器。

2. 迭代器的使用

你可以通过迭代器访问和修改元素:

for (std::list<int>::iterator it = myList.begin(); it != myList.end(); ++it) {std::cout << *it << " "; // 访问元素*it = *it * 2; // 修改元素
}

3. 常量迭代器

如果你只需要读取元素,而不需要修改它们,可以使用常量迭代器:

for (std::list<int>::const_iterator cit = myList.cbegin(); cit != myList.cend(); ++cit) {std::cout << *cit << " ";
}

三、std::list 的容量

std::list 是一个动态容器,其容量会根据元素的添加和删除自动调整。不过,它也提供了一些方法来管理容量:

1. 检查是否为空

if (myList.empty()) {std::cout << "List is empty." << std::endl;
}

empty() 方法返回一个布尔值,表示列表是否为空。

2. 获取元素数量

std::cout << "Number of elements: " << myList.size() << std::endl;

size() 方法返回列表中元素的数量。

3. 清空列表

myList.clear();

clear() 方法会移除列表中的所有元素,但不会释放内存。

四、std::list 的元素访问

由于 std::list 是一个链表结构,它不支持随机访问,因此没有像数组或 std::vector 那样的下标操作符 []。不过,你可以通过迭代器来访问元素:

std::list<int>::iterator it = myList.begin();
std::cout << *it << std::endl; // 访问第一个元素

如果你需要频繁访问特定位置的元素,建议使用其他容器(如 std::vector)。

五、std::list 的元素修改

std::list 提供了多种方法来添加、删除和修改元素:

1. 添加元素

  • 在头部添加元素

    myList.push_front(10);
    
  • 在尾部添加元素

    myList.push_back(20);
    
  • 在指定位置插入元素

    std::list<int>::iterator it = myList.begin();
    myList.insert(it, 15); // 在第一个元素之前插入 15
    

2. 删除元素

  • 删除头部元素

    myList.pop_front();
    
  • 删除尾部元素

    myList.pop_back();
    
  • 删除指定位置的元素

    std::list<int>::iterator it = myList.begin();
    myList.erase(it); // 删除第一个元素
    

3. 修改元素

你可以通过迭代器直接修改元素:

std::list<int>::iterator it = myList.begin();
*it = 100; // 修改第一个元素的值

六、std::list 的迭代器失效问题

在使用 std::list 时,迭代器失效是一个需要注意的问题。迭代器失效是指迭代器不再指向有效的元素,这通常发生在对容器进行修改操作时。

1. 何时迭代器会失效

  • 插入操作:在 std::list 中插入元素不会使任何迭代器失效。这是因为 std::list 是一个双向链表,插入操作不会影响已有的元素位置。

  • 删除操作:当你删除一个元素时,指向该元素的迭代器会失效。例如:

    std::list<int>::iterator it = myList.begin();
    myList.erase(it); // it 现在失效
    

    如果你需要继续使用迭代器,应该在删除操作后获取新的迭代器:

    std::list<int>::iterator it = myList.begin();
    it = myList.erase(it); // it 现在指向下一个有效元素
    

2. 如何避免迭代器失效

  • 在删除元素时,及时更新迭代器:如上例所示,erase() 方法会返回指向下一个有效元素的迭代器。
  • 避免在循环中直接删除元素:如果你需要在循环中删除多个元素,建议使用 remove_if()remove() 方法,或者使用一个临时迭代器来管理删除操作。

std::liststd::vector 的对比

一、数据结构

1. std::list:双向链表

std::list 是一个双向链表结构。每个元素通过指针(或引用)与前一个元素和后一个元素相连。链表结构使得 std::list 在插入和删除操作上非常高效,但不支持随机访问。

2. std::vector:动态数组

std::vector 是一个动态数组结构。它在内存中以连续的方式存储元素,支持快速的随机访问,但在插入和删除操作(尤其是非尾部操作)上可能效率较低。

二、内存分配

1. std::list

  • 内存分配std::list 的每个元素单独分配内存,因此内存分配较为分散。
  • 内存开销:每个元素除了存储数据外,还需要额外的空间来存储指针(或引用),用于连接前后元素。因此,std::list 的内存开销相对较大。
  • CPU高速缓存命中率低

2. std::vector

  • 内存分配std::vector 的内存是连续分配的。它会根据需要动态调整内存大小,但每次调整可能会涉及内存复制。
  • 内存开销std::vector 的内存开销相对较小,因为它只需要存储元素本身,而不需要额外的指针。
  • CPU高速缓存命中率高

三、插入和删除操作

1. std::list

  • 插入操作
    • 时间复杂度:O(1),插入操作只需要更新前后元素的指针。
    • 适用场景:适合在任意位置频繁插入元素。
  • 删除操作
    • 时间复杂度:O(1),删除操作只需要更新前后元素的指针。
    • 适用场景:适合在任意位置频繁删除元素。

2. std::vector

  • 插入操作
    • 时间复杂度:O(n),插入操作可能需要移动插入点之后的所有元素。
    • 适用场景:适合在尾部插入元素,因为尾部插入的时间复杂度为 O(1)。
  • 删除操作
    • 时间复杂度:O(n),删除操作可能需要移动删除点之后的所有元素。
    • 适用场景:适合在尾部删除元素,因为尾部删除的时间复杂度为 O(1)。

四、随机访问

1. std::list

  • 随机访问:不支持随机访问,只能通过迭代器逐个遍历元素。
  • 适用场景:适合不需要随机访问的场景。

2. std::vector

  • 随机访问:支持快速随机访问,通过下标可以直接访问任意位置的元素。
  • 适用场景:适合需要频繁随机访问元素的场景。

五、迭代器

1. std::list

  • 迭代器类型:双向迭代器,支持向前和向后遍历。
  • 迭代器失效:插入操作不会使迭代器失效,但删除操作会使指向被删除元素的迭代器失效。

2. std::vector

  • 迭代器类型:随机访问迭代器,支持随机访问。
  • 迭代器失效:插入或删除操作会使所有指向被修改区域的迭代器失效。

六、性能对比

1. 时间复杂度

操作类型std::liststd::vector
插入(任意位置)O(1)O(n)
删除(任意位置)O(1)O(n)
随机访问O(n)O(1)
遍历O(n)O(n)

2. 内存使用

  • std::list:内存使用较为分散,每个元素需要额外的指针空间。
  • std::vector:内存使用较为紧凑,但可能需要预留额外空间以支持动态扩展。

七、适用场景

1. std::list 适用场景

  • 需要在任意位置频繁插入和删除元素。
  • 不需要随机访问元素。
  • 对内存使用分散性不敏感。

2. std::vector 适用场景

  • 需要频繁随机访问元素。
  • 主要在尾部插入和删除元素。
  • 对内存使用紧凑性有要求。
http://www.xdnf.cn/news/916993.html

相关文章:

  • LeetCode 239. 滑动窗口最大值(单调队列)
  • 【Hot 100】295. 数据流的中位数
  • 客户端和服务器已成功建立 TCP 连接【输出解析】
  • Doris 数据库深度解析:架构、原理与实战应用
  • 5.4.2 Spring Boot整合Redis
  • Cisco Packer Tracer 综合实验
  • 网页绘制表格
  • 8个AI软件介绍及其工作原理讲解
  • 基于功能基团的3D分子生成扩散模型 - D3FG 评测
  • Java编程中常见的条件链与继承陷阱
  • 60天python训练计划----day46 and day47
  • 比较数据迁移后MySQL数据库和ClickHouse数据仓库中的表
  • Faiss vs Milvus 深度对比:向量数据库技术选型指南
  • 在 Linux 中修改 Apache HTTP Server(httpd)默认端口的完整指南
  • 电路图识图基础知识-电动机制动控制电路(十八)
  • 【力扣】2434.使用机器人打印字典序最小的字符串
  • 计算机组成原理-总线
  • rabbit mq使用TTL和DLX实现延迟队列
  • ios苹果系统,js 滑动屏幕、锚定无效
  • Go 标准库 encoding/gob 快速上手
  • NLP学习路线图(三十一): 迁移学习在NLP中的应用
  • 在ROS中实现消息通信和服务通信Python
  • 【图像处理基石】如何构建一个简单好用的美颜算法?
  • 【win | docker开启远程配置】使用 SSH 隧道访问 Docker的前操作
  • 手拉手处理RuoYi脚手架常见文问题
  • win11系统 Docker Desktop 突然提示Docker Engine stopped解决情况之一
  • CentOS 7.9安装Nginx1.24.0时报 checking for LuaJIT 2.x ... not found
  • 【Linux】系统部分——进程控制
  • 使用 Python + SQLAlchemy 创建知识库数据库(SQLite)—— 构建本地知识库系统的基础《一》
  • Python Cookbook-7.11 在 PostgreSQL 中储存 BLOB