C++ list【常用接口、模拟实现等】

1. list的介绍及使用

1.1 list的介绍

1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

2.list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

3.list与forward_list非常相似,最主要的不同在于forward_list是单链表,只能朝前迭代,让其更简单高效。

4.与其他的序列式容器相比(array,_vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

5.与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第六个元素,必须从已知的位置(比如头部或尾部)迭代到该位置,在这段位置上迭代器需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息。

1.2 list的使用

1.2.1 list的构造

|-----------------------------------------------------------|----------------------------|
| #### 析构函数(constructor) | #### 接口说明 |
| list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的元素 |
| list() | 构造空的list |
| list (const list& x) | 拷贝构造函数 |
| list (InputIterator first, InputIterator last) | 用[first, last)区间中的元素构造list |

(若为手机阅读,表格可左右移动)

1.2.2 list iterato的使用

此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。

|-------------|-------------------------------------------------------------------------|
| #### 函数声明 | #### 接口说明 |
| begin+end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
| rbegin+rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的reverse_iterator,即beign位置 |

(若为手机阅读,表格可左右移动)

【注意】

  1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

  2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

1.2.3 list capacity

|-----------|------------------------------|
| #### 函数声明 | #### 接口说明 |
| empty | 检测list是否为空,是返回true,否则返回false |
| size | 返回list中有效节点的个数 |

(若为手机阅读,表格可左右移动)

1.2.4 list element access

|-----------|--------------------|
| #### 函数声明 | #### 接口说明 |
| front | 返回list的第一个节点中值的引用 |
| back | 返回list的最后一个节点中值的引用 |

(若为手机阅读,表格可左右移动)

1.2.5 list modifiers

|------------|-----------------------------|
| #### 函数声明 | #### 接口说明 |
| push_front | 在list首元素前插入值为val的元素 |
| pop_front | 删除list中的第一个元素 |
| push_back | 在list尾部插入值为val的元素 |
| pop_back | 删除list中最后一个元素 |
| insert | 在list position位置中插入值为val的元素 |
| erase | 删除list position位置的元素 |
| swap | 交换两个list中的元素 |
| clear | 清空list中的有效元素 |

(若为手机阅读,表格可左右移动)

1.2.6 list的迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的 ,只有在删除时才会失效 ,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

错误:

改正:

2. list的模拟实现

实现节点类

cpp 复制代码
template<class T>
struct ListNode
{
	ListNode<T>* _next;
	ListNode<T>* _prev;
	T _data;


	ListNode(const T& data = T())
		:_next(nullptr)
		, _prev(nullptr)
		, _data(data)
	{


	}
};

实现正向迭代器

迭代器不用实现析构函数和深拷贝。因为迭代器本身就是为了访问链表的节点,节点属于链表,不属于迭代器,如果需要析构和深拷贝,应该在控制链表的类中实现。

cpp 复制代码
	template<class T, class Ref, class Ptr>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> self;
		Node* _node;


		ListIterator(Node* node)
			:_node(node)
		{


		}


		self& operator++()
		{
			_node = _node->_next;


			return *this;
		}


		self operator++(int)
		{
			self tmp(*this);
			_node = _node->_next;


			return tmp;
		}


		self& operator--()
		{
			_node = _node->_prev;


			return *this;
		}


		self operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;


			return tmp;
		}


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


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


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


		Ptr operator->()
		{
			return &_node->_data;
		}
	};

实现反向迭代器

cpp 复制代码
template<class T, class Ref, class Ptr>
struct RListIterator
{
	typedef ListNode<T> Node;
	typedef RListIterator<T, Ref, Ptr> self;
	Node* _node;


	RListIterator(Node* node)
		:_node(node)
	{


	}


	self& operator++()
	{

		_node = _node->_prev;


		return *this;
	}


	self operator++(int)
	{
		self tmp(*this);
		_node = _node->_prev;


		return tmp;
	}


	self& operator--()
	{
		_node = _node->_next;


		return *this;
	}


	self operator--(int)
	{

		self tmp(*this);
		_node = _node->_next;


		return tmp;
	}


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


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


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


	Ptr operator->()
	{
		return &_node->_data;
	}
};

实现控制list的类

cpp 复制代码
template<class T>
class list
{
	typedef ListNode<T> Node;


public:
	typedef ListIterator<T, T&, T*> iterator;
	typedef RListIterator<T, T&, T*> reverse_iterator;
	typedef ListIterator<T, const T&, const T*> const_iterator;


	void empty_init()
	{
		_head = new Node();
		_head->_next = _head;
		_head->_prev = _head;
	}




	list()
	{
		empty_init();
	}



