【C++】STL中 list 的模拟实现

本文详细介绍了一个自定义List的实现过程,包括结点定义、迭代器实现及其基本功能、List的主要功能实现等内容。通过深入探讨,帮助读者理解List的底层原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、list成员定义

1.1 list 的结点定义

1.2 list的结构

1.3 实现的函数

二、list 的迭代器

2.1 push_back

2.2 iterator 的实现

2.3 iterator 的基本功能

2.3.1 operator !=

2.3.2 operator *

2.3.3 operator ++

2.3.4 operator ->

2.4 iteartor 的效果检验

2.5 const 迭代器

三、list 的功能实现

3.1 insert

3.2 erase

3.3 pop/push

3.4 拷贝构造函数

3.5 赋值运算符重载

3.6 析构函数


一、list成员定义

1.1 list 的结点定义

实现 list,首先我们要先自定义创建一个结点类型 ,定义如下:

1.2 list的结构

STL中的 list 结构为带头双向循环链表,所以当调用了 list 时,就默认创建了 _head 结点,并将_next、_prev指向自身。

1.3 实现的函数

以下来看看我们接下来要实现的函数接口。本篇要实现三个类,一个是 list 的结点类,一个 list 的迭代器类,最后是 list 类。

namespace Brant
{
	template<class T>
	struct list_node
	{
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
		list_node(const T& x = T());
	};

	template <class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr>  iterator;
		Node* _node;
		__list_iterator(Node* node)
			:_node(node)
		{}
		bool operator !=(const iterator& it);
		bool operator !=(const iterator& it) const;
		bool operator ==(const iterator& it);
		bool operator ==(const iterator& it) const;
		Ref operator* ();
		Ptr operator->() const;
		iterator& operator++();
		iterator operator++(int);
		iterator& operator--();
		iterator operator--(int);

	};

	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();
		iterator end();
		const_iterator begin() const;
		const_iterator end() const;
		void empty_init();
		list();
		template <class InputIterator>
		list(InputIterator first, InputIterator last);
	    list(const list<T>& lt);
	    list<T>& operator=(list<T> lt);
	    ~list();
	    void push_back(const T& x);
	    iterator insert(iterator pos, const T& x);
	    iterator erase(iterator pos);
	    void push_front(const T& x);
	    void pop_back();
	    void clear();
	private:
		Node* _head;
	};

}

二、list 的迭代器

list 的迭代器不同于 string、vector的迭代器,它的迭代器并不是原生指针,list的迭代器指向的是每个结点。所以,我们要单独实现 list 的迭代器——__list_iteartor(像指针一样的对象),才能在 list 中进行使用。

首先我们先来是实现 list 的push_back,然后使用 list 的迭代器将其数据全部输出。

2.1 push_back

思路:

  1. 尾插的是在 _head->prev 处进行插入,保存 _head->prev 为 tail 。
  2. 创建 (new) 一个 newnode 。(注意,Node 类型向初始化要调用构造函数)
  3. 链表的链接

好的,接下来实现一个 test 函数来检验成果。

2.2 iterator 的实现

在上面实现了 push_back 后,我们只能在监视里观察插入的数据。因为我们无法像 string、vector 直接使用指针进行访问,因为 list 不是连续的物理空间。所以,我们要自己实现 list 的专用指针,才能在控制台输出数据。

 接下来,我们就开始编写我们自己的 iterator 类

如上,我们便实现了属于 list 的迭代器,本质是在 list 类中调用 __list_iteartor。

所以,如果我们创建一个 list 的迭代器。就可以在 list 类中构造一个__list_iteartor的迭代器。

接下来,我们使用实现一个成员函数,具体功能如下:

在 list 中将结点传入__list_iteartor,构造出一个 list 的迭代器。最常用的便是 begin()、end()。

注意上面使用的是匿名对象,一样是在用结点构造一个迭代器。

2.3 iterator 的基本功能

定义了 list 迭代器,我们接下来就是要实现其作为迭代器的基本功能。让其能便捷的操作每个结点。

