【C++】list介绍以及模拟实现(超级详细)
欢迎来到我的Blog,点击关注哦💕
list的介绍和模拟实现
- 前言
- `list`介绍
- 标准库容器` std::list` 与 `std::vector` 的优缺点
- 缺点
- `list`的基本操作
- 构造函数
- `list iterator`
- `list capcacity`
- `list modify`
- `list`模拟实现
- 存贮结构(双向带头循环)
- `iterator`
- `iterator`结构
- `operator!=` `operator ==`
- `operator++`
- `operator--`
- `list`数据结构
- 构造函数
- list的初始化
- 节点初始化
- 迭代器
- `list modify`
- insert
- erase
- 头插、头删、尾插、尾删
- `list operator`
- 交换
- clear
- 源码
前言
string
vector
的是存储是基于物理空间上连续的,而list
是作为线性的链式结构,是值得学习的。
list
介绍
std::list
是C++标准模板库(STL
)中的一个容器适配器,它内部实现为双向链表结构。- 这种设计使得
std::list
能够在常数时间内进行任意位置的插入和删除操作,这是其相对于其他序列容器如std::vector
的显著优点。 std::list
不支持随机访问,即无法直接通过索引来访问容器中的元素,这通常需要从头部或尾部开始迭代到目标位置.
标准库容器 std::list
与 std::vector
的优缺点
- std::list: 作为一个双向链表,std::list 在插入和删除操作上具有优势,因为这些操作只涉及到改变相邻节点的指针,而不需要移动其他元素。此外,std::list 不需要预分配额外的内存,可以更好地处理动态内存分配,减少内存碎片.
- std::vector: 作为一个动态数组,std::vector 提供了高效的随机访问能力,可以通过下标直接访问任意位置的元素,其访问效率为 O(1). 此外,std::vector 通常具有较高的空间利用率和缓存友好性,因为其元素在内存中是连续存储的.
缺点
- std::list: 由于非连续的内存存储,std::list 在访问元素时效率较低,因为可能需要从头开始遍历链表。此外,每个节点都需要存储额外的指针信息,这增加了内存开销.
- std::vector: 在 std::vector 的中间位置插入或删除元素可能会引起大量元素的移动,以维持内存的连续性,这会导致较差的性能。当 std::vector 的容量不足以容纳新增元素时,还需要进行动态扩容,这是一个成本较高的操作
vector | list | |
---|---|---|
底层 结构 | 动态顺序表,一段连续空间 | 带头结点的双向循环链表 |
随 机 访 问 | 支持随机访问,访问某个元素效率O(1) | 不支持随机访问,访问某个元素 效率O(N) |
插 入 删 除 | 任意位置插入和删除效率低,需要搬移元素, 时间复杂度为O(N),插入时有可能需要增容, 增容:开辟新空 间,拷贝元素,释放旧空间,导致效率更低 | 任意位置插入和删除效率高,不 需要搬移元 素,时间复杂度为 O(1) |
插 入 删 除 | 底层为连续空间,不容易造成内存碎片,空间利用率 高,缓存利用率高 | 底层节点动态开辟,小节点容易 造成内存碎片,空间利用率低, 缓存利用率低 |
迭 代 器 | 原生态指针 | 对原生态指针(节点指针)进行封装 |
迭 代 器 失 效 | 在插入元素时,要给所有的迭代器重新赋值,因为插入 元素有可能会导致重新扩容,致使原来迭代器失效,删 除时,当前迭代器需要重新赋值否则会失效 | 插入元素不会导致迭代器失效, 删除元素时,只会导致当前迭代 器失效,其他迭代器不受影响 |
使 用 场 景 | 需要高效存储,支持随机访问,不关心插入删除效率 | 大量插入和删除操作,不关心随 机访问 |
list
的基本操作
构造函数
【C++】vector介绍以及模拟实现 | 接口说明 |
---|---|
list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的元素 |
list() | 构造空的list |
list (const list& x) | 拷贝构造函数 |
list (InputIterator first, InputIterator last) | 用[first, last)区间中的元素构造list |
list iterator
此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
函数声明 | 接口说明 |
---|---|
begin + end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
rbegin + rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置 |
list capcacity
函数声明 | 接口说明 |
---|---|
empty | 检测list是否为空,是返回true,否则返回false |
size | 返回list中有效节点的个数 |
list modify
函数声明 | 接口说明 |
---|---|
push_front | 在list首元素前插入值为val的元素 |
pop_front | 删除list中第一个元素 |
push_back | 在list尾部插入值为val的元素 |
pop_back | 删除list中最后一个元素 |
insert | 在list position 位置中插入值为val的元素 |
erase | 删除list position位置的元素 |
swap | 交换两个list中的元素 |
clear | 清空list中的有效元素 |
list
模拟实现
存贮结构(双向带头循环)
- 定义一个类(C语言:结构体)存储数据,作为指向下一个上一个的节点
namespace MyList
{//LIst节点template<class T>struct _list_node{_list_node<T>* _next;_list_node<T>* _prev;T _val;_list_node(const T& val = T()): _next(nullptr), _prev(nullptr), _val(val){}};
}
iterator
迭代器有两种实现方式,具体应根据容器底层数据结构实现:
- 原生态指针,比如:
vector
string
- 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
1. 指针可以解引用,迭代器的类中必须重载operator*()
2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载 oprator->()
3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
iterator
结构
- 三个模板参数
- 第一个模板参数控制类型
- 第二个模板参数控制返回值类型
const
非const
- 第三个模板参数控制返回的
list
类的类型const
非const
Node* _node;
需要定义一个指针,指向list
节点
template<class T,class Ref,class ptr>struct _list_iterator{typedef _list_node<T> Node;typedef _list_iterator<T, Ref,ptr> self;Node* _node;};
operator!=
operator ==
//重载operator!=
bool operator!=(const self& it)const
{return _node != it._node;
}
//重载operator==
bool operator==(const self& it)const
{return _node == it._node;
}
operator++
//重载operator++(前置)
self& operator++()
{_node = _node->_next;return *this;
}
//重载operator++(后置)
self& operator++(int)
{self tmp(*this);_node = _node->_next;return tmp;
}
operator--
//重载operator--(前置)
self& operator--()
{_node = _node->_prev;return *this;
}
//重载operator--(后置)
self& operator--(int)
{self tmp(*this);_node = _node->_prev;return tmp;
}
operator*
operator->
//重载operator*
Ref& operator* ()
{return _node->_val;
}
//重载operator->
ptr operator->()
{return _node->_val;
}
list
数据结构
构造函数
list的初始化
- 双向带带头循环
//空list初始化
void empty_init()
{_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;
}
节点初始化
- 默认构造函数
- 默认构造函数
- 用迭代器初始化
- 拷贝构造函数
- 赋值运算符重载
- 赋值运算符重载
//默认构造函数
list()
{empty_init();
}
//默认构造函数
list(int n, const T& val = T())
{empty_init();while (n--){push_back(val);}}
//用迭代器初始化
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<T> operator=(list<T> lt)
{swap(lt);return *this;
}
//赋值运算符重载
~list()
{clear();delete _head;
}
迭代器
iterator begin()
{return _head->_next;
}
iterator end()
{return _head;
}
const_iterator begin()const
{return _head->_next;
}
const_iterator end()const
{return _head;
}
list modify
insert
- 在pos位置插入节点,同数据结构是一样的,在这里面不过多赘述(可以参考)
//insert
iterator insert(iterator pos, const T& x)
{Node* newcode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newcode;newcode->_prev = prev;newcode->_next = cur;cur->_prev = newcode;++_size;return pos;
}
erase
- 删除迫使位置的节点,同样(可以参考)
//erase
iterator erase(iterator pos)
{assert(pos._node != _head);Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;
}
头插、头删、尾插、尾删
- 可以复用
insert
ersae
STL标准模板库也是进行复用
// 头插
void push_front(const T& x)
{insert(begin(), x);
}
//头删
void pop_front()
{erase(begin());
}
//尾插
void push_back(const T& x)
{insert(begin());
}
//尾删
void pop_back()
{erase(--end());
}
list operator
交换
void swap(list<T> lt)
{std::swap(_head, lt._head);std::swap(_size, lt._size);}
clear
- 析构函数也是利用了clear
//删除
void clear()
{iterator it = begin();while (it != end()){it = erase(it);++it;}}
源码
#pragma once
#include <iostream>
#include <assert.h>namespace MyList
{//节点template<class T>struct _list_node{_list_node<T>* _next;_list_node<T>* _prev;T _val;_list_node(const T& val = T()): _next(nullptr), _prev(nullptr), _val(val){}};//迭代器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){}//重载operator*Ref& operator* (){return _node->_val;}//重载operator->ptr operator->(){return _node->_val;}//重载operator++(前置)self& operator++(){_node = _node->_next;return *this;}//重载operator++(后置)self& operator++(int){self tmp(*this);_node = _node->_next;return tmp;}//重载operator--(前置)self& operator--(){_node = _node->_prev;return *this;}//重载operator--(后置)self& operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}//重载operator!=bool operator!=(const self& it)const {return _node != it._node;}//重载operator==bool operator==(const self& it)const{return _node == it._node;}};//listtemplate<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;//空list初始化void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}//用n个val初始化list(int n, const T& val = T()){empty_init();while (n--){push_back(val);}}//用迭代器初始化template <class Iterator>list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);++first;}}//默认构造函数list(){empty_init();}//拷贝构造函数list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}//赋值运算符重载list<T> operator=(list<T> lt){swap(lt);return *this;}//析构函数~list(){clear();delete _head;}//删除void clear(){iterator it = begin();while (it != end()){it = erase(it);++it;}}//迭代器iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;}//void push_back(const T& x)//{// Node* newcode = new Node(x);// Node* tail = _head->_prev;// tail->_next = newcode;// newcode->_next = _head;// newcode->_prev = tail;// _head->_prev = newcode;// ++_size;//}// 头插void push_front(const T& x){insert(begin(), x);}//头删void pop_front(){erase(begin());}//尾插void push_back(const T& x){insert(begin());}//尾删void pop_back(){erase(--end());}//insertiterator insert(iterator pos, const T& x){assert(pos._node != _head);Node* newcode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newcode;newcode->_prev = prev;newcode->_next = cur;cur->_prev = newcode;++_size;return pos;}//eraseiterator erase(iterator pos){assert(pos._node != _head);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()const{return _size;}//交换void swap(list<T> lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}private:Node* _head;size_t _size;};}
相关文章:

【C++】list介绍以及模拟实现(超级详细)
欢迎来到我的Blog,点击关注哦💕 list的介绍和模拟实现 前言list介绍标准库容器 std::list 与 std::vector 的优缺点缺点 list的基本操作构造函数list iteratorlist capcacitylist modify list模拟实现存贮结构(双向带头循环)itera…...

从艺术创作到作物生长,农业AI迎来“GPT“时刻
(于景鑫 国家农业信息化工程技术研究中心)"GPT"一词早已不再神秘,其在文本、图像生成领域掀起的风暴正以摧枯拉朽之势席卷全球。人们惊叹于ChatGPT对话之智能、思维之敏捷,更对Stable Diffusion、Midjourney创作的艺术画作赞叹不已。而大语言模…...

前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线
本章响应小伙伴的反馈,除了算法自动画连接线(仍需优化完善),实现了可以手动绘制直线、折线连接线功能。 请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 Bug,欢迎来提 Issue 哟~ github源码 gitee…...

C#:通用方法总结—第15集
大家好,今天继续分享我们的通用方法系列。 下面是今天的通用方法: (1)这个通用方法为用文件流写数据 /// <summary> /// 用文件流写数据 /// </summary> /// <param name"data"></param> //…...

LoadRunner12 添加事务并添加检查点
1、先要添加事务开始函数lr_start_transaction("登陆事务");,在接口上方右击点击-插入-开始事务。输入事务名称; 2、在某个接口想法 右击点击-插入-结束事务,输入事务名称,与开始事务名称要保持一致,lr_end_…...

python中的文件
绝对路径和相对路径 一般情况下绝对路径就是从根目录开始描述的路径 相对路径就是相对于当前目录 . 没错,就是一个点,表示的是当前文件夹;.. 两个点表示的是上一层文件夹 os模块与os.path os 和 os.path 是两个非常重要的标准库模块,它们分别用于操作系统相关的功能操…...

Powerdesigner连接mysql数据库,逆向工程生成ER图 (保姆级教程:下载->连接->配置)看这一篇就够了
一、下载powerdesigner 下载的教程请看如下链接,我太懒了,直接借鉴! 把别大佬的博客搬过来了嘿嘿~我真聪明!ㄟ( ▔, ▔ )ㄏ 操作到完成汉化就好!!第5步不看了,别按那个走,因为新手…...

商家转账到零钱分销返佣申请方案及驳回处理办法
分销返佣场景是商家申请最多的场景,因而申请被驳回也是最多的,根据我们上万次成功开通商家转账到零钱的经验,当商家转账到零钱的分销返佣场景被驳回时,按照以下步骤,商家都可以快速过审: 一、分析驳回原因 …...

荟萃科技:国外问卷调查有没有实时更新的题库?
有的,口子查和渠道查都是。 口子查的题目都是国外的公司发放在网络上,都是实时发布,所以我们需要去国外的各大社交平台做题。 这些题目不是集中的,而是散布在网站里面,需要我们去找,都是老外上班实时发放…...

【课程总结】Day18:Seq2Seq的深入了解
前言 在上一章【课程总结】Day17(下):初始Seq2Seq模型中,我们初步了解了Seq2Seq模型的基本情况及代码运行效果,本章内容将深入了解Seq2Seq模型的代码,梳理代码的框架图、各部分组成部分以及运行流程。 框…...

C++利用开发人员命令提示工具查看对象模型
1.跳转文件路径 cd 具体路径 2.输入c1 /d1 reportSingleClassLayout类名 文件名 操作示例如下图:...

白骑士的PyCharm教学高级篇 3.4 服务器部署与配置
系列目录 上一篇:白骑士的PyCharm教学高级篇 3.3 Web开发支持 在开发完成后,将代码部署到服务器上是一个关键步骤。PyCharm不仅提供了强大的本地开发支持,还为远程服务器配置与部署、自动化部署流程提供了便捷的工具和功能。本文将详细介绍如…...

数据库管理-第226期 内存至超线程(20240805)
数据库管理226期 2024-08-05 数据库管理-第226期 内存至超线程(20240805)1 CPU内缓存结构2 缓存与内存3 单核单线程4 超线程5 超线程的利弊总结 数据库管理-第226期 内存至超线程(20240805) 作者:胖头鱼的鱼缸…...

Django学习-数据迁移与数据导入导出
文章目录 一、数据迁移二、数据导入导出1. 数据导出2. 数据导入 一、数据迁移 数据迁移是将项目里定义的模型生成相应的数据表。主要的迁移指令如下: # 第一次生成自定义模型与django admin自带模型迁移文件,后续只生成新增模型迁移文件。后面加App名…...

【Nuxt】编程式导航和动态路由
编程式导航 navigateTo: 更多用法:navigateTo <template><div class"app-container"><button click"goToCategory">Category</button><NuxtPage/></div> </template> <script setup&…...

14. 计算机网络HTTPS协议(二)
1. 前言 上一章节中我们主要就 HTTPS 协议的前置知识进行介绍,下面会继续介绍 HTTPS 的通信过程以及抛出一些常见问题的探讨。因为候选人准备面试的时间和精力是比较有限的,我们在学习的过程要抓住重点,如果感觉对于细节缺乏了解,可以通过维基百科和查阅 StackOverflow 等…...

【算法设计题】实现以字符串形式输入的简单表达式求值,第2题(C/C++)
目录 第2题 实现以字符串形式输入的简单表达式求值 得分点(必背) 题解 1. 初始化和变量定义 2. 获取第一个数字并存入队列 3. 遍历表达式字符串,处理运算符和数字 4. 初始化 count 并处理加减法运算 代码详解 🌈 嗨…...

Kylin系列-入门
Kylin系列-入门 Apache Kylin是一个开源的分布式分析引擎,提供Hadoop/Spark之上的SQL查询接口及多维分析(OLAP)能力,以支持超大规模数据。以下是对Kylin系列的入门介绍: 一、基本概念 1. 定义 Apache Kylin是由eBa…...

力扣-46.全排列
刷力扣热题–第二十六天:46.全排列 新手第二十六天 奋战敲代码,持之以恒,见证成长 1.题目简介 2.题目解答 这道题目想了会,思路比较好想,但一直没调试成功,所以就参考了力扣官网的代码,积累一下回溯算法的实现和基本实现思路,即先试探后回溯,结果在下面…...

博物馆展厅AI交互数字人,解锁创新的文化交互体验
在智能化时代,博物馆展厅融入AI交互数字人,可以为游客给予实时交互的旅游服务,AI交互数字人可以承担智能引导、讲解、接待、客服与导游等多重角色,为游客塑造崭新的旅游体验。 AI交互数字人相比传统的录屏解说相比,AI…...

DS18B20数字温度传感器操作解析
文章目录 引言特点工作原理引脚说明配置寄存器温度寄存器时序初始化时序写时序读时序 引言 DS18B20 是一种广泛使用的数字温度传感器,具有高精度和易用性。是Dallas Semiconductor公司(现为Maxim Integrated公司)生产的单总线数字温度传感器…...

你的财富正在被一个叫做通货膨胀的怪兽给吞噬掉,你却浑然不觉。
据统计,2024年全球总体通货膨胀率预计达到5.8%,这意味着:你的财富正在被一个叫做通货膨胀的怪兽给吞噬掉,你却浑然不觉。 数据来源:国际货币基金组织 如何跑赢通货膨胀? 家庭财富的积累速度,要…...

医疗设备漏费控制管理系统的必然性及未来发展性
医疗设备控费的必然性 医疗改革的要求 随着医疗改革的不断深入,原有的医药模式已经发生了改变。药品和耗材零差价的执行,使得医院需要寻找新的开源节流、降耗增效的方法。医疗设备控费系统的出现,正是为了满足这种管理需求。 控制成本和优…...

软件设计师笔记-网络基础知识
计算机网络的发展 计算机网络(计算机技术通信技术)的发展是一个逐步演进的过程,从简单的具有通信功能的单机系统,到复杂的以局域网及因特网为支撑环境的分布式计算机系统,这一历程经历了多个关键阶段: #me…...

MMC和eMMC的区别
MMC 和 eMMC 的区别 1. MMC MMC(MultiMediaCard)是一种接口协议,定义了符合这一接口的内存器,称为 MMC 储存体或 MMC 卡。它是一种非易失性存储器件,广泛应用于消费类电子产品中。 1.1 外观及引脚定义 MMC卡共有七个…...

亚马逊爬虫(Amazonbot)IP地址,真实采集数据
一、数据来源: 1、这批亚马逊爬虫(Amazonbot)IP来源于尚贤达猎头公司网站采集数据; 2、数据采集时间段:2023年10月-2024年7月; 3、判断标准:主要根据用户代理是否包含“Amazonbot”和IP核…...

Spring Boot(八十四):集成Thumbnailator来生成缩略图
1 Thumbnailator简介 Thumbnailator是一个用于Java的缩略图生成库。通过Thumbnailator提供的流畅接口(fluent interface)的方式可以完成复杂的缩略图处理任务,无需访问Image I/O API并通过Graphics2D对象手动操作BufferedImages。 2 代码示例 2.1 引入依赖 <dependency&g…...

MySQL基础操作全攻略:增删改查实用指南(上)
本节目标: NOT NULL - 指示某列不能存储 NULL 值。 UNIQUE - 保证某列的每行必须有唯一的值。 DEFAULT - 规定没有给列赋值时的默认值。 PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标 识&am…...

SAP MM学习笔记 - 豆知识02 - MR21 修改物料原价,MM02 修改基本数量单位/评价Class,MMAM 修改物料类型/评价Class
上一章讲了一些豆知识。比如 - MM50 批量扩张品目 - XK05/06 Block/消除供应商 - MM06/MM16 品目消除 - SE11/SE16/SE16/SE16N/SE16H/DB02 等查看常用的操作Table和数据的T-code SAP MM学习笔记- 豆知识01 - MM50 批量扩张,XK05/XK06 Block/消除供应商…...

谷粒商城实战笔记-126-全文检索-ElasticSearch-整合-测试保存
文章目录 一,谷粒商城实战笔记-126-全文检索-ElasticSearch-整合-测试保存1,在Elasticsearch的配置类中增加通用设置2,索引数据3,验证 一,谷粒商城实战笔记-126-全文检索-ElasticSearch-整合-测试保存 1,在…...