	list(const list<T>& it)
	{
		empty_init();
		for (const auto& e : it) 
		//在范围for上加上引用,如果it内的元素体积很大的话可以减小代价,引用并不会导致浅拷贝
		//eg:int a=1;int& a1=a;int b=a1;变量b只是和a的值一样并没有指向同一块空间(int b=a;)
		{
			push_back(e);
		}
	}


	list(initializer_list<T> il)
	{
		empty_init();
		for (const auto& e : il)
		{
			push_back(e);
		}
	}


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


	void clear()
	{
		auto it = begin();
		while (it != end())
		{
			it = erase(it);
		}
	}


	list<T>& operator=(list<T> it)
	{
		std::swap(_head, it._head);


		return *this;
	}


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


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


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


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

	reverse_iterator rbegin()
	{
		return reverse_iterator(_head->_prev);
	}

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

	void push_back(const T& x)
	{
		//Node* newnode = new Node(x);
		//Node* tail = _head->_prev;


		//tail->_next = newnode;
		//newnode->_prev = tail;
		//newnode->_next = _head;
		//_head->_prev = newnode;
		insert(end(), x);


	}


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


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


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


	iterator insert(iterator pos, const T& x)
	{
		Node* cur = pos._node;
		Node* newnode = new Node(x);
		Node* prev = cur->_prev;


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


		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);
	}


private:
	Node* _head;
};

完整list.h

cpp 复制代码
#pragma once
#include <assert.h>
namespace wmm
{
	template<class T>
	struct ListNode
	{
		ListNode<T>* _next;
		ListNode<T>* _prev;
		T _data;


		ListNode(const T& data = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _data(data)
		{


		}
	};

	template<class T, class Ref, class Ptr>
	struct RListIterator
	{
		typedef ListNode<T> Node;
		typedef RListIterator<T, Ref, Ptr> self;
		Node* _node;


		RListIterator(Node* node)
			:_node(node)
		{


		}


		self& operator++()
		{

			_node = _node->_prev;


			return *this;
		}


		self operator++(int)
		{
			self tmp(*this);
			_node = _node->_prev;


			return tmp;
		}


		self& operator--()
		{
			_node = _node->_next;


			return *this;
		}


		self operator--(int)
		{

			self tmp(*this);
			_node = _node->_next;


			return tmp;
		}


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


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


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


		Ptr operator->()
		{
			return &_node->_data;
		}
	};

	template<class T, class Ref, class Ptr>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> self;
		Node* _node;


		ListIterator(Node* node)
			:_node(node)
		{


		}


		self& operator++()
		{
			_node = _node->_next;


			return *this;
		}


		self operator++(int)
		{
			self tmp(*this);
			_node = _node->_next;


			return tmp;
		}


		self& operator--()
		{
			_node = _node->_prev;


			return *this;
		}


		self operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;


			return tmp;
		}


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


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


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


