STL——list模拟实现

一、模拟实现源码

cpp 复制代码
#pragma once

namespace sjx
{
	template <typename T>
	struct __list_node
	{
		__list_node<T>* _next;
		__list_node<T>* _prev;
		T _data;

		__list_node(const T& val = T()) :_data(val), _next(nullptr), _prev(nullptr)
		{

		}
	};

	template <typename T, typename Ref, typename Ptr>
	struct __list_iterator
	{
		typedef __list_node<T> node;
		typedef __list_node<T>* node_pointer;

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

		node_pointer _pnode;

		__list_iterator(const node_pointer& val = nullptr) :_pnode(val) {}
		__list_iterator(const iterator& it) :_pnode(it._pnode) {}

		Ref operator*()
		{
			return _pnode->_data;
		}
		Ptr operator->()
		{
			return &(_pnode->_data);
		}
		bool operator!=(const self& val) const
		{
			return _pnode != val._pnode;
		}
		bool operator==(const self& val) const
		{
			return _pnode == val._pnode;
		}

		self& operator++()
		{
			_pnode = _pnode->_next;
			return *this;
		}
		self operator++(int)
		{
			self tmp(_pnode);
			_pnode = _pnode->_next;
			return tmp;
		}
		self& operator--()
		{
			_pnode = _pnode->_prev;
			return *this;
		}
		self operator--(int)
		{
			self tmp(_pnode);
			_pnode = _pnode->_prev;
			return tmp;
		}
	};

	template <typename T>
	class list
	{
	public:
		typedef __list_node<T> node;
		typedef __list_node<T>* node_pointer;

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

		list()
		{
			empty_initialize();
		}
		template <typename InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_initialize();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		list(const list& other)
		{
			empty_initialize();
			list<T> tmp(other.begin(), other.end());
			swap(tmp);
		}

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

		list<T>& operator=(list<T> other)
		{
			empty_initialize();
			swap(other);
			return *this;
		}


		// Element access
		T& front()
		{
			assert(!empty());
			return _head->_next->_data;
		}
		const T& front() const
		{
			assert(!empty());
			return _head->_next->_data;
		}

		T& back()
		{
			assert(!empty());
			return _head->_prev->_data;
		}
		const T& back() const
		{
			assert(!empty());
			return _head->_prev->_data;
		}


		// Iterators
		iterator begin()
		{
			return _head->_next;
		}
		const_iterator begin() const
		{
			return _head->_next;
		}
		iterator end()
		{
			return _head;
		}
		const_iterator end() const
		{
			return _head;
		}

		
		// Capacity
		bool empty() const
		{
			return _head->_next == _head;
		}
		
		size_t size() const
		{
			size_t i = 0;
			node_pointer cur = _head->_next;
			while (cur != _head)
			{
				++i;
				cur = cur->_next;
			}
			return i;
		}


		// Modifiers
		void clear()
		{
			node_pointer cur = _head->_next;
			while (cur != _head)
			{
				node_pointer tmp = cur->_next;
				delete cur;
				cur = tmp;
			}
			_head->_next = _head;
			_head->_prev = _head;
		}

		iterator insert(const_iterator pos, const T& val)
		{
			node_pointer cur = new node(val);
			node_pointer tail = pos._pnode;
			node_pointer head = tail->_prev;

			head->_next = cur;
			cur->_next = tail;

			tail->_prev = cur;
			cur->_prev = head;

			return cur;
		}
		iterator insert(const_iterator pos, size_t count, const T& val)
		{
			for (size_t i = 0; i < count; ++i)
			{
				pos = insert(pos, val);
			}
			return pos._pnode;
		}
		template <typename InputIterator>
		iterator insert(const_iterator pos, InputIterator first, InputIterator last)
		{
			node_pointer head = pos._pnode;
			if (first != last)
			{
				head = insert(pos, *first)._pnode;
				++first;
			}
			while (first != last)
			{
				insert(pos, *first);
				++first;
			}
			return head;
		}