2.3.1 operator !=

 这里为了便捷书写、提高代码可读性,我们在__list_iteartor 中再 typedef 一下。

便可以简便、清晰地书写

2.3.2 operator *

如果我们想访问、修改一个迭代器所指向的结点中的数据,所以我们要再提供(*)操作符重载.

2.3.3 operator ++

 这个功能就更重要,++iterator就可以让迭代器指向下一个结点,并返回++迭代器后的值(*this)。

2.3.4 operator ->

重载出这个运算符重载,可以更方便我们访问迭代器的成员变量。

使用场景:

当我们list中存放的内置类型,此时我们直接 *iterator 就可以很好的拿到数据,可是如果我们list 中存放的 自定义类型的数据,此时我们呢 *iterator 取到的是 data ,而data又是一个内置类型,我们要再次解引用 (*data) ,使用起来就十分别扭。

这时,我们就可以重载出 -> 运算符重载,使用起来非常方便。

我们来看看是如何实现这个运算符的。

 其中 this 调用了 operator*()函数

 其中C++对这里的书写进行了简化,直接省略了一个 ->,为了可读性而进行了特殊处理。

2.4 iteartor 的效果检验

实现了上面的基本功能,就可以使用迭代器循环打印出一串链表了

我们范围 for 同样也可以使用,在编译中范围 for的编译就是直接替换为迭代器,如果迭代器是正确的,那范围 for 就可以运行。

2.5 const 迭代器

以上我们我们实现的都是非 const 型的迭代器,如果现在我们的 list 是 const 型,所以迭代器也应该为 const 型。如下图,将对象进行引用传参,则需配套使用 const 进行传参。如果使用 const 型 list 便无法使用一系列函数。

如果想解决上面的问题,我们需要提供一套 const 作返回值的成员函数(只读)。

不难发现,其实就是返回值加上了 const 。但是 返回值不同不能构成函数重载,我们不可能因为要实现 const 作返回值的迭代器,而再去实现一个const__list_iteartor。这便是这个地方的难点。

接下来我们来看一下STL源码中是如何解决这样的问题的

如果 list 是 const 成员, 则会调用 const 型的 begin() 函数,然后 const begin() 函数会构造一个const_iterator,并且模板中的Ref、Ptr就是 const 型的。

 此时,迭代器内部无需关心到底是 const 型还是非 const 型,全凭外部传来的值决定。

这样,一些需要 const 型也需要普通类型做返回值得地方,我们就可以用此模板参数作返回值。

如果模板参数传来是const型的,就是以 const 类型的作返回值。

 在 list 类中,我们便要对这 const_iterator 和 iterator做区别


三、list 的功能实现

基于之前学过数据结构,list 这些接口的实现其实非常相似,这里不做过多讲解。

3.1 insert

insert就是在pos位置的前面进行插入,尾插相当于在end()位置进行 insert 。

3.2 erase

3.3 pop/push

实现了 insert 和 erase ,那push_back、push_front、pop_back、pop_front都可以复用实现。

3.4 拷贝构造函数

如果我们不提供拷贝构造函数,那 list 中的拷贝构造就是值(浅)拷贝,如下图:

为了实现 list 的深拷贝,所以我们要实现 list 的拷贝构造。

我们在 string、vector中都实现了传统写法、现代写法,在 list 中我们直接书写现代写法。

  1. 创建以迭代器区间为参数的带参默认构造函数
  2. 使用该构造函数根据 lt 构造一个 temp 的临时变量
  3. 创建一个头节点
  4. 直接交换哨兵位的头结点

3.5 赋值运算符重载

同样采用现代写法,使用传值传参调用了拷贝构造创建了临时变量,再使用swap函数进行交换。

3.6 析构函数

实现 list 的析构函数主要分为两步:1.释放除_head 外所有的结点 2.释放头节点,并置空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Brant_zero2022

素材免费分享不求打赏,只求关注

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值