list模拟实现

目录

前言

具体实现

节点

迭代器

list迭代器的基本内容

成员变量和typedef

构造函数

[对 ++ 和 -- 运算符的重写](#对 ++ 和 -- 运算符的重写)

[对 运算符* 和 运算符->的重写](#对 运算符* 和 运算符->的重写)

[对运算符== 和 运算符!=的重写](#对运算符== 和 运算符!=的重写)

迭代器完整代码

List的具体实现

基本成员和typedef

构造函数

[front 和 back](#front 和 back)

insert和erase

push_back和push_front

pop_back和push_back

empty和size

begin和end

clear和swap

析构函数

总结


前言

list底层是一个带头双向循环链表。list的重点是对其节点的封装**(即迭代器的封装)**。希望可以通过对list的模拟实现使各位更理解封装的意义。

具体实现

节点

节点内容很常规,一个_val存储数据,一个prev指针指向节点的前一个数据,一个next指针指向节点的后一个数据。(画图较丑,大致就是这样的图)

节点代码

cpp 复制代码
	template<class T>
	struct ListNode
	{
		T _val = T();
		ListNode<T>* prev = nullptr;
		ListNode<T>* next = nullptr;

		ListNode(const T& x)
			: _val(x)
			, prev(nullptr)
			, next(nullptr)
		{}
	};

迭代器

list迭代器的基本内容

list的迭代器实质上是对 节点 即 Node 的封装,使得迭代器能实现 ++ 和 -- 等一系列迭代器所需的基本运算操作**(因为list的存储空间不连续,所以Node无法直接进行迭代器所需的基本运算,因此对其进行封装)**。 值得一提的是list的迭代器不是随机迭代器,不支持 + 和 - ,其主要原因是因为 + 和 - 的操作太过消耗性能了。

成员变量和typedef

由于是对 节点Node的封装,因此成员变量只有 _node。

cpp 复制代码
		typedef ListIterator<T, Ref, Ptr> Self;
		typedef ListNode<T> Node;
	public:
		Node* _node = nullptr;
构造函数
cpp 复制代码
		ListIterator() = default;
		ListIterator(Node* x)
		{
			_node = x;
		}
对 ++ 和 -- 运算符的重写

Self operator++(int) 是对后置++的重写, Self& operator++() 是对前置++的重写。

cpp 复制代码
Self& operator++()
{
	_node = _node->next;
	return *this;
}
Self operator++(int)
{
	Self ret(_node);
	_node = _node->next;
	return ret;
}
Self& operator--()
{
	_node = _node->prev;
	return *this;
}
Self operator--(int)
{
	Self ret(_node);
	_node = _node->prev;
	return ret;
}
对 运算符* 和 运算符->的重写
cpp 复制代码
Ref operator*()
{
	return _node->_val;
}
Ptr operator->()
{
	return &*this->_node;
}
对运算符== 和 运算符!=的重写
cpp 复制代码
		bool operator==(const Self& x)
		{
			return _node == x._node;
		}
		bool operator!=(const Self& x)
		{
			return _node != x._node;
		}
迭代器完整代码
cpp 复制代码
	template<class T , class Ref , class Ptr>
	struct ListIterator
	{
		typedef ListIterator<T, Ref, Ptr> Self;
		typedef ListNode<T> Node;
	public:
		Node* _node = nullptr;
	public:
		ListIterator() = default;
		ListIterator(Node* x)
		{
			_node = x;
		}

		Self& operator++()
		{
			_node = _node->next;
			return *this;
		}
		Self operator++(int)
		{
			Self ret(_node);
			_node = _node->next;
			return ret;
		}
		Self& operator--()
		{
			_node = _node->prev;
			return *this;
		}
		Self operator--(int)
		{
			Self ret(_node);
			_node = _node->prev;
			return ret;
		}

		Ref operator*()
		{
			return _node->_val;
		}
		Ptr operator->()
		{
			return &*this->_node;
		}


		bool operator==(const Self& x)
		{
			return _node == x._node;
		}
		bool operator!=(const Self& x)
		{
			return _node != x._node;
		}

	};

List的具体实现

基本成员和typedef
cpp 复制代码
		typedef ListNode<T> Node;
	public:
		typedef ListIterator<T, T&, T*> iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;
	private:
		Node* _head = nullptr;
构造函数
cpp 复制代码
list()
{
	_head = new Node(T());
	_head->next = _head->prev = _head;
}

list(int n , const T& x = T())
{
	_head = new Node(T());
	_head->next = _head->prev = _head;
	while (n--) push_back(x);
}

template<class InputIterator>
list(InputIterator l, InputIterator r)
{
	_head = new Node(T());
	_head->next = _head->prev = _head;
	while (l != r)
	{
		push_back(*l);
		l++;
	}
}

list(initializer_list<T> il)
{
	_head = new Node(T());
	_head->next = _head->prev = _head;
	for (const auto& x : il)
	{
		push_back(x);
	}
}
front 和 back
cpp 复制代码
T& front()
{
	return _head->next->_val;
}
T& back()
{
	return _head->prev->_val;
}
insert和erase

erase返回删除节点的后一个节点,避免迭代器失效问题。 insert此处也返回迭代器是为了工整,实际上list的insert不会导致迭代器失效

cpp 复制代码
iterator insert(iterator pos, const T& x)
{
	Node* dest = new Node(x);
	dest->prev = pos._node->prev;
	dest->next = pos._node;
	pos._node->prev->next = dest;
	pos._node->prev = dest;
	return dest;
}
iterator erase(iterator pos)
{
	Node* dest = pos._node->next;
	dest->prev = pos._node->prev;
	pos._node->prev->next = dest;
	delete pos._node;
	return dest;
}
push_back和push_front

除下面写法外,也可以考虑对insert进行复用

cpp 复制代码
		void push_back(const T& x)
		{
			Node* dest = new Node(x);
			dest->prev = _head->prev;
			dest->next = _head;
			_head->prev->next = dest;
			_head->prev = dest;
		}
		void push_front(const T& x)
		{
			Node* dest = new Node(x);
			dest->prev = _head;
			dest->next = _head->next;
			_head->next->prev = dest;
			_head->next = dest;
		}
pop_back和push_back

除下面写法外,也可以考虑对erase的复用

cpp 复制代码
		void pop_front()
		{
			if (!empty())
			{
				Node* dest = _head->next;
				dest->next->prev = _head;
				_head->next = dest->next;
				delete dest;
			}
		}
		void pop_back()
		{
			if (!empty())
			{
				Node* dest = _head->prev;
				_head->prev = dest->prev;
				dest->prev->next = _head;
				delete dest;
			}
		}
empty和size
cpp 复制代码
		bool empty() 
		{
			return _head->next == _head->prev;
		}
		size_t size() const
		{
			size_t n = 0;
			iterator b = _head->next;
			iterator e = _head;
			while (b != e)
			{
				n++;
				++b;
			}
			return n;
		}
begin和end
cpp 复制代码
		const_iterator begin() const
		{
			return const_iterator(_head->next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}
		iterator begin() 
		{
			return _head->next;
		}
		iterator end()
		{
			return _head;
		}
clear和swap
cpp 复制代码
void clear()
{
	iterator b = _head->next;
	iterator e = _head;
	while (b != e)
	{
		b = erase(b);
	}
}

void swap(list<T>& l)
{
	Node* m = l._head;
	l._head = _head;
	_head = m;
}
析构函数
cpp 复制代码
		~list()
		{
			iterator b = _head->next, e = _head;
			while (b != e)
			{
				b = erase(b);
			}
			delete _head;
		}

总结

难点在于对迭代器的封装,同时不要忽略list类中erase迭代器通过返回值来防止因删除节点而导致的迭代器失效问题

相关推荐
XiaoLeisj25 分钟前
【递归,搜索与回溯算法 & 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)
数据结构·算法·leetcode·决策树·深度优先·剪枝
Jackey_Song_Odd1 小时前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
乐之者v2 小时前
leetCode43.字符串相乘
java·数据结构·算法
A懿轩A3 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
️南城丶北离4 小时前
[数据结构]图——C++描述
数据结构··最小生成树·最短路径·aov网络·aoe网络
✿ ༺ ོIT技术༻4 小时前
C++11:新特性&右值引用&移动语义
linux·数据结构·c++
菜鸡中的奋斗鸡→挣扎鸡11 小时前
滑动窗口 + 算法复习
数据结构·算法
axxy200012 小时前
leetcode之hot100---240搜索二维矩阵II(C++)
数据结构·算法
Uu_05kkq13 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
1nullptr15 小时前
三次翻转实现数组元素的旋转
数据结构