【3-22 list 详解STL C++ 】

先看代码,常用的就是代码中有的那些

#include <bits/stdc++.h>
using namespace std;
int main() {list<int> mylist;for(int i=0;i<5;i++){mylist.push_back(i);//TODO}for(const auto&i:mylist)cout<<i<<'\n';//fanzhuanreverse(mylist.begin(),mylist.end());cout<<" 	//fanzhuan\n ";for(const auto&i:mylist){cout<<i<<'\n';	//TODO}mylist.insert(++mylist.begin(),9);cout<<" 	//插入\n ";for(const auto&i:mylist){cout<<i<<'\n';	//TODO}	mylist.erase(++ mylist.begin(),--mylist.end());//删除了一个区间的数cout<<"size"<<mylist.size()<<'\n';for(const auto&i:mylist){cout<<i<<'\n';	//TODO}	return 0;}
  1. List的核心操作:如push_back, push_front, pop_back, pop_front等。
  2. 迭代器使用:如何遍历list,不同迭代器的区别(正向、反向)。
  3. 容量与大小管理:size(), empty(), clear()等方法,以及与vector在内存管理上的对比。
  4. 元素访问:通过迭代器和下标访问的效率差异,at()方法的使用。
  5. 插入与删除操作:在特定位置插入或删除元素的效率,erase方法的不同用法。
  6. 自定义类型支持:如何存储对象,需要重载哪些运算符。
  7. 性能比较:list在插入删除时的优势,以及随机访问的劣势。
  8. 实际应用案例:比如实现栈、队列,或者作为链表结构的使用场景。

一、核心成员函数详解(修正拼写错误后)

函数名称功能说明示例代码注意事项
push_back()在链表尾部插入元素lst.push_back(10);时间 O(1)
push_front()在链表头部插入元素lst.push_front(20);时间 O(1)
pop_back()移除链表尾部元素lst.pop_back();空容器调用会崩溃
pop_front()移除链表头部元素lst.pop_front();同上
size()返回链表元素个数int n = lst.size();O(1)
empty()检查链表是否为空if (lst.empty()) {...}O(1)
clear()清空所有元素lst.clear();O(n)
front()获取第一个元素的引用int x = lst.front();空容器调用崩溃
back()获取最后一个元素的引用int y = lst.back();同上
begin()返回首元素的迭代器auto it = lst.begin();
end()返回尾元素后继的迭代器auto rit = lst.rbegin();
insert(pos, val)在位置 pos 前插入元素lst.insert(lst.begin()+1, 30);时间 O(n)
erase(pos)删除位置 pos 的元素lst.erase(lst.begin()+1);同上

二、常用扩展函数(图片未提及)

函数名称功能说明示例代码
emplace_back(val)在尾部直接构造元素(比 push_back 更高效)lst.emplace_back(100);
splice(pos, other)将另一个链表的元素插入到当前位置lst.splice(it, other_lst);
merge(other)合并两个有序链表(保持有序性)auto merged = merge(&a, &b);
remove(val)删除所有等于 val 的元素lst.remove(5);
reverse()反转链表顺序lst.reverse();
assign(range)用区间内的元素覆盖当前链表lst.assign(arr.begin(), arr.end());

三、安全操作示例

#include <iostream>
#include <list>
using namespace std;int main() {list<int> lst;// 安全插入lst.push_back(1);lst.push_front(2);// 避免空容器操作if (!lst.empty()) {cout << "首元素: " << lst.front() << endl; // 输出 2cout << "末元素: " << lst.back() << endl;   // 输出 1}// 使用迭代器安全删除if (lst.size() > 0) {auto it = lst.begin();lst.erase(it); // 删除第一个元素}return 0;
}

四、list vs vector 对比分析

特性list(双向链表)vector(动态数组)
内存分配分散的内存块(指针开销大)连续内存块(紧凑存储)
插入/删除效率头部 O(1),中间 O(1)(已知位置)头部 O(n),中间 O(n)
随机访问O(n)(需遍历)O(1)(直接索引)
内存占用较高(每个节点存储指针)较低(仅存储数据)
迭代器失效性仅被删除元素的迭代器失效所有迭代器可能失效(扩容时)
适用场景频繁插入/删除元素频繁随机访问元素

1. 实现LRU缓存(基于list和unordered_map)
#include <list>
#include <unordered_map>
using namespace std;template<typename K, typename V>
class LRUCache {
private:list<pair<K, V>> cache; // 按访问顺序排列unordered_map<K, typename list<pair<K, V>>::iterator> pos_map;size_t capacity;public:LRUCache(size_t cap) : capacity(cap) {}void get(K key) {auto it = pos_map.find(key);if (it == pos_map.end()) return;// 将节点移到头部(最近使用)cache.splice(cache.begin(), cache, it->second);}void put(K key, V value) {auto it = pos_map.find(key);if (it != pos_map.end()) {// 更新值并移到头部it->second->second = value;cache.splice(cache.begin(), cache, it->second);} else {if (cache.size() >= capacity) {// 删除末尾元素(最久未使用)auto last = cache.end();--last;pos_map.erase(last->first);cache.pop_back();}// 插入新节点到头部auto newNode = cache.emplace_front(key, value);pos_map[key] = newNode;}}
};
2. 双向链表反转
void reverse_list(list<int>& lst) {auto it1 = lst.begin();auto it2 = lst.end();while (it1 != it2) {swap(*it1, *it2);++it1;--it2;}
}

二、核心内容架构

1. 双向链表节点的底层实现

节点结构体解析

template<typename T>
struct Node {T data;          // 存储元素Node* prev;       // 前驱指针Node* next;       // 后继指针Node(const T& val) : data(val), prev(nullptr), next(nullptr) {}
};

内存分配策略
节点池技术:预分配内存块减少动态分配开销
分配器模式:与vector不同的allocator实现(如__gnu_pbds::node_allocator)

2. 关键成员函数源码剖析

构造函数

list() : head(nullptr), tail(nullptr), size(0) {} // 空链表初始化
list(initializer_list<T> il) { ... } // 包含初始化列表的构造

动态扩容机制
无需扩容:链表结构支持O(1)时间复杂度的头尾插入/删除
迭代器失效性:只有被删除元素的迭代器会失效,其他迭代器保持有效

3. 高效操作实现原理

push_back()

void push_back(const T& val) {Node* newNode = allocator.allocate(1);allocator.construct(newNode, val);if (empty()) {head = tail = newNode;} else {tail->next = newNode;newNode->prev = tail;tail = newNode;}++size;
}

insert(pos, val)
定位节点:双向链表支持O(n)时间复杂度定位
指针调整:四步操作(新节点创建→前后指针重新链接)

4. 与vector的对比实验
操作listvector
头部插入O(1)O(n)
中间插入O(1)(已知位置)O(n)
随机访问O(n)O(1)
内存占用较高(指针开销)较低(紧凑存储)
适用场景频繁插入/删除频繁随机访问

三、代码示例与调试

1. 实现链表反转(迭代器版)
void reverse_list(list<int>& lst) {auto it1 = lst.begin();auto it2 = lst.end();while (it1 != it2) {swap(*it1, *it2);++it1;--it2;}
}
2. 模拟LRU缓存淘汰算法
#include <list>
#include <unordered_map>template<typename K, typename V>
class LRUCache {
private:list<pair<K, V>> cache; // 按访问顺序排列unordered_map<K, typename list<pair<K, V>>::iterator> pos_map;size_t capacity;public:LRUCache(size_t cap) : capacity(cap) {}void get(K key) {auto it = pos_map.find(key);if (it == pos_map.end()) return;// 将访问的节点移到链表头部cache.splice(cache.begin(), cache, it->second);}void put(K key, V value) {auto it = pos_map.find(key);if (it != pos_map.end()) {// 存在则更新值并移动到头部it->second->second = value;cache.splice(cache.begin(), cache, it->second);} else {if (cache.size() >= capacity) {// 淘汰末尾元素auto last = cache.end();--last;pos_map.erase(last->first);cache.pop_back();}// 插入新节点到头部auto newNode = cache.emplace_front(key, value);pos_map[key] = newNode;}}
};

四、进阶知识点

1. 内存泄漏检测技巧

• 使用Valgrind工具检测链表节点泄漏:

valgrind --leak-check=yes ./a.out
2. 自定义内存池优化
template<typename T>
class FastList : public std::list<T> {
private:struct Pool {T* buffer;size_t capacity;Pool(size_t cap) : capacity(cap) {buffer = static_cast<T*>(malloc(cap * sizeof(T)));}~Pool() { free(buffer); }};Pool pool(1024); // 预分配1024个节点// 重载allocatorusing allocator_type = typename std::list<T>::allocator_type;allocator_type alloc;public:FastList() : std::list<T>(alloc), pool(1024) {this->allocator = alloc; // 绑定自定义分配器}
};

五、学习建议

  1. 配套书籍推荐
    • 《Effective STL》Item 10:选择合适的容器
    • 《C++ Primer》第16章:链表容器详解

  2. 实验环境配置

    g++ -std=c++17 -Wall -Wextra list_exercise.cpp -o list_exercise
    
  3. 常见错误总结
    • 误用operator[]访问链表(仅vector支持随机访问)
    • 忘记释放自定义分配的内存(内存泄漏)
    • 在迭代器失效后继续操作(未理解链表结构特性)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/74551.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

田间机器人幼苗视觉检测与护苗施肥装置研究(大纲)

田间机器人幼苗视觉检测与护苗施肥装置研究 基于多光谱视觉与精准施肥的农业机器人系统设计 第一章 绪论 1.1 研究背景与意义 农业智能化需求&#xff1a; 传统幼苗检测依赖人工&#xff0c;效率低且易遗漏弱苗/病苗施肥不精准导致资源浪费和环境污染 技术挑战&#xff1a;…

如何在Linux CentOS上安装和配置Redis

如何在Linux CentOS上安装和配置Redis 大家好&#xff0c;我是曾续缘。欢迎来到本教程&#xff01;今天我将向您介绍在Linux CentOS上安装和配置Redis的详细步骤。Redis是一个高性能的键值存储系统&#xff0c;常用于缓存、消息队列和数据持久化等应用场景。让我们一起开始吧&…

requests库post方法怎么传params类型的参数

在使用 requests 库的 post 方法时&#xff0c;params 类型的参数通常用于在 URL 中作为查询字符串传递。这与 data 或 json 参数不同&#xff0c;后者是放在请求体中的。下面详细介绍如何在使用 post 方法时传递 params 参数。 使用 params 参数 params 参数接受一个字典或包…

C++常见问题与思考

TLS&#xff08;线程本地存储&#xff09;原理 线程本地存储&#xff08;Thread Local Storage&#xff0c;TLS&#xff09;是一种机制&#xff0c;它允许每个线程拥有自己独立的变量实例&#xff0c;这些变量的生命周期与线程相同。也就是说&#xff0c;不同线程对同一个 TLS…

如何快速下载并安装 Postman?

从下载、安装、启动 Postman 这三个方面为大家详细讲解下载安装 Postman 每一步操作&#xff0c;帮助初学者快速上手。 Postman 下载及安装教程(2025最新)

使用Gitee Go流水线部署个人项目到服务器指南

使用Gitee Go流水线部署个人项目到服务器指南 前言&#xff01;&#xff01;&#xff01; 本文解决的问题&#xff1a; 你有一台ECS服务器&#xff0c;你在上面部署了一个Java服务也就是一个jar&#xff0c;你觉着你每次手动本地打包&#xff0c;上传&#xff0c;在通过命令去…

Linux第一节:Linux系统编程入门指南

摘要 本文面向Linux初学者&#xff0c;系统讲解操作系统核心概念、Shell命令实战、权限管理精髓及目录结构解析。通过思维导图命令示例原理解析的方法&#xff0c;帮助开发者快速构建Linux知识体系&#xff0c;掌握生产环境必备技能。 一、Linux的前世今生&#xff1a;从实验室…

【Linux 维测专栏 5 -- linux pstore 使用介绍】

文章目录 Linux pstore 功能简介1. pstore 概述2. pstore 的核心功能3. pstore 的工作原理4. pstore 的使用示例5. pstore 的优势6. 典型应用场景配置示例1)DTS配置2)config配置运行测试及log问题小结Linux pstore 功能简介 1. pstore 概述 pstore(Persistent Storage)是…