		iterator erase(const_iterator pos)
		{
			node_pointer tmp = pos._pnode;
			if (pos != end())
			{
				node_pointer del = tmp;
				tmp = tmp->_next;
				del->_prev->_next = del->_next;
				del->_next->_prev = del->_prev;
				delete del;
			}
			return tmp;
		}
		iterator erase(const_iterator first, const_iterator last)
		{
			while (first != last)
			{
				first = erase(first);
			}
			return last._pnode;
		}

		void push_back(const T& val)
		{
			node_pointer tmp = new node(val);
			node_pointer tail = _head->_prev;
			
			tail->_next = tmp;
			tmp->_next = _head;

			_head->_prev = tmp;
			tmp->_prev = tail;
		}

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

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

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

		void swap(list<T>& val)
		{
			std::swap(_head, val._head);
		}
	
	protected:
		void empty_initialize()
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}

	private:
		node_pointer _head;
	};
}

二、重难点------迭代器实现

list的迭代器不同于vector,vector的迭代器用指针就可以实现大部分功能,但是list的迭代器要实现++,不再是单纯数值上的加减,而是要让迭代器指向当前结点的next。

因此,需要将list的迭代器封装成一个类__list_iterator。通过运算符重载,来改变迭代器运算的效果。

需要注意的是__list_iterator还有另外两个模板参数,Ref和Ptr。

对于const_iterator,它与普通的iterator的区别就是它里面的内容不允许被修改,但是本身依旧可以进行++或者--等操作,其区别之一就在于对迭代器的解引用,一个的返回值可以被修改,一个不可以,因此我们引入了一个模板参数Ref,对于普通的迭代器,它被设置为T&,而对于const迭代器,它被设置为const T&。

对于模板参数Ptr,需要应对以下情况:

cpp 复制代码
#include <iostream>
#include <assert.h>
#include "my_list.h"
struct Data
{
	int _year;
	int _month;
	int _day;

	Data(int year = 2000, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{

	}
};

int main()
{
	// 如果存储的对象是自定义类型,且要访问其中的数据
	sjx::list<Data> l1;
	l1.push_back(Data());

	sjx::list<Data>::iterator it = l1.begin();

	// 使用 * 访问
	std::cout << (*it)._year << " " << (*it)._month << " " << (*it)._day << std::endl;
	// 使用 operator->
	std::cout << it.operator->()->_year << " " << it.operator->()->_month << " " << it.operator->()->_day << std::endl;
	// 为了可读性,一般我们省略了一个 ->
	std::cout << it->_year << " " << it->_month << " " << it->_day << std::endl;

	return 0;
}

以上三种输出方式实际上是等价的。

相关推荐
桃园码工2 分钟前
21_HTML5 WebSocket --[HTML5 API 学习之旅]
websocket·学习·html5
一代...18 分钟前
【C++】string的模拟实现
开发语言·c++
c++初学者ABC33 分钟前
【基础】卒的遍历(DFS)
c++·算法
Rinai_R34 分钟前
计算机组成原理的学习笔记(10)-- CPU·其二 组合逻辑控制器和微程序
笔记·学习
A懿轩A2 小时前
C/C++ 数据结构与算法【树和森林】 树和森林 详细解析【日常学习,考研必备】带图+详细代码
c语言·c++·考研·数据结构与算法·树和森林
Bucai_不才3 小时前
【C++】初识C++之C语言加入光荣的进化(下)
c语言·c++·面向对象编程
小Mie不吃饭3 小时前
Linux | Ubuntu零基础安装学习cURL文件传输工具
学习
A懿轩A3 小时前
C/C++ 数据结构与算法【哈夫曼树】 哈夫曼树详细解析【日常学习,考研必备】带图+详细代码
c语言·c++·学习·算法·哈夫曼树·王卓
新中地GIS开发老师3 小时前
25考研希望渺茫,工作 VS 二战,怎么选?
javascript·学习·考研·arcgis·地理信息科学·地信
w_outlier3 小时前
cookie__HTTPS
c++·网络协议·http·https