【STL】list常见用法及模拟实现(附完整源码)

目录

      • 前言
      • 1. list介绍及使用
        • 1.1 list介绍
        • 1.2 list使用
      • 2. list模拟实现
        • 2.1 迭代器功能分类
        • 2.2 list迭代器模拟实现
          • 2.2.1 普通迭代器
          • 2.2.2 const迭代器
      • 3. list和vector区别
      • 4. 源码

前言

这篇文章我们继续STL中容器的学习,这篇文章要讲解的是list。

1. list介绍及使用

1.1 list介绍

list文档
在这里插入图片描述
list的底层实现就是数据结构学过的带头双向循环链表:
在这里插入图片描述

1.2 list使用

我们来看一下几个常用的接口:

首先看一下构造函数:
在这里插入图片描述
这里几个都是我们熟悉的,默认构造、n个val构造、迭代器区间构造以及拷贝构造。
我们再来看一下迭代器:
在这里插入图片描述
我相信之前的文章对迭代器的介绍已经很详细了这里我们就不过多赘述了。

我们再来看一下修改操作:
在这里插入图片描述

这里list与string和vector区别在于:
list没有重载[],也就是说我们要遍历和访问list,就只能用迭代器。迭代器才是通用的方式,所有的容器都可以用迭代器,而[]只是针对特定容器的特殊方式。

遍历

int main()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(3);l.push_back(5);for (auto it = l.begin(); it != l.end(); ++it)cout << *it << " ";cout << endl;for (auto e : l)cout << e << " ";cout << endl;for (auto rit = l.rbegin(); rit != l.rend(); ++rit)cout << *rit << " ";cout << endl;return 0;
}

在这里插入图片描述

我们再来看几个之前没怎么用过的接口:
在这里插入图片描述
这里的splice ,它可以把链表的一部分转移到另一个链表:
在这里插入图片描述
remove就是删除指定的元素:
在这里插入图片描述
merge可以合并两个有序链表:
在这里插入图片描述

2. list模拟实现

2.1 迭代器功能分类

1、单向迭代器:只能++,不能- -。例如单链表,哈希表;
2、双向迭代器:既能++也能--。例如双向链表;
3、随机访问迭代器:能++ - -,也能+-。例如vector和string。
迭代器是内嵌类型(内部类或定义在类里)

2.2 list迭代器模拟实现
2.2.1 普通迭代器

在模拟实现string、vector时是使用的原生指针,没有将迭代器用类进行封装,但是STL标准库也是用类封装了迭代器。而在模拟实现list迭代器时,不能用原生指针了,因为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;__list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){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;}bool operator!=(const self& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};
2.2.2 const迭代器

我们先来看一下错误写法:
在这里插入代码片typedef __list_iterator<T> iterator; const list<T>::iterator it=lt.begin();

在STL库中是通过类模板多给一个参数来实现,这样,同一份类模板就可以生成两种不同的类型的迭代器

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;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);}

3. list和vector区别

vectorlist
底 层 结 构动态顺序表,一段连续空间带头结点的双向循环链表
随 机 访 问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(N)
插 入 和 删 除任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)
空 间 利 用 率底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层结点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低
迭 代 器原生态指针对原生态指针进行封装
迭 代 器 失 效在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效带头结点的双向循环链表
使 用 场 景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

4. 源码

list.h

#include<iostream>
using namespace std;
namespace w
{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){}};// 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*(){return _node->_val;}Ptr operator->(){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;}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;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);}_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;}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(){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()){cout << *it << " ";++it;}cout << endl;}}

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

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

相关文章

数据分析:人工智能篇

文章目录 第三章 数据可视化库matplotlib3.1 matplotlib基本绘图操作3.2 plot的线条和颜色3.3 条形图分析3.4 箱型图分析3.5 直方图分析3.6 散点图分析3.7 图表的美化 第四章 数据预测库Sklearn4.1 sklearn预测未来4.2 回归数据的预测4.2.1 回归数据的切分4.2.2 线性回归数据模…

数学建模Matlab之评价类方法

大部分方法来自于http://t.csdnimg.cn/P5zOD 层次分析法 层次分析法&#xff08;Analytic Hierarchy Process, AHP&#xff09;是一种结构决策的定量方法&#xff0c;主要用于处理复杂问题的决策分析。它将问题分解为目标、准则和方案等不同层次&#xff0c;通过成对比较和计算…

js——深拷贝和浅拷贝

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。对于基本数据类型&#xff0c;例如字符串、数字、布尔值等&#xff0c;由于它们是按值传递的&#xff0c;所以不存在深拷贝和浅拷贝的问题。 深拷贝 将对象从内存中完整拷贝出来&#xff0c;从堆内存中开辟一个新的…

7-2 图着色问题

输入样例&#xff1a; 6 8 3 2 1 1 3 4 6 2 5 2 4 5 4 5 6 3 6 4 1 2 3 3 1 2 4 5 6 6 4 5 1 2 3 4 5 6 2 3 4 2 3 4 输出样例&#xff1a; Yes Yes No No idea 注意合理的方案需满足&#xff1a;用到的颜色数 给定颜色数 solution #include <cstdio> #include &l…

Linux系统编程系列之线程池

Linux系统编程系列&#xff08;16篇管饱&#xff0c;吃货都投降了&#xff01;&#xff09; 1、Linux系统编程系列之进程基础 2、Linux系统编程系列之进程间通信(IPC)-信号 3、Linux系统编程系列之进程间通信(IPC)-管道 4、Linux系统编程系列之进程间通信-IPC对象 5、Linux系统…

PyTorch入门之【tensor】