在 ASP .NET Core 9.0 中使用 Scalar 创建漂亮的 API 文档

示例代码&#xff1a;https://download.csdn.net/download/hefeng_aspnet/90407900 Scalar 是一款可帮助我们为 API 创建精美文档的工具。与感觉有些过时的默认 Swagger 文档不同&#xff0c;Scalar 为 API 文档提供了全新而现代的 UI。其简洁的设计让开发人员可以轻松找到测试…

Rabbitmq消息被消费时抛异常,进入Unacked 状态,进而导致消费者不断尝试消费(下)

一、消费流程图 消息在消费出现异常的时候&#xff0c;将一直保留在消息队列&#xff0c;所以你会看到以下奇怪的现象&#xff1a; 消息队列仅有5个消息&#xff0c; 投递速度也非常快&#xff0c;结果却一直无法消费掉。 二、重试策略 重试机制的使用场景&#xff1a;重试机制…

【STM32】知识点介绍二:GPIO引脚介绍

文章目录 一、概述二、GPIO的工作模式三、寄存器编程 一、概述 GPIO&#xff08;英语&#xff1a;General-purpose input/output&#xff09;,即通用I/O(输入/输出)端口&#xff0c;是STM32可控制的引脚。STM32芯片的GPIO引脚与外部设备连接起来&#xff0c;可实现与外部通讯、…

