【C++】“list”的介绍和常用接口的模拟实现
【C++】“list”的介绍和常用接口的模拟实现
- 一. list的介绍
- 1. list常见的重要接口
- 2. list的迭代器失效
- 二. list常用接口的模拟实现(含注释)
- 三. list与vector的对比
一. list的介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向带头链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息。

1. list常见的重要接口


- begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
- rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

2. list的迭代器失效
迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响
二. list常用接口的模拟实现(含注释)
#include<assert.h>
#include<iostream>
using std::cout;
using std::endl;
namespace wch
{//由于list中的val支持多种类型,定义模板参数Ttemplate<class T>struct list_node{list_node<T>* _next;list_node<T>* _prev;T _val;//T(),针对自定义类型会去调用它的构造函数,针对内置类型无影响list_node(const T& val = T()):_next(nullptr), _prev(nullptr), _val(val){}};// typedef __list_iterator<T, T&, T*> iterator;// typedef __list_iterator<T, const T&, const T*> const_iterator;//此处定义多个模板参数针对返回值类型template<class T, class Ref, class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;Node* _node;__list_iterator(Node* node):_node(node){}Ref operator*() const//重载普通对象解引用{return _node->_val;}Ptr operator->() const//重载指针对象解引用{return &_node->_val;}self& operator++()//返回对象在函数体执行结束后依旧存在,建议引用返回,减少拷贝开销{_node = _node->_next;return *this;}//返回对象(局部变量或指向局部变量的指针)在函数体执行结束后不存在,不可引用返回,值返回self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}//尽量使用引用形参, 避免拷贝开销。同时在不需要修改实参时,通过指定const 引用形参来限制。bool operator!=(const self& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};template<class T>class list{typedef list_node<T> Node;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;// 这样设计const迭代器是不行的,因为const迭代器期望指向内容不能修改// 这样设计是迭代器本身不能修改// T* const ptr2;iterator begin() {//return _head->_next;//单参构造函数支持隐式类型转换return iterator(_head->_next);}iterator end() {return _head;//单参构造函数支持隐式类型转换//return iterator(_head);}const_iterator begin() const{//return _head->_next;return const_iterator(_head->_next);}const_iterator end() const{return _head;//return const_iterator(_head);}void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list()//无参默认构造函数{empty_init();}// lt2(lt1)list(const list<T>& lt)//拷贝构造//list(const list& lt)//不加类型也可以,不建议{empty_init();for (auto& e : lt)//深拷贝{push_back(e);}}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt)//赋值运算符重载//list& operator=(list lt)//不加类型也可以,不建议{swap(lt);return *this;}~list()//析构函数{clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);//带位置返回值的erase函数,防止迭代器失效}_size = 0;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}// pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;++_size;return newnode;}//删除pos处节点iterator erase(iterator pos){assert(pos != end());//不可删除头节点Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}size_t size(){/*size_t sz = 0;iterator it = begin();while (it != end()){++sz;++it;}return sz;*/return _size;}private:Node* _head;size_t _size;};void Print(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){//(*it) += 1;cout << *it << " ";++it;}cout << endl;}void test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator it = lt.begin();//由于链表的各个节点地址是不连续的,前一个节点的地址可能比后一个地址大,所以不可已写为 it < it.end();while (it != lt.end()){(*it) += 1;cout << *it << " ";++it;}cout << endl;for (auto e : lt){cout << e << " ";}cout << endl;Print(lt);}struct A{A(int a1 = 0, int a2 = 0):_a1(a1), _a2(a2){}int _a1;int _a2;};void test_list2(){list<A> lt;lt.push_back(A(1, 1));lt.push_back(A(2, 2));lt.push_back(A(3, 3));lt.push_back(A(4, 4));list<A>::iterator it = lt.begin();while (it != lt.end()){//cout << (*it)._a1 << " " << (*it)._a2 << endl;//it->->_a1, it->->_a2,特殊处理为一个->cout << it->_a1 << " " << it->_a2 << endl;++it;}cout << endl;}void test_list3(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_front(5);lt.push_front(6);lt.push_front(7);lt.push_front(8);for (auto e : lt){cout << e << " ";}cout << endl;lt.pop_front();lt.pop_back();for (auto e : lt){cout << e << " ";}cout << endl;lt.clear();lt.push_back(10);lt.push_back(20);lt.push_back(30);lt.push_back(40);for (auto e : lt){cout << e << " ";}cout << endl;cout << lt.size() << endl;}void test_list4(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);for (auto e : lt){cout << e << " ";}cout << endl;list<int> lt1(lt);for (auto e : lt1){cout << e << " ";}cout << endl;list<int> lt2;lt2.push_back(5);lt2.push_back(6);lt2.push_back(7);lt2.push_back(8);for (auto e : lt2){cout << e << " ";}cout << endl;lt1 = lt2;for (auto e : lt1){cout << e << " ";}cout << endl;}
}
三. list与vector的对比
vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:

