【C++练级之路】【Lv.8】【STL】list类的模拟实现



快乐的流畅:个人主页


个人专栏:《C语言》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 引言
  • 一、结点
  • 二、迭代器
    • 2.1 成员变量与默认成员函数
    • 2.2 operator*
    • 2.3 operator->
    • 2.4 operator++
    • 2.5 operator- -
    • 2.6 relational operators
  • 三、list
    • 3.1 成员变量
    • 3.2 迭代器
      • 3.2.1 begin
      • 3.2.2 end
    • 3.3 默认成员函数
      • 3.3.1 constructor
      • 3.3.2 destructor
      • 3.3.3 copy constructor
      • 3.3.4 operator=
    • 3.4 修改
      • 3.4.1 insert
      • 3.4.2 push_front
      • 3.4.3 push_back
      • 3.4.4 erase
      • 3.4.5 pop_front
      • 3.4.6 pop_back
      • 3.4.7 clear
      • 3.4.8 swap
  • 总结

引言

因为list结构的特殊性,所以拆分为结点、迭代器和list本身进行学习。

一、结点

细节:

  1. 使用struct,标明公有属性(这样从外部调用比较方便
  2. list是带头双向循环链表
  3. 提供全缺省的默认构造函数
template<class T>
struct __list_node
{
	__list_node<T>* _prev;
	__list_node<T>* _next;
	T _data;

	__list_node(const T& x = T())
		: _prev(nullptr)
		, _next(nullptr)
		, _data(x)
	{}
};

二、迭代器

由于list的每个结点物理空间不连续,导致迭代器不能像之前string、vector那样简单的设计为指针,而是设计为一个类(进行封装),以此完成*、->、++、–等一系列操作。

2.1 成员变量与默认成员函数

细节:

  1. 仍然使用struct,标明公有属性
  2. 成员变量是一个结点的指针
  3. 提供带参构造函数(其余的默认成员函数不用显式定义,浅拷贝即可)
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* n)
		: _node(n)
	{}
};

此时的迭代器设计,可以说是list乃至STL的精华,天才般地运用了类的优势。

2.2 operator*

细节:

  • 返回引用,为了区别普通迭代器和const迭代器
Ref operator*()
{
	return _node->_data;
}

2.3 operator->

细节:

  • 返回指针,为了区别普通迭代器和const迭代器
Ptr operator->()
{
	return &_node->_data;
}

2.4 operator++

细节:

  1. 为了区分前置和后置,后置参数加上int(无实际意义,以示区分)
  2. 前置传引用返回,后置传值返回
self& operator++()//前置++
{
	_node = _node->_next;
	return *this;
}

self operator++(int)//后置++
{
	self tmp(*this);
	_node = _node->_next;
	return tmp;
}

2.5 operator- -

细节:同上

self& operator--()//前置--
{
	_node = _node->_prev;
	return *this;
}

self operator--(int)//后置--
{
	self tmp(*this);
	_node = _node->_prev;
	return tmp;
}

2.6 relational operators

bool operator!=(const self& s)
{
	return _node != s._node;
}

bool operator==(const self& s)
{
	return _node == s._node;
}

三、list

3.1 成员变量

list类包含了

  • _head(指向哨兵位)
template<class T>
class list
{
public:
	typedef __list_node<T> node;
private:
	node* _head;
};

3.2 迭代器

typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;

3.2.1 begin

细节:

  1. begin()在_head->next
  2. 使用匿名对象
iterator begin()
{
	return iterator(_head->_next);
}

const_iterator begin() const
{
	return const_iterator(_head->_next);
}

3.2.2 end

细节:

  1. end()在_head
  2. 使用匿名对象
iterator end()
{
	return iterator(_head);
}

const_iterator end() const
{
	return const_iterator(_head);
}

3.3 默认成员函数

3.3.1 constructor

空初始化:创建哨兵位

void empty_init()
{
	_head = new node;
	_head->_prev = _head;
	_head->_next = _head;
}

无参构造

list()
{
	empty_init();
}

迭代器区间构造

细节:使用类模板,可以传任意类型的迭代器