目录 tensor的创建tensor的相关信息tensor的运算 tensor的创建 1.手动创建 import torch test1torch.tensor([1,2,3])#一维时为向量 test2torch.tensor([[1,2,3]])#二维时为矩阵 test3torch.tensor([[[1,2,3]]])#三维及以上统称为tensor print(test1) print(test2) print(tes…

【RP-RV1126】烧录固件使用记录

文章目录 烧录完整固件进入MASKROM模式固件烧录升级中&#xff1a;升级完成&#xff1a; 烧录部分进入Loader模式选择文件切换loader模式 烧录完整固件 完整固件就是update.img包含了所有的部件&#xff0c;烧录后可以直接运行。 全局编译&#xff1a;./build.sh all生成固件…

TCP端口崩溃,msg:socket(): Too many open files

一、现象 linux系统中运行了一个TCP服务器&#xff0c;该服务器监听的TCP端口为10000。但是长时间运行时发现该端口会崩溃&#xff0c;TCP客户端连接该端口会失败&#xff1a; 可以看到进行三次握手时&#xff0c;TCP客户端向该TCP服务器的10000端口发送了SYN报文&#xff0c;…

(二)正点原子STM32MP135移植——TF-A移植

目录 一、TF-A概述 二、编译官方代码 2.1 解压源码 2.2 打补丁 2.3 编译准备 &#xff08;1&#xff09;修改Makfile.sdk &#xff08;2&#xff09;设置环境变量 &#xff08;3&#xff09;编译 三、移植 3.1 复制官方文件 3.2 修改电源 3.3 修改TF卡和emmc 3.4 添…

【面试HOT100】哈希双指针滑动窗口

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于LeetCodeHot100进行的&#xff0c;每个知识点的修正和深入主要参考…

【数据结构与算法】树、二叉树的概念及结构(详解)

前言: &#x1f4a5;&#x1f388;个人主页:​​​​​​Dream_Chaser&#xff5e; &#x1f388;&#x1f4a5; ✨✨专栏:http://t.csdn.cn/oXkBa ⛳⛳本篇内容:c语言数据结构--树以及二叉树的概念与结构 目录 一.树概念及结构 1.树的概念 1.1树与非树 树的特点&#xff1…

XXL-JOB源码梳理——一文理清XXL-JOB实现方案

分布式定时任务调度系统 流程分析 一个分布式定时任务&#xff0c;需要具备有以下几点功能&#xff1a; 核心功能&#xff1a;定时调度、任务管理、可观测日志高可用&#xff1a;集群、分片、失败处理高性能&#xff1a;分布式锁扩展功能&#xff1a;可视化运维、多语言、任…

【计算机网络笔记八】应用层(五)HTTPS

什么是 HTTPS HTTPS 解决了 HTTP 不安全的问题 HTTP 整个传输过程数据都是明文的&#xff0c;任何人都能够在链路中截获、修改或者伪造请求&#xff0f;响应报文&#xff0c;数据不具有可信性。 ① HTTPS 使用加密算法对报文进行加密&#xff0c;黑客截获了也看不懂 ② HTTP…

Play Beyond:Sui让优秀的游戏变得更好

自问世以来&#xff0c;视频游戏就紧随着文化产业发展。从Pong和Space Invaders的时代到Animal Crossing和Among Us&#xff0c;伟大的游戏总有能力吸引玩家&#xff0c;并推动娱乐产业发展。根据Grand View Research的数据&#xff0c;全球视频游戏市场在2022年估计为2170.6亿…

CUDA C编程权威指南:1.1-CUDA基础知识点梳理

主要整理了N多年前&#xff08;2013年&#xff09;学习CUDA的时候开始总结的知识点&#xff0c;好长时间不写CUDA代码了&#xff0c;现在LLM推理需要重新学习CUDA编程&#xff0c;看来出来混迟早要还的。 1.CUDA 解析&#xff1a;2007年&#xff0c;NVIDIA推出CUDA&#xff08…

Docker 日志管理 - ELK

Author&#xff1a;rab 目录 前言一、Docker 日志驱动二、ELK 套件部署三、Docker 容器日志采集3.1 部署 Filebeat3.2 配置 Filebeat3.3 验证采集数据3.4 Kibana 数据展示3.4.1 创建索引模式3.4.2 Kibana 查看日志 总结 前言 如何查看/管理 Docker 运行容器的日志&#xff1f;…

图像拼接后丢失数据,转tiff报错rasterfile failed: an unknown

图像拼接后丢失数据 不仅是数据丢失了&#xff0c;还有个未知原因报错 部分数据存在值不存在的情况 原因 处理遥感数据很容易&#xff0c;磁盘爆满了 解决方案 清理一些无用数据&#xff0c;准备买个2T的外接硬盘用着了。 然后重新做处理

redis高可用(主从复制,哨兵,集群)

目录 一、主从复制&#xff1a; 1.主从复制介绍&#xff1a; 2.主从复制的作用&#xff1a; 3.主从复制流程&#xff1a; 4.搭建Redis 主从复制&#xff1a; 4.1 环境准备&#xff1a; 4.2 安装redis&#xff1a; 4.3 master节点修改 Redis 配置文件&#xff1a; 4.4 slave节点…

Linux学习之悟空派上实现OLED的无线网IP及CPU温度显示【守护进程】

起因 最近各种网购平台似乎都在推送99元的悟空派全志H3的开发板&#xff0c;出于好奇就买了一块来试试水&#xff0c;由于这块板子基本上和orangepi-Zero的硬件结构一模一样&#xff0c;所以设备树、boot这些就用orangepi现成的部件了。 因为本人比较喜欢使用SSH操作&#xff…