当前位置: 首页 > news >正文

【C++笔记】list结构剖析及其模拟实现

【C++笔记】list结构剖析及其模拟实现

🔥个人主页大白的编程日记

🔥专栏C++笔记


文章目录

  • 【C++笔记】list结构剖析及其模拟实现
    • 前言
    • 一 .list的结构及其介绍
      • 1.1list的结构
      • 1.2list的使用
      • 1.3迭代器划分
    • 二.list的模拟实现
      • 2.1 list结构的定义
      • 2.2iterator迭代器
      • 2.3list迭代器
      • 2.3构造
      • 2.4拷贝构造
      • 2.5 operator=
      • 2.6 insert
      • 2.7 erase
      • 2.8 clear
      • 2.9析构函数
    • 三.按需实例化
    • 四.迭代器失效
    • 五.initializer_list
    • 后言

前言

哈喽,各位小伙伴大家好!上期我们讲了vector和深浅拷贝。今天我们来讲一下list及其实现。话不多说,我们进入正题!向大厂冲锋
在这里插入图片描述

一 .list的结构及其介绍

1.1list的结构

list的底层结构是一个带哨兵位头结点的双向链表。

1.2list的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口。

  • 构造
  • 迭代器
    此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。

    在这里插入图片描述

需要注意的是list的不支持下标+[]。
因为之前像vector这样底层连续的空间。直接用+指针下标即可索引到目标值。
但是list空间不连续。所以需要遍历n次依次移动才可以。所以时间复杂度是O(n).
语法上可以实现,但是可行性上成本很高所以list没有实现operator[]

【注意】

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

这就是list的迭代器。

  • list capacity
    在这里插入图片描述

  • list element access

  • list modifiers

  • emplace_back
    emplace_back这个接口和push_back差不多。


只是emplace_back支持传构造自定义对象的参数。
所以这种场景下emplace_back更高效。少了依次拷贝构造

  • splice
    这里接口的主要功能是将一个链表的节点转移到另一个链表。
    也可以调整当前链表的节点顺序。
    在这里插入图片描述
    转移链表的节点
    调整当前链表

1.3迭代器划分

根据功能和性质可以将迭代器这样划分

而迭代器的底层结构决定了他的性质。
例如vector底层结构连续就可支持随机访问。
同时迭代器的性质决定了可以使用那些算法。
例如算法库的sort算法就要求是随机迭代器。

因为他的底层是快排。需要支持随机访问和下标±[]。
所以list不可以库的sort,因为他不支持随机迭代器。
所以list自己支持了一个sort

同时C++库里对迭代器的定义使用了继承的概念。子类就是特殊的父类

如果我们想查看某个容器的迭代器就去官网查看即可。

二.list的模拟实现

list因为底层空间不连续所以迭代器我们要用模版封装起来 节点也用模版封装起来
list也是模版封装。

2.1 list结构的定义

template<class T>
struct list_node 
{T data;list_node<T>* prev;list_node<T>* next;list_node(const T& x=T()):data(x),next(nullptr),prev(nullptr){}
};
template<class T,class Ref,class Ptr>
struct list_iterator
{typedef list_node<T> Node;typedef list_iterator<T,Ref,Ptr> self;
};
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;private:Node* _head;size_t _size;
};

2.2iterator迭代器

  • operator±

operator±我们只需要手动让迭代器指向前后位置即可。

self& operator++()
{self tmp(*this);_node=_node->next;return *this;
}
self& operator--()
{_node = _node->prev;return *this;
}
  • operator* 和operator->
    operator*就直接返回data即可。
    这里为了支持T是自定义类型指针访问数据。
    我们需要支持operator->取出节点data的地址。
    同时为了防止const_iterator和iterator两个类模版冗余,
    并且这两个模版只有这两个函数的返回值不同。
    *返回T& ->返回T *
    我们让list和list_iterator多加两个模版参数,让这两个模版参数做返回值即可。
Ref operator*()
{return _node->data;
}
Ptr operator->()
{return &_node->data;
}

需要注意的是如果T是自定义类型
那it->a1这里是省略了一个->.

  • operator++ - -
    这里我们自己手动移动_node即可。
    如果后置++ - -我们先拷贝一份当前位置再移动即可。