template <class InputIterator>
list(InputIterator first, InputIterator last)
{
	empty_init();

	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

3.3.2 destructor

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

3.3.3 copy constructor

现代写法

细节:

  1. 迭代器区间构造,构造出临时对象
  2. 再使用list中的swap,交换*this和tmp的值,完成拷贝构造
list(const list<T>& lt)
{
	empty_init();

	list<T> tmp(lt.begin(), lt.end());
	swap(tmp);
}

3.3.4 operator=

现代写法

细节:

  1. 传参变成传值,这样就会拷贝构造出一个临时对象
  2. 再使用list中的swap,交换*this和tmp的值,完成赋值重载
list<T>& operator=(list<T> lt)
{
	swap(lt);
	return *this;
}

3.4 修改

3.4.1 insert

指定位置插入

细节:

  1. 在pos之前插入
  2. 迭代器不会失效
void insert(iterator pos, const T& x)
{
	node* cur = pos._node;
	node* prev = cur->_prev;
	node* new_node = new node(x);

	prev->_next = new_node;
	new_node->_prev = prev;
	cur->_prev = new_node;
	new_node->_next = cur;
}

3.4.2 push_front

头插

void push_front(const T& x)
{
	insert(begin(), x);
}

3.4.3 push_back

尾插

void push_back(const T& x)
{
	insert(end(), x);
}

3.4.4 erase

指定位置删除

细节:

  1. assert断言,防止删除哨兵位
  2. 返回删除节点的下一位,防止迭代器失效
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;

	return iterator(next);
}

3.4.5 pop_front

void pop_front()
{
	erase(begin());
}

3.4.6 pop_back

void pop_back()
{
	erase(--end());
}

3.4.7 clear

清除所有结点(除哨兵位以外)

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

3.4.8 swap

交换两个list类的值

细节:使用std库中的swap函数,交换各个成员变量的值

void swap(list<T>& lt)
{
	std::swap(_head, lt._head);
}

总结

学习完list类,对于STL中的精华——迭代器设计,有了更深一步的了解。同时,了解多参数模板的用途和方法,极大提高代码复用程度。


真诚点赞,手有余香

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

openGauss学习笔记-225 openGauss性能调优-系统调优-配置向量化执行引擎

文章目录 openGauss学习笔记-225 openGauss性能调优-系统调优-配置向量化执行引擎 openGauss学习笔记-225 openGauss性能调优-系统调优-配置向量化执行引擎 openGauss数据库支持行执行引擎和向量化执行引擎&#xff0c;分别对应行存表和列存表。 一次一个batch&#xff0c;读…

安装及使用Nginx

目录 一、编译安装Nginx 1、关闭防火墙&#xff0c;将安装nginx所需要软件包传到/opt目录下 2、安装依赖包 3、创建运行用户、组 4、编译安装nginx 5、创建软链接后直接nginx启动 6、创建nginx自启动文件 6.1 重新加载配置、设置开机自启并开启服务 二、yum安装 一、编…

【论文解读】transformer小目标检测综述

目录 一、简要介绍 二、研究背景 三、用于小目标检测的transformer 3.1 Object Representation 3.2 Fast Attention for High-Resolution or Multi-Scale Feature Maps 3.3 Fully Transformer-Based Detectors 3.4 Architecture and Block Modifications 3.6 Improved …

fatal error: costmap_2d/keepOutZone.h

fatal error: costmap_2d/keepOutZone.h: No such file or directory 7 | #include "costmap_2d/keepOutZone.h" 解决&#xff1a; #include "costmap_plugins/keepOutZone.h"代码中搜索 costmap_2d&#xff0c;全部替换成costmap_plugins&#xff1b…

MySQL高可用架构探秘:主从复制剖析、切换策略、延迟优化与架构选型

MySQL高可用的基石 在分布式系统中&#xff0c;单机节点在发生故障时无法提供服务&#xff0c;这可能导致长期的服务不可用&#xff0c;从而影响其他节点的运作&#xff0c;导致的后果非常严重 为了满足服务的高可用&#xff0c;往往是通过节点冗余&#xff08;新增相同功能的…

ABAQUS 软件在土木工程中的应用研究

摘要 随着土木工程的不断复杂化以及工程实践对土木工程分析计算要求越来越高,有限元技术在土木工程中的应用也越来越广泛。本文主要介绍国际大型通用有限元软件ABAQUS在土木工程中的应用&#xff0c;主要包括在建筑工程、桥梁工程、岩土工程中的应用&#xff0c;以期为相关工程…

【webrtc】m77 PacedSender

mediasoup是m77的代码,m77的代码并没有paced controller ,而且与paced sender 的逻辑混在了一起。结合大神们的代码分析,对照m77 进行 理解。m77 有ProbeController。给pacersender 更新飞行数据:PacedSender::InsertPacket(size_t bytes) 对应的是 PacingController::OnPa…

