list的常用接口底层实现与介绍

目录

概念:

list的基本结构:

list的迭代器⭐❤: 

自定义类型的完善: 

const的迭代器:

insert 

erase:

size 

empty 

push_back 、push_front 、pop_back、pop_front 

swap 、operator=

析构函数、clear() 


 

概念:
  1. list是序列容器,允许在序列中的任何位置执行固定O(1)时间复杂度的插入和删除操作,并在两个方向进行迭代。
  2. list容器使用双链表实现;双链表将每个元素存储在不同的位置,每个节点通过next,prev指针链接成顺序表。
  3. list与其他标准序列容器(array,vector和deque)相比,list通常可以在容器内的任何位置插入、提取和移动元素。
  4. list与其他标准序列容器(array,vector和deque)相比,list和forward_list(单链表实现)的主要缺点是他们不能通过位置直接访问元素;例如,要访问列表中的第五个元素,必须从已知位置(开始或结束)迭代到该位置,需要哦线性时间开销。
  5. 存储密度低,list要使用一些额外的内容空间(next,prev)来保持与每个元素相关联(前后续的线性)的链接信息,从而导致存储小元素类型(如char,short,int等)的列表的存储密度低。

list的基本结构:
#include<iostream>
#include<assert.h>
using namespace std;
namespace bit {template <class T>struct ListNode{ListNode<T>* _next;ListNode<T>* _prev;T _data;ListNode(const T& x = T()):_next(nullptr),_prev(nullptr),_data(x){}};template<class T>class list {typedef ListNode<T> Node;public:list(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}private:Node* _head;size_t _size;};
}

通过list的概念我们可以得知,list在本质上就是一种带头的双向链表结构,所以在创建list类之前,我们首先要构建一个节点的结构体,其次在list的构造函数中,为了让list遵循它本质上的数据结构,以及通过之后的插入删除等等操作,利用带头双向链表结构的特点,我们将成员变量特地设置为头节点以及长度。

list的迭代器⭐❤: 

list的迭代器特殊之处: 

  • 迭代器的本质就是不管是什么类型的数据都可以进行访问!所以该如何使用迭代器遍历链表内的数据呢?是否能使用前驱、后继指针充当迭代器?答案是不能!
  • 如果使用前驱后继指针充当迭代器,那么就需要遇到一个问题,链表的各个节点是不同位置不同地址的!
  • 所以如果使用指针+1的方式并不能正确的遍历链表!
  • 其次,如果使用前驱后继指针当迭代器,那么解引用能得到节点内的数据吗?不能!因为Node * 解引用后上一个Node 是一个strcut结构体

所以对于list的迭代器,正确的解决方案是另外在设置一个类对迭代器进行分装操作! 

	template<class T>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T> self;Node* _node;ListIterator(Node*node):_node(node){}};

在原先的原身指针 prev和next下,并不能解决迭代器遍历操作,以及解引用操作,因为节点的空间问题并不能使用指针+1的操作,以及解引用prev和next并不能直接获取到节点内部存储的数值元素,所以我们需要在这个封装操作中进行。

至于这个封装为什么是结构体呢?

在C++中,struct和class是非常相似的,唯一的区别是默认的访问权限不同。在struct中,成员默认是公共的(public),而在class中,默认是私有的(private)。因此,在C++中,struct内部是可以定义函数的。 

在这个结构体的内部我们需要解决迭代器的遍历、解引用、遍历修改、不等于 等运算符重载问题! 

		//*T& operator*(){return _node->_data;}//前置++ 因为这里是链表所以++应该是指向下一个节点!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;}slef& operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& it){return _node != it._node;}

我们定义这些重载运算符的意义就在于为了之后我们在定义begin时,可以直接使用封装的重载运算符!

		typedef ListIterator<T> iteator;iterator begin(){iterator it(_head->_next);return it;}iterator end(){iterator it(_head);return it;}

自定义类型的完善: 

自定义类型的完善 ,因为我们写的是一个自定义类型,所以读取*it后解决完后还是一个自定义类型的数据结构,所以需要在使用数据结构的写法,表明其中内部的数据即可!

 

		T* operator->(){return &_node->_data;}

it->是需要进行拆解的,可以变成it.operator()->,这里其实是编译器的一种隐藏操作,之前的it++也是一种隐藏操作,可以变化为it.operator++()

而it->_a1这里隐藏的是另一个-> ,也就是图中第二个->,第一个->是属于it的重载运算符标识!