self& operator++()
{_node = _node->next;return *this;
}
self& operator--()
{_node = _node->prev;return *this;
}
self& operator--(int)
{self tmp(*this);_node = _node->prev;return tmp;
}
self& operator++(int)
{self tmp(*this);_node=_node->next;return *this;
}

这里return *this会调用迭代器的拷贝构造。
但是我们不用写。因为编译器会自动生成一份浅拷贝的拷贝构造。
那浅拷贝会不会有问题呢?

不会,因为我们要的就是浅拷贝。

  • operator!=和operator==
    operator!=和operator==直接判断指针是否相等即可。
bool operator!=(const self& s) const
{return _node != s._node;
}
bool operator==(const self& s) const
{return _node == s._node;
}

2.3list迭代器

迭代器我们直接返回哨兵位的下一个数据节点和哨兵位节点即可

iterator begin()
{return _head->next;
}
iterator end()
{return _head;
}
const_iterator begin() const
{return _head->next;
}
const_iterator end() const
{return _head;
}

2.3构造

我们先写一个初始化链表的函数。
new一个哨兵位节点。让节点的前后指针都指向自己即可。

void empty_init()
{_head = new Node;_head->next = _head;_head->prev = _head;_size = 0;
}
list()
{empty_init();
}

2.4拷贝构造

拷贝构造我们先初始化链表,然后把链表节点尾插到新链表即可

list(initializer_list<T> il)
{empty_init();for (auto& x : il){push_back(x);}
}

2.5 operator=

这里我们让先拷贝一份形参list,然后交换list和*this即可。函数结束后list自动销毁。

void swap(list<T> list)
{std::swap(_head, list._head);std::swap(_size, list._size);
}
list<T>& operator=(list<T> list)
{swap(list);return *this;
}

2.6 insert

insert要在某个位置插入数据。
我们new开一个节点,将前后节点和newnode连接起来即可。

iterator insert(iterator pos, const T& x)
{Node* cur = pos._node;Node* prev = cur->prev;Node* newnode = new Node(x);//prev newnode curnewnode->next = cur;newnode->prev = prev;prev->next = newnode;cur->prev = newnode;++_size;return newnode;
}

2.7 erase

erase连接前后节点。释放pos位置的节点即可。
同时防止释放哨兵位的头结点。

iterator erase(iterator pos)
{assert(pos != end());//防止销毁哨兵位的头结点Node* next = pos._node->next;Node* prev = pos._node->prev;next->prev = prev;prev->next = next;delete pos._node;//释放原节点--_size;return next;
}

2.8 clear

clear只需要从begin开始erase节点即可。注意erase后迭代器失效,要接受返回值也就是下一个位置的迭代器。

void clear()
{auto it = begin();while (it != end()){it = erase(it);}
}

2.9析构函数

复用clear清空节点后,释放哨兵位节点,再把_head置空即可。

~list()
{clear();delete _head;_head = nullptr;
}

三.按需实例化

编译器对模版是按需实例化。
调用了才会实例化,不调用就不会实例化。

四.迭代器失效

  • insert
    list的insert不会导致迭代器失效。

  • erase
    erase迭代器失效

五.initializer_list

C++11中,list还可以这样初始化。
用一个花括号括起来,里面就是初始化的内容。

这主要与initializer_list类型有关。C++11标准库之后可以认为花括号括起来的类型就是initializer_list。
在这里插入图片描述

它的底层在栈上开一个数组把初始化内容存起来,initializer_list对象有两个指针。
一个指针指向数据的开始,一个指针指向结束。

它支持这几个成员。

迭代器支持只读

