【C++】list的模拟实现

list 的常见接口介绍

  1. 构造函数
函数名称 功能说明
list() 构造空的list
list(const list& x) 拷贝构造
list(InputIterator first, InputIterator last) 用迭代器区间构造list
list(int n, const T& val = T()) 用 n 个 val 元素构造list
  1. 遍历及访问操作
函数名称 功能说明
begin() 返回第一个元素的迭代器
end() 返回最后一个元素下一个位置的迭代器
rbegin() 返回 end() 位置的反向迭代器
rend() 返回 begin() 位置的反向迭代器
front() 获取 list 中第一个元素的引用
back() 获取 list 中最后一个元素的引用
  1. 容量操作
函数名称 功能说明
empty() 判断 list 是否为空
size() 返回 list 中有效节点的个数
  1. 修改操作
函数名称 功能说明
push_front(const T& val) 在 list 第一个元素之前插入 val 元素
push_back(const T& val) 在 list 最后一个元素之后插入 val 元素
pop_front() 删除 list 中的第一个节点
pop_back() 删除 list 中的最后一个节点
insert(iterator pos, const T& val) 在 pos 位置插入 val 元素
erase(iterator pos) 删除 pos 位置的节点
swap(list& lt) 两个 ilst 进行相互交换
clear() 清除 list 中的有效节点

list 的模拟实现

cpp 复制代码
#pragma once
#include <cassert>

namespace zs
{
	template<class T>
	class list_node
	{
	public:
		list_node(const T& val = T())
			: _data(val)
			, _next(nullptr)
			, _prev(nullptr)
		{}
	public:
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
	};
	
	// 反向迭代器
	template<class Iterator, class Ref, class Ptr>
	class __reverse_iterator
	{
	public:
		typedef __reverse_iterator<Iterator, Ref, Ptr> reverse_iterator;
	public:
		__reverse_iterator(Iterator it)
			:_cur(it)
		{}

		reverse_iterator& operator++()
		{
			--_cur;
			return *this;
		}

		reverse_iterator& operator--()
		{
			++_cur;
			return *this;
		}

		reverse_iterator operator++(int)
		{
			reverse_iterator tmp = *this;
			--_cur;
			return tmp;
		}

		reverse_iterator operator--(int)
		{
			reverse_iterator tmp = *this;
			++_cur;
			return tmp;
		}

		Ref operator*()
		{
			Iterator tmp = _cur;
			--tmp;
			return *tmp;
		}

		Ptr operator->()
		{
			return &(operator*());
		}

		bool operator!=(const reverse_iterator& it)
		{
			return _cur != it._cur;
		}

		bool operator==(const reverse_iterator& it)
		{
			return _cur == it._cur;
		}
	public:
		Iterator _cur;
	};
	
	// 正向迭代器
	template<class T, class Ref, class Ptr>
	class __list_iterator
	{
	private:
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> iterator;
	public:
		__list_iterator(Node* node)
			: _node(node)
		{}

		bool operator!=(const iterator& it) const
		{
			return _node != it._node;
		}

		bool operator==(const iterator& it) const
		{
			return _node == it._node;
		}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &(operator*());
		}

		iterator& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		iterator operator++(int)
		{
			iterator ret(*this);
			_node = _node->_next;
			return ret;
		}

		iterator& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		iterator operator--(int)
		{
			iterator ret(*this);
			_node = _node->_prev;
			return ret;
		}
	public:
		Node* _node;
	};

	template<class T>
	class list
	{
	private:
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;
		typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef __reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

	public:
		iterator begin()
		{
			return iterator(_head->_next);
		}

		iterator end()
		{
			return iterator(_head);
		}

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

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

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}
	public:
		list()
		{
			empty_init();
		}
		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_init();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		list(const list<T>& lt)
		{
			empty_init();
			list<T> tmpList = list(lt.begin(), lt.end());
			swap(tmpList);
		}
		list(int n, const T& val = T())
		{
			empty_init();
			int i = 0;
			while(i++ < n)
			{
				push_back(val);
			}
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}
		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		void swap(list<T>& lt)
		{
			::swap(_head, lt._head);
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		void push_front(const T& val)
		{
			insert(begin(), val);
		}
		void push_back(const T& val)
		{
			insert(end(), val);
		}
		void pop_front()
		{
			erase(begin());
		}
		void pop_back()
		{
			erase(-end());
		}
		iterator insert(iterator pos, const T& val)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;

			Node* newnode = new Node(val);

			prev->_next = newnode;
			newnode->_prev = prev;
			cur->_prev = newnode;
			newnode->_next = cur;

			return iterator(newnode);
		}
		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);
		}

		T& front()
		{
			return *(begin());
		}
		T& back()
		{
			return *(--end());
		}
		const T& front() const
		{
			return *(begin());
		}
		const T& back() const
		{
			return *(--end());
		}

		bool empty() const
		{
			return _head->_next == _head;
		}
		size_t size() const
		{
			size_t count = 0;
			list<T>::const_iterator it = begin();
			while (it != end())
			{
				++it;
				++count;
			}
			return count;
		}
	private:
		Node* _head;
	};
}

list 与 vector 的对比

vector 与 list 都是重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不尽相同,其主要不同如下:

vector list
底层结构 动态顺序表,一段连续空间 带头结点的双向循环链表
随机访问 支持随机访问 不支持随机访问,访问某个元素的效率是O(N)
插入和删除 任意位置插入删除效率低,时间复杂度是O(N);插入时可能还需要增容,导致效率更低 任意位置插入删除效率高,时间复杂度是O(1)
空间利用率 底层为连续空间,不容易造成内存碎片,缓存利用率高,空间利用率高 底层动态开辟小节点,缓存利用率低,空间利用率低
迭代器 原生态指针 对原生态指针进行封装
迭代器失效 插入元素时,可能导致扩容,使原来的迭代器失效;删除元素时,当前迭代器会失效 插入元素不会导致迭代器失效,删除元素会导致当前迭代器失效
使用场景 需要高效存储,支持随机访问,不关心插入删除效率 需要大量插入删除操作,不关心随机访问
相关推荐
feiyangqingyun22 分钟前
Qt/C++开发监控GB28181系统/录像文件查询/录像回放/倍速播放/录像文件下载
c++·qt·gb28181·录像回放·录像文件下载
2301_8076114935 分钟前
310. 最小高度树
c++·算法·leetcode·深度优先·回溯
四谷夕雨2 小时前
C++八股——智能指针
c++
Once_day2 小时前
C++之fmt库介绍和使用(1)
开发语言·c++·fmt
是店小二呀2 小时前
【优选算法 | 字符串】字符串模拟题精选:思维+实现解析
android·c++·算法
不爱学英文的码字机器2 小时前
[操作系统] 策略模式进行日志模块设计
c++·策略模式
凤年徐2 小时前
【C/C++】自定义类型:结构体
c语言·开发语言·c++·经验分享·笔记·算法
DARLING Zero two♡3 小时前
C++效率掌握之STL库:map && set底层剖析及迭代器万字详解
c++·stl·set·map
绯樱殇雪3 小时前
编程题 02-线性结构3 Reversing Linked List【PAT】
c++·pat考试
Rachelhi3 小时前
C++.神经网络与深度学习(赶工版)(会二次修改)
c++·深度学习·神经网络