const的迭代器:

首先要记住const不能调用非const的成员函数!但是非const可以调用const的成员函数

为了让const修饰的类型能够使用迭代器,我们需要根据const不能修改内容的特点进行另外设置一共专门让const使用的迭代器封装,但是由于只是需要变动operator*()和operator->所以我们可以使用模板类解决这类问题! 

template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* node):_node(node){}// *it//T& operator*()Ref operator*(){return _node->_data;}// it->//T* operator->()Ptr operator->(){return &_node->_data;}// ++itSelf& 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;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};
insert 

 有了迭代器之后了,可以利用迭代器的操作进行insert的底层实现

void insert(iterator pos, const T& val){Node* cur = pos._node;Node* newnode = new Node(val);Node* prev = cur->_prev;// prev newnode cur;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;}

erase:

操作和insert一样都是对指针的方向的修改!但是pos会在后面失效,也就是迭代器会失效,所以需要改变类型!然后进行返回!这里的返回变成了的pos节点的后面一个节点的迭代器。

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 iterator(next);}
size 
        size_t size() const{return _size;}
empty 
        bool empty(){return _size == 0;}
push_back 、push_front 、pop_back、pop_front 
        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());}
swap 、operator=
        void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}// lt1 = lt3list<T>& operator=(list<T> lt){swap(lt);return *this;}
析构函数、clear() 
		void clear(){iterator it = begin();while (it != end()){it = erase(it);}}~list(){clear();delete _head;_head = nullptr;}

 

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

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

相关文章

什么是CSGO游戏搬砖及游戏搬砖注意事项?

CSGO市场是指《反恐精英&#xff1a;全球攻势》游戏内的物品交易市场。玩家可以在这个市场上买卖各类虚拟物品&#xff0c;包括武器皮肤、刀具、手套等。CSGO市场的价格是由供需关系、稀有度、流行度等多个因素影响的。 一般来说&#xff0c;稀有度较高或者比较受欢迎的物品价格…

vscode安装通义灵码

作为vscode的插件&#xff0c;直接使用 通义灵码-灵动指间&#xff0c;快码加编&#xff0c;你的智能编码助手 通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研…

python--不死兔子问题

def rabbit(n):if n < 3:return 1return rabbit(n - 1) rabbit(n - 3)if __name__ __main__:print(rabbit(4))

1.Docker简介和安装

1 Docker 简介 1.1 Docker 是什么&#xff1f; docker是一个开源的应用容器引擎。 1.2 容器是什么&#xff1f; 容器是一种轻量级的虚拟化技术 &#xff0c;它是一个由应用运行环境、容器基础镜像组成的集合。 以 Web 服务 Nginx 为例&#xff0c;如下图所示&#xff1a;Ngin…

算法 - 符号表-下

&#x1f600;前言 推荐从上看到下 算法 - 符号表-上 &#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 算法 - 符号表查找树1. 插入操作2. 性质 红黑树1. 左旋转2. 右旋转3. 颜色转换4. 插入5. 分析 散列表1. 散列函数2. 拉链法3. 线性探测法3.1 查找3.2 插入3.3 删除3.5 …

外卖配送时间预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 项目背景 外卖服务的兴起: 随着互联网技术和移动应用的发展&#xff0c;外卖成为一种日益普及的餐饮服务方式。顾客通过餐厅、杂货店的网站或移…

查询SQL server数据库在后台执行过的语句

查询SQL server数据库在后台执行过的语句 SELECT TOP 30000total_worker_time/1000 AS [总消耗CPU 时间(ms)],execution_count [运行次数],qs.total_worker_time/qs.execution_count/1000 AS [平均消耗CPU 时间(ms)],last_execution_time AS [最后一次执行时间],min_worker_ti…

LInux脚本学习

1.注释 #单行注释 以 # 字符开头就是单行注释 当然第一行除外&#xff0c;比较特殊 2.多行注释 3.Shell文件的作用 Shell文件就是linux命令集 4.sh脚本的执行方式 bash xxx.sh 5.新建的文件会没有执行权限 #为文件赋予执行权限 chmod ux xxx.sh 6.编写规范 #!/bin/bash #…

2024.4.1 系统移植

