C++:list使用以及模拟实现
list使用以及模拟实现
- list介绍
- list常用接口
- 1.构造
- 2.迭代器
- 3.容量
- 4.访问数据
- 5.增删查改
- 6.迭代器失效
- list模拟实现
- 1.迭代器的实现
- 2.完整代码
list介绍
- list是一个类模板,加<类型>实例化才是具体的类。
- list是可以在任意位置进行插入和删除的序列式容器。
- list的底层是双向循环链表结构,链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- 与其他序列式容器相比,list最大的缺陷是不支持任意位置的随机访问,比如访问第六个节点,必须从已知节点迭代到该节点。
双向链表图解:
list常用接口
1.构造
函数 | 功能 |
---|---|
list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的节点 |
list() | 构造空的list |
list (const list& x) | 拷贝构造 |
list (InputIterator first, InputIterator last) | 迭代器区间初始化 (模板,可以传入其它容器的迭代器区间) |
2.迭代器
函数 | 功能 |
---|---|
begin()加end() | 获取第一个数据位置的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator |
rbegin()加rend() | 反向迭代器,获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator |
3.容量
函数 | 功能 |
---|---|
size() | 获取有效数据个数 |
empty() | 判断是否为空(size为0为空,返回true) |
4.访问数据
函数 | 功能 |
---|---|
front() | 取到头节点数据的引用 |
back() | 返回尾节点数据的引用 |
5.增删查改
函数 | 功能 |
---|---|
push_front (const value_type& val) | 头插数据val |
push_back (const value_type& val) | 尾删数据val |
pop_front() | 头删 |
pop_back() | 尾删 |
insert (iterator position, const value_type& val) | 在position位置中插入值为val的元素 |
erase (iterator position) | 删除position位置的元素 |
swap(list& x) | 交换两个list |
clear() | 清空有效数据 |
6.迭代器失效
迭代失效即迭代器所指向的节点的无效,即该节点被删除了。 因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
#include<iostream>
#include<list>
using namespace std;//错误代码演示
int main()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()){// erase()函数执行后,it所指向的节点已被删除//因此it无效,在下一次使用it时,必须先给其赋值it = l.erase(it); //只需要去掉++it,这里修改成it = erase(it)即可++it;}return 0;
}
list模拟实现
1.迭代器的实现
有别于vector,list的迭代器并不是一个原生的指针,因为使用者需要得到的是节点中的数据而不是整个节点,而且寻找下一个节点并不能通过指针简单的++,所以需要把迭代器单独封装成一个类,通过重载*等运算符来完成需求。
namespace MyList
{//节点设计成结构体,方便访问template<typename T>struct list_node{list_node(const T val = T()):_data(val), _next(nullptr), _prev(nullptr){}T _data;list_node<T>* _next;list_node<T>* _prev;};//迭代器//这里设计模板参数除了迭代器,还有Ref(引用)和Ptr(指针)//这样设计是为了同时生成普通迭代器和const对象的迭代器//普通对象(可读可写):iterator<T, T&, T*>//const对象(可读不可写):const_iterator<T, const T&, const T*>template<typename T, typename Ref, typename Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self; //要返回迭代器需要返回实例化对象,重命名一下Node* _node;__list_iterator(Node* p):_node(p){}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;}Ref operator*(){return _node->_data;}//返回指针可以让自定义类型自行打印,访问成员//->操作符,比较特殊,it->_num转换出来其实是it.operator->()->_numPtr operator->(){return &(_node->_data);}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}};//反向迭代器//反向迭代器需要进行封装,其实就是复用普通迭代器,然后++和--操作反过来//普通对象(可读可写):Reverse_iterator<iterator,T&,T*>//const对象(可读不可写):Reverse_iterator<const_iterator,const T&,const T*>template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator<Iterator, Ref, Ptr> self;Iterator _it;//构造Reverse_iterator(Iterator it):_it(it){}self& operator++(){_it--;return *this;}self operator++(int){self tmp(*this);_it--;return tmp;}self& operator--(){_it++;return *this;}self operator--(int){self tmp(*this);_it++;return tmp;}Ref operator*(){return *_it;}Ptr operator->(){return _it;}bool operator!=(const self& s){return _it != s._it;}bool operator==(const self& s){return _it == s._it;}};
}
2.完整代码
#pragma once
#include<iostream>
using namespace std;namespace MyList
{//节点设计成结构体,方便访问template<typename T>struct list_node{list_node(const T val = T()):_data(val), _next(nullptr), _prev(nullptr){}T _data;list_node<T>* _next;list_node<T>* _prev;};//迭代器//这里设计模板参数除了迭代器,还有Ref(引用)和Ptr(指针)//这样设计是为了同时生成普通迭代器和const对象的迭代器//普通对象(可读可写):iterator<T, T&, T*>//const对象(可读不可写):const_iterator<T, const T&, const T*>template<typename T, typename Ref, typename Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self; //要返回迭代器需要返回实例化对象,重命名一下Node* _node;__list_iterator(Node* p):_node(p){}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;}Ref operator*(){return _node->_data;}//返回指针可以让自定义类型自行打印,访问成员//->操作符,比较特殊,it->_num转换出来其实是it.operator->()->_numPtr operator->(){return &(_node->_data);}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}};//反向迭代器//反向迭代器需要进行封装,其实就是复用普通迭代器,然后++和--操作反过来//普通对象(可读可写):Reverse_iterator<iterator,T&,T*>//const对象(可读不可写):Reverse_iterator<const_iterator,const T&,const T*>template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator<Iterator, Ref, Ptr> self;Iterator _it;Reverse_iterator(Iterator it):_it(it){}self& operator++(){_it--;return *this;}self operator++(int){self tmp(*this);_it--;return tmp;}self& operator--(){_it++;return *this;}self operator--(int){self tmp(*this);_it++;return tmp;}Ref operator*(){return *_it;}Ptr operator->(){return _it;}bool operator!=(const self& s){return _it != s._it;}bool operator==(const self& s){return _it == s._it;}};template<typename 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;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;typedef Reverse_iterator< const_iterator, const T&, const T*> reverse_const_iterator;//迭代器部分iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;}reverse_iterator rbegin(){return (--end());//_head->_prev}reverse_iterator rend(){return (end());//_head}reverse_const_iterator rbegin()const{return (--end());//_head->_prev}reverse_const_iterator rend()const{return (end());//_head}/// ///// private://不希望外界调用,设计成私有void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}public://构造、析构部分list(){empty_init();}list(size_t n, const T& value = T()){empty_init();while (n--){push_back(value);}}//重载给内置类型使用,整形默认是int,不写这个会优先匹配list(Iterator first, Iterator last)list(int n, const T& value = T()){empty_init();while (n--){push_back(value);}}//迭代器区间初始化template <class Iterator>list(Iterator first, Iterator last){empty_init();while(first != last){push_back(*first);first++;}}list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}~list(){clear();delete _head;_head = nullptr;}//其它void swap(list<T> lt){std::swap(_size, lt._size);std::swap(_head, lt._head);}//使用传之传参,直接拷贝一份交换操作的底层空间就好list<T>& operator=(list<T> lt){swap(lt);return *this;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}/// ////访问头,尾数据T& front(){return _head->_next->_data;}const T& front()const{return _head->_next->_data;}T& back(){return _head->_prev->_data;}const T& back()const{return _head->_prev->_data;}/// ///// //增加删除部分void push_back(const T& val){insert(end(), val);}void push_front(const T& val){insert(begin(), val);}iterator insert(iterator pos, const T& val){Node* newnode = new Node(val);Node* cur = pos._node;Node* prev = cur->_prev;cur->_prev = newnode;newnode->_next = cur;newnode->_prev = prev;prev->_next = newnode;++_size;return newnode;}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator erase(iterator pos){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(){return _size;}private:Node* _head; //这里存储卫兵节点,因为底层是双向循环链表,可以找到头和尾size_t _size; //只需要在insert和erase里面加减就可以};}
相关文章:

C++:list使用以及模拟实现
list使用以及模拟实现 list介绍list常用接口1.构造2.迭代器3.容量4.访问数据5.增删查改6.迭代器失效 list模拟实现1.迭代器的实现2.完整代码 list介绍 list是一个类模板,加<类型>实例化才是具体的类。list是可以在任意位置进行插入和删除的序列式容器。list的…...

深度学习基础知识-pytorch数据基本操作
1.深度学习基础知识 1.1 数据操作 1.1.1 数据结构 机器学习和神经网络的主要数据结构,例如 0维:叫标量,代表一个类别,如1.0 1维:代表一个特征向量。如 [1.0,2,7,3.4] 2维:就是矩…...
Springboot使用QueryDsl实现融合数据查询
SpringbootQueryDsl技术 1、添加依赖 <!--基于JPA--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!--QueryDSL支持--> <dependenc…...

解决方案 | 电子签打通消费电子行业数智化经营通路
技术迭代不断驱动产业快速增长,从PC电脑到手机平板、再到可穿戴设备的兴起,每一次设备的迭代都代表着技术为产品注入了新的发展动能。与此同时,消费电子设备迭代更新周期的不断缩短,市场增长疲缓等因素,也对行业的流转…...

JVM理论知识
一、JVM内存结构 java的内存模型主要分为5个部分,分别是:JVM堆、JVM栈、本地栈、方法区还有程序计数器,他们的用途分别是: JVM堆:新建的对象都会放在这里,他是JVM中所占内存最大的区域。他又分为新生区还…...
idea - 报错 Mybatis提示Tag name expected的问题< 小于号 无法识别
问题:Mybatis提示Tag name expected 原因: 当我们在mapper中编写sql语句的时候会发现使用"<“符号会提示一个Tag name expected。这是因为xml文件中不识别”<"符号和“&”符号。防止与xml本身的元素命名混淆,导致无法解…...

合宙Air724UG LuatOS-Air LVGL API--对象
对象 概念 在 LVGL 中,用户界面的基本构建块是对象。例如,按钮,标签,图像,列表,图表或文本区域。 属性 基本属性 所有对象类型都共享一些基本属性: Position (位置) Size (尺寸) Parent (父母…...

Java将PDF文件转为Word文档
Java将PDF文件转为Word文档 一、创建Springboot Maven项目 二、导入依赖信息 <repositories><repository><id>com.e-iceblue</id><url>https://repo.e-iceblue.cn/repository/maven-public/</url></repository></repositories&g…...

vite创建项目命令
1.第一步运行创建命令(npm) npm create vitelatest也可以使用yarn yarn create vite还可以 pnpm create vite注意的地方:首次创建的时候会出现这个 Need to install the following packages:create-vitelatest Ok to proceed? (y) 直接y就…...

解决Pandas KeyError: “None of [Index([...])] are in the [columns]“问题
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...

前端加springboot实现Web Socket连接通讯以及测试流程(包括后端实现心跳检测)
【2023】前端加springboot实现Web Socket连接通讯(包括后端实现心跳检测) 一级目录二级目录三级目录 前言一、Web Socket 简绍1 为什么用 websocket? 二、代码实现1、前端(html)1.1、无前端向后端发送消息1.2、有前端向…...

node使用高版本的oracledb导致连接oracle的Error: NJS-138异常
异常信息如下 Error: NJS-138: connections to this database server version are not supported by node-oracledb in Thin mode 我的oracle版本是11g,之前的使用正常,今天却报错了,显示不支持thin模式,后面回退版本就可以了。...
RabbitMQ手动签收消息
RabbitMQ手动签收消息 这里讲解SpringBoot使用RabbitMQ进行有回调的用法和消费者端手动签收消息的用法。 1、pom依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"h…...
Unity 3d角色展示脚本(旋转 平移 缩放)展示界面
不考虑性能 很简陋的一个功能,主要是用于角色渲染的观察用,比simplecontroller要好用一点 using System; using UnityEngine;public class CharacterViewer : MonoBehaviour {public Transform target; // 人物模型的Transformpublic float rotationSpee…...
Spring Boot 将 Word 转换为 PDF
首先,确保项目中添加了对Apache POI和Apache PDFBox的依赖。可以在你的 pom.xml 文件中添加以下依赖: <dependencies><!-- Apache POI --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</arti…...

【PHP面试题82】system和exec是用来做什么的?有什么区别
文章目录 🚀一、前言,PHP中system和exec命令的作用🚀二、system()函数🚀三、exec()函数🚀四、区别和应用场景🔎4.1 使用system()函数的应用场景🔎4.2 使用exec()函数的应用场景🔎4.3…...

05-微信小程序常用组件-表单组件
05-微信小程序常用组件-表单组件 文章目录 表单组件button 按钮案例代码 form 表单案例代码 image 图片支持长按识别的码案例代码 微信小程序包含了六大组件: 视图容器、 基础内容、 导航、 表单、 互动和 导航。这些组件可以通过WXML和WXSS进行布局和样式设…...

Lucky player —— Java 项目(Spring Boot)
一、项目介绍 项目名称:lucky player 项目的主要功能:本系统主要功能为构建了一个用户分享音乐的平台,普通用户不进行登录即可收听其他用户已经发布的专辑中的音乐。 作为博主则可以在该平台上传音频,以及在线音频录制上传。音频上…...
ios 声网agora 音视频直播场景下的集成总结
文章目录 一、前言二、视频会议场景2.1 场景描述2.2 功能列表三、电商直播场景3.1 场景描述3.2 功能列表3.3 技术方案四、声网iOS SDK集成4.1 集成4.2 示例demo4.3 核心代码4.3.1 初始化4.3.2 加入频道4.3.3 切换身份4.4.4 连麦4.4 相关问题4.4.1 监听观众角色用户事件五、相关…...

mysql 、sql server 临时表、表变量、
sql server 临时表 、表变量 mysql 临时表 创建临时表 create temporary table 表名 select 字段 [,字段2…,字段n] from 表...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...

【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...