2023年12月 Python(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 下面代码的输出结果是?( ) dict1 = {1: 10, 2: 20, 3: 30} dict2 <

XML的写法

下面我将以如下代码来解释下XML的写法 <?xml version"1.0" encoding"UTF-8" ?> <Steam><steam id"1"><zhanghao>admin</zhanghao><mima>123</mima><num>120</num></steam><st…

学习数仓工具 dbt

DBT 是一个有趣的工具&#xff0c;它通过一种结构化的方式定义了数仓中各种表、视图的构建和填充方式。 dbt 面相的对象是数据开发团队&#xff0c;提供了如下几个最有价值的能力&#xff1a; 支持多种数据库通过 select 来定义数据&#xff0c;无需编写 DML构建数据时&#…

色彩搭配:打造视觉吸引力与用户体验的关键

title: 色彩搭配&#xff1a;打造视觉吸引力与用户体验的关键 date: 2024/2/22 12:01:11 updated: 2024/2/22 12:01:11 tags: 网站色彩搭配视觉吸引力品牌形象用户体验设计色彩心理学配色技巧色轮互补 在当今数字化时代&#xff0c;网站已经成为了人们获取信息、进行交流和进行…

嵌入式学习之Linux入门篇——使用VMware创建Unbuntu虚拟机

目录 主机硬件要求 VMware 安装 安装Unbuntu 18.04.6 LTS 新建虚拟机 进入Unbuntu安装环节 主机硬件要求 内存最少16G 硬盘最好分出一个单独的盘&#xff0c;而且最少预留200G&#xff0c;可以使用移动固态操作系统win7/10/11 VMware 安装 版本&#xff1a;VMware Works…

Jmeter内置变量 vars 和props的使用详解

JMeter是一个功能强大的负载测试工具&#xff0c;它提供了许多有用的内置变量来支持测试过程。其中最常用的变量是 vars 和 props。 vars 变量 vars 变量是线程本地变量&#xff0c;它们只能在同一线程组内的所有线程中使用&#xff08;线程组内不同线程之间变量不共享&#…

机器学习——正规方程

正规方程的基本介绍 之前我们使用梯度下降算法求代价函数J(θ)的最小值&#xff0c;而梯度下降算法是通过一步步不断地迭代来收敛到全局最小值&#xff0c;如下 而正规方程则是另一种求解J(θ)最小值的方法&#xff0c;并且正规方程不需要通过迭代&#xff0c;而是一次性得到θ…

体育网站的比分、赛事数据一般从哪里获取?

像一般的体育类门户网站&#xff0c;或者是APP产品&#xff0c;换句话说&#xff0c;不是专业做数据的公司&#xff0c;基本上都是购买付费的api接口&#xff0c;越是大公司越是依靠从大的服务商处购买的。比如说whoscored这样的网站&#xff0c;以及像曼城、利物浦这样的俱乐部…

跨境电商本土化运营:深度融合本地市场,提升用户体验与市场份额

随着全球经济的不断发展&#xff0c;跨境电商在国际贸易中扮演着越来越重要的角色。然而&#xff0c;单一地面对全球市场可能并不足以满足用户的多样化需求&#xff0c;因此&#xff0c;跨境电商需要与本地市场深度融合&#xff0c;实现本土化运营。本文Nox聚星将和大家探讨跨境…

软件兼容性测试要考虑什么?

1、向前兼容和向后兼容。向前兼容是指可以使用软件的未来版本&#xff0c;向后兼容是指可以使用软件的以前版本。并非所有的软件都要求向前兼容和向后兼容&#xff0c;这是软件设计者需要决定的产品特性。 2、不同版本之间的兼容。不同版本之间的兼容指要实现测试平台和应用软…

【elasticsearch实战】知识库文件系统检索工具FSCrawler

需求背景 最近有一个需求需要建设一个知识库文档检索系统&#xff0c;这些知识库物料附件的文档居多&#xff0c;有较多文档格式如&#xff1a;PDF, Open Office, MS Office等&#xff0c;需要将这些格式的文件转化成文本格式&#xff0c;写入elasticsearch 的全文检索索引&am…

解决app中以webview的方式嵌入h5网页,h5网页加载不出来

问题描述&#xff1a;我的h5网页在web端和手机浏览器都能正常渲染展示&#xff0c;但是嵌入到客户的webview中&#xff0c;渲染加载不出来&#xff0c;仔细检查代码之后并没有任何代码错误和后台报错。抓耳挠腮查找两天之后发现&#xff0c;原因为整个h5网页的最外层高度设置成…

六、回归与聚类算法 - 线性回归

目录 1、线性回归的原理 1.1 应用场景 1.2 什么是线性回归 1.2.1 定义 1.2.2 线性回归的特征与目标的关系分析 2、线性回归的损失和优化原理 2.1 损失函数 2.2 优化算法 2.2.1 正规方程 2.2.2 梯度下降 3、线性回归API 4、回归性能评估 5、波士顿房价预测 5.1 流…