【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)
空间利用率 底层为连续空间,不容易造成内存碎片,缓存利用率高,空间利用率高 底层动态开辟小节点,缓存利用率低,空间利用率低
迭代器 原生态指针 对原生态指针进行封装
迭代器失效 插入元素时,可能导致扩容,使原来的迭代器失效;删除元素时,当前迭代器会失效 插入元素不会导致迭代器失效,删除元素会导致当前迭代器失效
使用场景 需要高效存储,支持随机访问,不关心插入删除效率 需要大量插入删除操作,不关心随机访问
相关推荐
天若有情67316 分钟前
【c++】手撸C++ Promise:从零实现通用异步回调组件,支持链式调用+异常安全
开发语言·前端·javascript·c++·promise
学困昇27 分钟前
C++中的异常
android·java·c++
合作小小程序员小小店1 小时前
桌面安全开发,桌面二进制%恶意行为拦截查杀%系统安全开发3.0,基于c/c++语言,mfc,win32,ring3,dll,hook,inject,无数据库
c语言·开发语言·c++·安全·系统安全
Codeking__1 小时前
C++ 11 atomic 原子性操作
开发语言·c++
crescent_悦1 小时前
PTA L1-020 帅到没朋友 C++
数据结构·c++·算法
卡提西亚2 小时前
C++笔记-34-map/multimap容器
开发语言·c++·笔记
2***B4492 小时前
C++在金融中的QuantLibXL
开发语言·c++·金融
A***07172 小时前
C++在游戏中的阴影渲染
开发语言·c++·游戏
Q***l6873 小时前
C++在计算机图形学中的渲染
开发语言·c++
oioihoii4 小时前
C++语言演进之路:从“C with Classes”到现代编程基石
java·c语言·c++