		Ptr operator->()
		{
			return &_node->_data;
		}
	};


	template<class T>
	class list
	{
		typedef ListNode<T> Node;


	public:
		typedef ListIterator<T, T&, T*> iterator;
		typedef RListIterator<T, T&, T*> reverse_iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;


		void empty_init()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}




		list()
		{
			empty_init();
		}



		list(const list<T>& it)
		{
			empty_init();
			for (const auto& e : it) 
			//在范围for上加上引用,如果it内的元素体积很大的话可以减小代价,引用并不会导致浅拷贝
			//eg:int a=1;int& a1=a;int b=a1;变量b只是和a的值一样并没有指向同一块空间(int b=a;)
			{
				push_back(e);
			}
		}


		list(initializer_list<T> il)
		{
			empty_init();
			for (const auto& e : il)
			{
				push_back(e);
			}
		}


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


		void clear()
		{
			auto it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}


		list<T>& operator=(list<T> it)
		{
			std::swap(_head, it._head);


			return *this;
		}


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


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


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


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

		reverse_iterator rbegin()
		{
			return reverse_iterator(_head->_prev);
		}

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

		void push_back(const T& x)
		{
			//Node* newnode = new Node(x);
			//Node* tail = _head->_prev;


			//tail->_next = newnode;
			//newnode->_prev = tail;
			//newnode->_next = _head;
			//_head->_prev = newnode;
			insert(end(), x);


		}


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


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


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


		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* newnode = new Node(x);
			Node* prev = cur->_prev;


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


			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);
		}


	private:
		Node* _head;
	};


	//遍历测试
	void test()
	{
		list<int> l;
		l.push_back(1);
		l.push_back(2);
		l.push_back(3);
		l.push_back(4);


		list<int>::iterator it = l.begin();
		while (it != l.end())
		{
			cout << *it << endl;
			++it;
		}
	}


	//结构体数据,重载符号->测试
	struct pos
	{
		int _x;
		int _y;


		pos(int x = 0, int y = 0)
			:_x(x)
			, _y(y)
		{


		}
	};


	void test2()
	{
		list<pos> l;
		struct pos* a = (struct pos*)malloc(sizeof(struct pos));
		a->_x = 200;
		a->_y = 200;


		struct pos b;
		b._x = 300;
		b._y = 300;


		l.push_back(pos(100, 100));
		l.push_back(*a);
		l.push_back(b);


		list<pos>::iterator it = l.begin();
		while (it != l.end())
		{
			cout << (*it)._x << endl;
			cout << (*it)._y << endl;


			cout << it._node->_data._x << endl;
			cout << it._node->_data._y << endl;


			cout << it->_x << endl;
			cout << it->_y << endl;
			//想让迭代器it像结构体指针一样访问数据,重载了一个->符号


			++it;
		}
	}


	//erase insert 测试
	void test3()
	{
		list<int> l;
		l.push_back(1);
		l.push_back(2);
		l.push_back(3);
		l.push_back(4);


		list<int>::iterator it = l.begin();
		it=l.erase(it);//注意迭代器失效问题
		for (auto e : l)
		{
			cout << e << endl;
		}
		cout << endl;


		//it=l.begin();


		l.insert(it, 1);
		for (auto& e : l)
		{
			cout << e << endl;
			e = 3;
		}

	}


	//拷贝构造测试
	void test4()
	{
		list<int> l;
		l.push_back(1);
		l.push_back(2);
		l.push_back(3);
		l.push_back(4);


		for (auto e : l)
		{
			cout << e << endl;
		}
		cout << endl;


		list<int> l1(l);
		for (auto e : l1)
		{
			cout << e << endl;
		}
		cout << endl;


		list<int>::iterator it = l1.begin();
		*it = 0;


		for (auto e : l)
		{
			cout << e << endl;
		}
		cout << endl;


		for (auto e : l1)
		{
			cout << e << endl;
		}
		cout << endl;
	}


	//operator=测试
	void test5()
	{
		list<int> l({ 1,2,3,4,5 });
		list<int> l1 = { 1,2,3,4,6 };


		l1 = l;


		for (const auto& e : l)
		{
			cout << e << endl;
		}
		cout << endl;


		for (const auto& e : l1)
		{
			cout << e << endl;
		}
		cout << endl;


		list<int>::iterator it = l1.begin();
		*it = 0;


		for (const auto& e : l)
		{
			cout << e << endl;
		}
		cout << endl;


		for (const auto& e : l1)
		{
			cout << e << endl;
		}
		cout << endl;
	}

    //反向迭代器测试
	void test6()
	{
		list<int> l({ 1,2,3,4,5 });
		list<int>::iterator it = l.begin();
		while (it != l.end())
		{
			cout << *it << endl;
			++it;
		}

		list<int> l2({ 1,2,3,4,5 });
		list<int>::reverse_iterator it1 = l2.rbegin();
		while (it1 != l2.rend())
		{
			cout << *it1 << endl;
			++it1;
		}
	}
}

3. list与vector的对比

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

下次再见~~很高兴帮助到你~~

如果有问题欢迎指正批评~~

相关推荐
Antonio915几秒前
【CMake】使用CMake在Visual Studio内构建多文件夹工程
开发语言·c++·visual studio
LyaJpunov14 分钟前
C++中move和forword的区别
开发语言·c++
程序猿练习生19 分钟前
C++速通LeetCode中等第9题-合并区间
开发语言·c++·leetcode
z千鑫27 分钟前
【人工智能】如何利用AI轻松将java,c++等代码转换为Python语言?程序员必读
java·c++·人工智能·gpt·agent·ai编程·ai工具
一名路过的小码农29 分钟前
C/C++动态库函数导出 windows
c语言·开发语言·c++
m0_6312704031 分钟前
标准c语言(一)
c语言·开发语言·算法
万河归海42831 分钟前
C语言——二分法搜索数组中特定元素并返回下标
c语言·开发语言·数据结构·经验分享·笔记·算法·visualstudio
Messiah___37 分钟前
【论文阅读】Slim Fly: A Cost Effective Low-Diameter Network Topology 一种经济高效的小直径网络拓扑
开发语言·php
农民小飞侠1 小时前
python AutoGen接入开源模型xLAM-7b-fc-r,测试function calling的功能
开发语言·python
指尖流烟1 小时前
C#调用图表的使用方法
开发语言·c#