所以我们要支持一个initializer_list的list构造即可实现花括号初始化。

	list(initializer_list<T> il){empty_init();for (auto& x : il)//支持迭代器就是支持范围for{push_back(x);}}

支持迭代器就支持范围for.
将initializer_list存储的数据拿来尾插即可。

后言

这就是list结构剖析及其模拟实现。大家自己好好消化。今天就分享到这,感谢各位的耐心垂阅!咱们下期见!拜拜~

在这里插入图片描述

相关文章:

【C++笔记】list结构剖析及其模拟实现

【C笔记】list结构剖析及其模拟实现 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】list结构剖析及其模拟实现前言一 .list的结构及其介绍1.1list的结构1.2list的使用1.3迭代器划分 二.list的模拟实现2.1 list结构…...

C#进阶1

C#进阶1 本文章主要介绍C#的进阶知识&#xff0c;如反射&#xff0c;特性.... 参考视频链接 原码 文章目录 C#进阶1反射步骤泛型反射调用方法 获取属性 特性特性的定义步骤扩展枚举练习 反射 在 C# 中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&a…...

PHP如何对输出进行转义

在PHP中&#xff0c;对输出进行转义是为了防止跨站脚本攻击&#xff08;XSS&#xff09;和其他安全问题。PHP提供了多种函数来对输出进行转义&#xff0c;这些函数根据输出的上下文&#xff08;如HTML、JavaScript、URL等&#xff09;而有所不同。以下是一些常用的转义函数及其…...

Windows 10 安装Docker踩过的坑和解决-31/10/2024

目录 环境版本 一、Docker Desktop双击启动没反应&#xff0c;open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified. 二、Docker Desktop运行run命令时显示错误HTTP code 500 并且错误大意是服务器拒绝访问 三、检测Docker是否可以正常使用…...

【应急响应】Linux植入恶意程序排查流程

文章目录 前言一、Linux入侵检查二、Linux系统被入侵/中毒有哪些现象三、Linux系统被入侵/中毒处置过程四、Linux安全防护措施五、服务器被GetShell渗透解决办法(案例)前言 本篇文章主要是以我们日常的运维工作中对Linux服务器进行安全检查,进一步介绍如何使用具体命令来对Li…...

微信小程序app.js里面onLaunch里面的函数比page里面的onshow里面的方法后执行

微信小程序app.js里面onLaunch里面的函数比page里面的onshow里面的方法后执行 我们在app.js里面执行登录时可以调用checkLoginReadyCallback wx.login({ success: (res) > { $api .login({ jsCode: res.code, }) .then((res1) > { wx.hideLoading(); if (res1.code 0) …...

斐波那契时间序列,精准捕捉市场拐点 MT4免费公式源码!

指标名称&#xff1a;斐波那契时间序列 版本&#xff1a;MT4 ver. 2.01 斐波那契时间序列是一种技术分析工具&#xff0c;通过将斐波那契数列&#xff08;如1, 2, 3, 5, 8, 13等&#xff09;应用于时间轴上&#xff0c;用于预测市场价格的时间周期拐点。斐波那契时间序列在股…...

计算机的错误计算(一百四十)

摘要 探讨 MATLAB 中函数 的计算精度。 从计算机的错误计算&#xff08;一百三十九&#xff09;知&#xff0c;对于对数运算&#xff0c;当真数在 1 附近时&#xff0c;计算机的输出会出现较大误差。为此&#xff0c;IEEE 754-2019 中专门定义有函数 其目的就是当自变量在 …...

JavaEE初阶---网络原理(四)--IP协议/DNS协议

文章目录 1.初识网络层&#xff08;了解即可&#xff09;2.地址管理2.1动态分配2.2网络地址转换2.3IP-v6最终解 3.网段划分4.以太网协议--数据链路层5.DNS应用层协议 1.初识网络层&#xff08;了解即可&#xff09; 网络层做的事情就是下面的两个&#xff1a; 1&#xff09;地…...

LeetCode20:有效的括号

原题地址&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合…...

简单介绍Class文件、Dex文件以及ELF文件

Class文件 Class文件是Java源代码文件经Java编译器编译后得到的Java字节码文件。对比Linux、Windows上的可执行文件而言&#xff0c;Class文件可以看作是Java虚拟机的可执行文件。 Dex文件 Dex文件是Android平台上与传统Class文件对应的Java字节码文件。Dex文件的核心内容与Cl…...

Vivo开奖了,劝退价。。

vivo 也开奖了&#xff0c;不过有小伙伴反馈是个劝退价&#xff0c;甚至不如隔壁的 oppo&#xff0c;要说这两家也是渊源颇深&#xff0c;一家是绿厂&#xff0c;一家是蓝厂&#xff0c;高管也都是早期步步高出来的。 给大家盘一下开奖的信息&#xff0c;方便大家横向做个对比&…...

鸿蒙打包hvigorw clean报错No npmrc file is matched in the current user folder解决

问题 在执行hvigorw clean等命令时&#xff0c;报错如下&#xff1a; Error: The hvigor depends on the npmrc file. No npmrc file is matched in the current user folder. Configure the npmrc file first解决方案 在用户当前目录下新建.npmrc文件&#xff0c;并配置如下…...

无人机救援系统基本组成

无人机救援系统基本组成 1. 源由2. 组成2.1 无人机载具2.1.1 多旋翼2.1.2 垂起固定翼2.1.3 智能避障2.1.4 物资投递 2.2 智能吊舱2.2.1 云台2.2.2 高清摄像2.2.3 红外热成像2.2.4 激光测距2.2.5 目标跟踪 2.3 通讯链路2.3.1 超长距离通信2.3.2 长距离通信2.3.3 中等距离通信 2.…...

git入门教程

git入门教程1&#xff1a;git简介git入门教程2&#xff1a;git发展历史git入门教程3&#xff1a;安装配置git入门教程4&#xff1a;git工作流程git入门教程5&#xff1a;git仓库操作git入门教程6&#xff1a;git基本版本控制git入门教程7&#xff1a;git与远程仓库的交互git入门…...

AMBA:AHB_Slave_Mux的解析与HREADY、HREADYOUT

相关阅读 AMBAhttps://blog.csdn.net/weixin_45791458/category_12800219.html?spm1001.2014.3001.5482 简介 从1999年的AMBA2发布以来&#xff0c;AHB协议中就存在数据选择器&#xff0c;如图1所示的AHB2协议的总线互连。 图1 AHB2的总线互连 这幅图画得比较粗糙&#xff0…...

初始Linux (2) : 权限

1. su [用户名]及权限概念 Linux中有两种用户&#xff1a;普通用户、超级用户 超级用户可以再 linux 系统下做任何事情&#xff0c;不受限制&#xff1b;而普通用户只能做有限的事情。 可以使用指令&#xff1a;su -快速进入root账户&#xff0c;但需要输入相关密码。 超级用…...

在Mac下安装时间序列软件Hector

1.软件介绍 Hector 是一款开源软件&#xff0c;专用于 GNSS 时间序列数据的处理与分析&#xff0c;广泛应用于地球科学研究。它帮助研究人员从 GNSS 数据中提取长期趋势、周期性成分&#xff0c;并建模噪声特性&#xff0c;用于地壳形变、地震影响和气候变化等方面的研究。Hec…...

JVM1.8内存模型

一、内存模型概览 本文介绍的是JDK1.8的内存模型。1.8同1.7相比&#xff0c;最大的差别就是元空间取代了永久代。元空间的本质和永久代类似&#xff0c;都是堆JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于&#xff1a;元空间并不存在虚拟机中&#xff0c;而是…...

windows C#-类型系统(上)

C# 是一种强类型语言。 每个变量和常量都有一个类型&#xff0c;每个求值的表达式也是如此。 每个方法声明都为每个输入参数和返回值指定名称、类型和种类(值、引用或输出)。 .NET 类库定义了内置数值类型和表示各种构造的复杂类型。 其中包括文件系统、网络连接、对象的集合和…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

Matlab实现任意伪彩色图像可视化显示

Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中&#xff0c;如何展示好看的实验结果图像非常重要&#xff01;&#xff01;&#xff01; 1、灰度原始图像 灰度图像每个像素点只有一个数值&#xff0c;代表该点的​​亮度&#xff08;或…...

C++ 类基础:封装、继承、多态与多线程模板实现

前言 C 是一门强大的面向对象编程语言&#xff0c;而类&#xff08;Class&#xff09;作为其核心特性之一&#xff0c;是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性&#xff0c;包括封装、继承和多态&#xff0c;同时讨论类中的权限控制&#xff0c;并展示如何使用类…...

C# WPF 左右布局实现学习笔记(1)

开发流程视频&#xff1a; https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码&#xff1a; GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用&#xff08;.NET Framework) 2.…...

uniapp获取当前位置和经纬度信息

1.1. 获取当前位置和经纬度信息&#xff08;需要配置高的SDK&#xff09; 调用uni-app官方API中的uni.chooseLocation()&#xff0c;即打开地图选择位置。 <button click"getAddress">获取定位</button> const getAddress () > {uni.chooseLocatio…...