JavaScript流程控制精讲(二)运算符与循环实战

JavaScript流程控制精讲&#xff08;二&#xff09;运算符与循环实战 学习目标&#xff1a;掌握条件判断与循环控制&#xff0c;实现基础业务逻辑 核心要点&#xff1a;运算符优先级 | 短路运算 | 循环优化 | 项目实战 一、运算符进阶技巧 1.1 算术运算符 console.log(5 % 3)…

如何在IPhone 16Pro上运行python文件?

在 iPhone 16 Pro 上运行 Python 文件需要借助第三方工具或远程服务&#xff0c;以下是具体实现方法和步骤&#xff1a; 一、本地运行方案&#xff08;无需越狱&#xff09; 使用 Python 编程类 App 以下应用可在 App Store 下载&#xff0c;支持直接在 iPhone 上编写并运行 …

【赵渝强老师】达梦数据库的数据库对象

达梦数据库中包含各种数据库对象&#xff0c;主要分为两大类型&#xff1a;基本数据库对象和复杂数据库对象。下面分别进行介绍。 视频讲解如下 【赵渝强老师】达梦数据库的数据库对象 一、 基本数据库对象 常见的基本数据库对象有&#xff1a;表、索引、视图、序列、同义词等…

【每日算法】Day 6-1:哈希表从入门到实战——高频算法题(C++实现)