TF-A移植 TF-A是基于 Arm 的可信固件 Trusted Firmware-A&#xff0c;简称 TF-A。它是一个开源软件&#xff0c;运行在一个硬件隔离的安全环境中并提供安全服务。 分析README文档 Compilation of TF-A (Trusted Firmware-A): > tf-a目录 1. Pre-requisite > 准备工作 …

paddlepaddle模型转换onnx指导文档

一、检查本机cuda版本 1、右键找到invdia控制面板 2、找到系统信息 3、点开“组件”选项卡&#xff0c; 可以看到cuda版本&#xff0c;我们这里是cuda11.7 cuda驱动版本为516.94 二、安装paddlepaddle环境 1、获取pip安装命令 &#xff0c;我们到paddlepaddle官网&#xff…

医院云HIS系统源码,二级医院、专科医院his系统源码,经扩展后能够应用于医联体/医共体

基于云计算技术的B/S架构的HIS系统&#xff0c;为医疗机构提供标准化的、信息化的、可共享的医疗信息管理系统&#xff0c;实现医患事务管理和临床诊疗管理等标准医疗管理信息系统的功能。 系统利用云计算平台的技术优势&#xff0c;建立统一的云HIS、云病历、云LIS&#xff0…

【OSTEP】并发:线程与多线程

" A flow of control within a process that consists of a PC, a register set and a stack space" 本章将介绍为单个运行进程提供的新抽象 —— 线程 (thread) 线程是 调度的一个基本单位&#xff08;basic unit of CPU scheduling&#xff09;一个单独的线程至…

MySQL 索引底层探索:为什么是B+树?

MySQL 索引底层探索&#xff1a;为什么是B树&#xff1f; 1. 由一个例子总结索引的特点2. 基于哈希表实现的哈希索引3. 高效的查找方式&#xff1a;二分查找4. 基于二分查找思想的二叉查找树5. 升级版的BST树&#xff1a;AVL 树6. 更加符合磁盘特征的B树7. 不断优化的B树&#…

rabbitMQ版本问题与下载

都到现在了&#xff0c;大家不会安装东西还是不看版本吧 云服务器买的是centos7&#xff0c;而erlang在24版本后不支持centos7了 所以需要找24版本以下的erlang&#xff0c;而不同erlang对应不同rabbitmq所以需要对应 下载erlang 说实话&#xff0c;自己安装&#xff0c;还是…

RIP协议(路由信息协议)

一、RIP协议概述 RIP协议&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;是一种基于距离矢量的内部网关协议&#xff0c;即根据跳数来度量路由开销&#xff0c;进行路由选择。 相比于其它路由协议&#xff08;如OSPF、ISIS等&#xff09;&#…

C++ | string类学习 | string的常见接口使用方式

目录 为什么要学习string类&#xff1f; C语言中的字符串 OOP面向对象编程 两个面试题 标准库中的string类 string类了解 string类的文档介绍 总结 string类的常用接口说明 string类对象的常见构造 string类对象的容量操作 size()和length() clear() resize(size…

【JVM】关于JVM垃圾回收

文章目录 &#x1f334;死亡对象的判断算法&#x1f338;引用计数算法&#x1f338;可达性分析算法 &#x1f333;垃圾回收算法&#x1f338;标记-清除算法&#x1f338;复制算法&#x1f338;标记-整理算法&#x1f338;分代算法&#x1f338;哪些对象会进入新生代&#xff1f…

idea2023.2.1 java项目-web项目创建-servlet类得创建

如何创建Java项目 1.1 方式1&#xff1a; 1.2 方式&#xff1a; 1.3 方式 如何创建web项目 方式 ----- 推荐 如何创建servlet类 复制6 中得代码 给servlet 配置一个路径 启动tomcat 成功了

Netty进阶

三. Netty 进阶 1. 粘包与半包 1.1 粘包现象 服务端代码 public class HelloWorldServer {static final Logger log LoggerFactory.getLogger(HelloWorldServer.class);void start() {NioEventLoopGroup boss new NioEventLoopGroup(1);NioEventLoopGroup worker new Ni…

时序预测 | Python实现VMD-CNN-LSTM时间序列预测

时序预测 | Python实现VMD-CNN-LSTM时间序列预测 目录 时序预测 | Python实现VMD-CNN-LSTM时间序列预测预测效果基本介绍模型描述代码设计预测效果 基本介绍 VMD-CNN-LSTM 是一种混合深度学习模型,结合了变分模态分解(VMD)、卷积神经网络(CNN)和长短期记忆网络(LSTM)的…