相关文章:
【C++】“list”的介绍和常用接口的模拟实现
【C】“list”的介绍和常用接口的模拟实现 一. list的介绍1. list常见的重要接口2. list的迭代器失效 二. list常用接口的模拟实现(含注释)三. list与vector的对比 一. list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器…...
第九篇——数列和级数(二):传销骗局的数学原理
目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么? 四、总结五、升华 一、背景介绍 文章不长,但是道理深刻;相邻两个数的差值…...
docker如何查看容器的ip
要查看Docker容器的IP地址,可以使用以下几种方法: 使用docker inspect命令: docker inspect -f {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} <容器ID或名称> 使用docker ps和docker inspect组合: 首先查看正…...
Mysql ONLY_FULL_GROUP_BY模式详解、group by非查询字段报错
文章目录 一、问题报错二、ONLY_FULL_GROUP_BY模式2.1、什么是ONLY_FULL_GROUP_BY?2.2、为什么要使用ONLY_FULL_GROUP_BY?2.3、查看sql_mode 三、解决方法3.1、关闭only_full_group_by模式3.1.1、方法一:关闭当前会话中的only_full_group_by3…...
设计模式(2)工厂模式
让一个工厂类去生产出对象 (new )来。 我们想要一个 形状,我们用工厂去生产出,圆形,方形。 package com.example.factory2;public interface Shape {void draw(); }public class Square implements Shape {Overridep…...
二分查找算法专题(1)
找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏: 优选算法专题 目录 二分查找算法的介绍 704. 二分查找 34. 在排序数组中查找元素的第一个和 最后一个位置 35. 搜索插入位置 69. x的平…...
ACP科普:SoS不是救命
Scrum of Scrums(SoS)是一种用于协调多个Scrum团队之间工作的扩展框架,特别适用于大型项目或组织中有多个团队同时进行开发的情况。它帮助团队在保持敏捷性的同时,解决跨团队的依赖和协调问题。以下是对Scrum of Scrums的详细介绍…...
C++:模拟实现vector
目录 成员变量与迭代器 size capacity empty 迭代器有关函数 实现默认成员函数的前置准备 reserve 编辑 编辑 push_back 构造函数 无参构造 迭代器区间构造 n个val来进行构造 析构函数 拷贝构造函数 赋值重载 增删查改 clear resize pop_back inser…...
Leecode SQL 184. Department Highest Salary 找出tie
Department Highest Salary 注意!要找出 tie 的 highest salary! Write a solution to find employees who have the highest salary in each of the departments. Return the result table in any order. The result format is in the following ex…...
[Redis][典型运用][缓存]详细讲解
目录 0.什么是缓存?1.使用Redis作为缓存1.为什么用?2.如何用? 2.缓存的更新策略0.前言1.定期生成2.实时生成 3.缓存相关问题1.缓存预热(Cache Preheating)2.缓存穿透(Cache Penetration)3.缓存雪崩(Cache Avalanche)4.缓存击穿(Cache Breakdo…...
GPG error golang 1.19
1. 问题描述及原因分析 在飞腾2000的服务器,OS为Kylin Linux Advanced Server release V10环境下,docker版本为18.09.0(docker-engine-18.09.0-101.ky10.aarch64),基于容器镜像golang:1.19编译新的容器镜像࿰…...
Linux如何查看每个文件及文件夹的大小
查看当前目录下每个文件夹的大小,包括其内部所有文件: du -sh *-s:仅显示每个文件夹的总大小,而不是每个文件。-h:以人类可读的格式显示。...
Word样式的同步与重置
有时候我们需要修改Word中的样式,实现排版的个性化。 如何同步样式到其他电脑上? Word中的样式是由Normal.dotm文件控制的,对样式所有的设置和修改,都会保存到这个问题件中,所以我们只需要在设置好样式以后ÿ…...
力扣 —— 跳跃游戏
题目一(中等) 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例 1&…...
SOCKS5代理和HTTP代理哪个快?深度解析两者的速度差异
在现代互联网环境中,使用代理IP已经成为了许多人日常生活和工作的必备工具。无论是为了保护隐私,还是为了访问某些特定资源,代理IP都扮演着重要的角色。今天,我们就来聊聊SOCKS5代理和HTTP代理,看看这两者到底哪个更快…...
工具介绍---效率高+实用
Visual Studio Code (VS Code) 功能特点: 智能代码提示:内置的智能代码提示功能可以自动完成函数、变量等的输入,提高代码编写速度。插件丰富:支持成千上万的扩展插件,例如代码片段、主题、Linting等,能够…...
本地部署开源在线PPT制作与演示应用PPTist并实现异地远程使用
文章目录 前言1. 本地安装PPTist2. PPTist 使用介绍3. 安装Cpolar内网穿透4. 配置公网地址5. 配置固定公网地址 前言 本文主要介绍如何在Windows系统环境本地部署开源在线演示文稿应用PPTist,并结合cpolar内网穿透工具实现随时随地远程访问与使用该项目。 PPTist …...
leetcode_238:除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂…...
网络协议详解--IPv6
IPv6产生背景 (1)地址空间的耗尽:因特网呈指数级发展,导致IPv4地址空间几乎耗尽。虽然采用了子网划分、CIDR和NAT地址转换技术,但这没有从根源解决地址耗尽的问题 (2)IP层安全需求的增长&#x…...
阿里云域名注册购买和备案
文章目录 1、阿里云首页搜索 域名注册2、点击 控制台3、域名控制台 1、阿里云首页搜索 域名注册 2、点击 控制台 3、域名控制台...
利用快马平台快速生成javascript交互原型:以动态待办列表为例
利用快马平台快速生成JavaScript交互原型:以动态待办列表为例 最近在尝试快速验证一个待办事项应用的交互设计,发现用传统方式从零开始写代码太耗时了。正好试用了InsCode(快马)平台,只需要描述功能需求,就能自动生成可运行的Jav…...
AI背景分离革新性全攻略:ComfyUI-BiRefNet创意工作流零基础上手指南
AI背景分离革新性全攻略:ComfyUI-BiRefNet创意工作流零基础上手指南 【免费下载链接】ComfyUI-BiRefNet-ZHO Better version for BiRefNet in ComfyUI | Both img & video 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-BiRefNet-ZHO 在数字创意…...
3步掌握DoL-Lyra整合包:从零到精通的完整指南
3步掌握DoL-Lyra整合包:从零到精通的完整指南 【免费下载链接】DOL-CHS-MODS Degrees of Lewdity 整合 项目地址: https://gitcode.com/gh_mirrors/do/DOL-CHS-MODS Degrees of Lewdity中文整合包DoL-Lyra为您提供了一站式的游戏体验解决方案。这个自动化构建…...
会Python可以找什么工作?
Python凭借简洁易用、功能强大的特点,成为当下就业面极广的编程语言。不少人学会后却不清楚可以找什么工作,其实从开发、数据分析到自动化运维都有大量机会,接下来为大家详细讲解一下。会Python后,可以找的工作有很多,…...
为什么你的asyncio服务内存永不释放?深入CPython asyncio循环引用链,给出4行补丁级解决方案!
第一章:Shell脚本的基本语法和命令Shell脚本是Linux/Unix系统自动化任务的核心工具,以可执行文本文件形式存在,由Bash等Shell解释器逐行解析执行。其语法简洁但严谨,强调空格、换行与引号的正确使用。脚本结构与执行方式 每个Shel…...
Ollama镜像免配置原理:daily_stock_analysis启动脚本中systemd服务注册与健康检查逻辑
Ollama镜像免配置原理:daily_stock_analysis启动脚本中systemd服务注册与健康检查逻辑 1. 项目背景与核心价值 在当今AI技术快速发展的时代,本地化部署大模型成为了许多企业和开发者的迫切需求。daily_stock_analysis镜像正是基于这一需求,…...
ChatGPT归档数据恢复机制深度解析:原理与实战指南
ChatGPT归档数据恢复机制深度解析:原理与实战指南 在AI应用开发中,数据管理是一个绕不开的话题。随着项目迭代和用户量增长,对话记录、训练数据、配置信息等会迅速累积。为了平衡存储成本与数据可用性,归档(Archive&a…...
【Python实战解析】从数据爬取到房价预测:一个完整的数据科学项目实战
1. 从零开始:房产数据爬取实战 第一次做房产数据爬取时,我盯着满屏的HTML标签差点崩溃。但后来发现,只要掌握几个关键技巧,爬取房产网站数据其实比想象中简单得多。我们这次要爬取的是长沙二手房数据,包含户型、面积、…...
影墨·今颜开源可部署方案:私有化AI影像系统建设白皮书
影墨今颜开源可部署方案:私有化AI影像系统建设白皮书 1. 引言:重新定义AI影像生成标准 在数字影像创作领域,我们经常面临一个困境:AI生成的图片往往带有明显的"塑料感",缺乏真实照片的温度和质感。影墨今颜…...
OpenClaw安全加固实践:Qwen3-32B私有镜像+本地防火墙配置
OpenClaw安全加固实践:Qwen3-32B私有镜像本地防火墙配置 1. 为什么需要安全加固? 当我第一次看到OpenClaw能够自动操作我的电脑时,既兴奋又担忧。兴奋的是它能够帮我完成重复性工作,担忧的是它本质上是一个拥有系统操作权限的AI…...