摘要 &#xff1a;掌握高频数据结构&#xff01;今日深入解析哈希表的核心原理与设计实现&#xff0c;结合冲突解决策略与大厂高频真题&#xff0c;彻底掌握O(1)时间复杂度的数据访问技术。 一、哈希表核心思想 哈希表&#xff08;Hash Table&#xff09; 是一种基于键值对的…

LeetCode 第29题、30题

LeetCode 第29题&#xff1a;两数相除 题目描述 给你两个整数&#xff0c;被除数dividend和除数divisor。将两数相除&#xff0c;要求不使用乘法、除法和取余运算。整数除法应该向零截断&#xff0c;也就是截去其小数部分。例如&#xff0c;8.345将被截断为8&#xff0c;-2.733…

26考研——树与二叉树_树、森林(5)

408答疑 文章目录 二、树、森林树的基本概念树的定义和特性树的定义树的特性 基本术语树的基本术语和概念祖先、子孙、双亲、孩子、兄弟和堂兄弟结点的层次、度、深度和高度树的度和高度分支结点和叶结点有序树和无序树路径和路径长度 森林的基本术语和概念森林的定义森林与树的…

【HarmonyOS Next之旅】DevEco Studio使用指南(六)

目录 1 -> 在模块中添加Ability 1.1 -> Stage模型添加UIAbility 1.1.1 -> 在模块中添加UIAbility 1.1.2 -> 在模块中添加Extension Ability 2 -> 创建服务卡片 2.1 -> 概述 2.2 -> 使用约束 2.3 -> 创建服务卡片 2.4 -> 创建动态/静态卡片…

Langchain 多模态输入和格式化输出

多模态输入 图片处理&#xff08;最高频&#xff09; 1.1 URL形式&#xff08;推荐大文件&#xff09; from langchain.schema import HumanMessage from langchain.chat_models import ChatOpenAIchat ChatOpenAI(model"gpt-4-vision-preview")message HumanMes…

Excel多级联动下拉菜单的自动化设置(使用Python中的openpyxl模块)

1 主要目的 在Excel中&#xff0c;经常会遇到需要制作多级联动下拉菜单的情况&#xff0c;要求单元格内填写的内容只能从指定的多个选项中进行选择&#xff0c;并且需要设置多级目录&#xff0c;其中下级目录的选项内容要根据上级目录的填写内容确定&#xff0c;如下图所示&am…