【C++杂货铺】详解list容器


目录

🌈前言🌈

[📁 介绍](#📁 介绍)

[📁 使用](#📁 使用)

[📂 构造](#📂 构造)

[📂 迭代器iterator](#📂 迭代器iterator)

[📂 capacity](#📂 capacity)

[📂 modifiers](#📂 modifiers)

[📂 迭代器失效](#📂 迭代器失效)

[📁 模拟实现](#📁 模拟实现)

[📂 迭代器的实现](#📂 迭代器的实现)

[📂 代码展示](#📂 代码展示)

[📁 和vector的区别](#📁 和vector的区别)

[📁 总结](#📁 总结)


🌈前言🌈

欢迎收看本期【C++杂货铺】,本期内容将讲解STL中关于list的内容,会分为一下几个方面进行讲解:第一,什么是list,和其他容器的比较;第二,list的常用接口的介绍;第三,从底层除法,模拟实现简易版list;最后,对比和vecotr的主要区别。

以上就是本期要讲解的全部内容了,讲解之前需要你有数据结构中链表的储备知识,是为了更好的理解讲解内容。此外,模拟实现需要类和对象,模板等储备知识,如果只是想简单使用可以只看前两章。

如果你还没有类和对象及模板的知识,可以阅览下面这几篇文章:【C++杂货铺】详解类和对象 [上]-CSDN博客

【C++杂货铺】详解类和对象 [中]-CSDN博客

【C++杂货铺】详解类和对象 [下]-CSDN博客

【C++杂货铺】模板-CSDN博客

📁 介绍

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

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

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

与之相对的,list的最大缺陷是不支持在任意位置的随机访问。

📁 使用

list接口较多,这里简单介绍一些常用的重要接口。

下面是官方文档的链接,对于容器的学习还是要多看文档的。

list - C++ Reference (cplusplus.com)

📂 构造

📂 迭代器iterator

📂 capacity

📂 modifiers

📂 迭代器失效

迭代器失效即迭代器所指向的节点无效,即该节点被删除。 因为list底层是带头结点的双向循环链表 ,因此在list中进行插入时是不会导致迭代器失效的 ,只有在删除时才会失效 ,并且失效只是指向所删除结点的迭代器,其他迭代器不会受到影响

cpp 复制代码
void TestListIterator1()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 list<int> l(array, array+sizeof(array)/sizeof(array[0]));
 auto it = l.begin();
 while (it != l.end())
 {
 // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值
 l.erase(it); 
 ++it;
 }
}

// 改正
void TestListIterator()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 list<int> l(array, array+sizeof(array)/sizeof(array[0]));
 auto it = l.begin();
 while (it != l.end())
 {
 l.erase(it++); // it = l.erase(it);
 }
}

📁 模拟实现

对于list的模拟实现最难实现的就是迭代器的实现。所以下面将重点讲解迭代器内容。

📂 迭代器的实现

迭代器就是通过模拟指针,提供一种统一的方法来使用容器。

对于vecotr这样的容器,迭代器可以直接是指针,但对于list这样的容器,不能直接使用原生指针,因为底层内存地址不是连续的。

指针++,并不能实现node = node->next这样的操作。这里就要用到C++的重要组成部分了,运算符重载和实现了类。通过将指针封装成类,来实现运算符重载。

这里迭代器使用三个模板参数,第一个表示数据data的类型,第二表示数据data的引用,第三个表示数据data的地址。

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

		//构造函数

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

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

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

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

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

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

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

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

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

		Node* _node;
	};

📂 代码展示

下面将list的实现,放在exercise命名空间中。

cpp 复制代码
namespace exercise
{
	//节点类
	template<class T>
	struct ListNode
	{
		typedef ListNode<T> Node;
		Node* _next;
		Node* _prev;
		T data;

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


	};

	template<class T,class Ref,class Ptr>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T,Ref,Ptr> iterator;

		//构造函数

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

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

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

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

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

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

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

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

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

		Node* _node;
	};

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

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

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

		list()
		{
			empty_init();
		}

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

		void swap(list<T>& temp)
		{
			std::swap(_head,temp._head);
			std::swap(_size, temp._size);
		}

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

		void clear()
		{
			iterator it = _head->_next;
			while (it != _head)
			{
				it = erase(it);
			}
		}

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



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

		iterator end()
		{
			return _head;
		}

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

		const_iterator end() const
		{
			return _head;
		}

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

		void push_back(const T& val)
		{
			insert(end(), val);
		}

		void insert(iterator pos, const T& val)
		{
			Node* newnode = new Node(val);
			Node* prev = pos._node->_prev;
			Node* next = pos._node;
			newnode->_prev = prev;
			prev->_next = newnode;
			newnode->_next = next;
			next->_prev = newnode;
			_size++;
		}

		iterator erase(iterator pos)
		{
			Node* prev = pos._node->_prev;
			Node* next = pos._node->_next;
			delete pos._node;
			prev->_next = next;
			next->_prev = prev;
			_size--;
			return next;
		}
		
		void pop_back()
		{
			erase(--end());
		}

		size_t size()
		{
			return _size;
		}


	private:
		Node* _head;
		size_t _size;
	};

}

📁 和vector的区别

📁 总结

以上,就是本期【C++杂货铺】的主要内容了,包含了list的介绍,list常用接口以及模拟实现list。

如果感觉本期内容有帮助到你,欢迎点赞,收藏,关注Thanks♪(・ω・)ノ

相关推荐
Narutolxy3 分钟前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
XiaoLeisj8 分钟前
【递归,搜索与回溯算法 & 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)
数据结构·算法·leetcode·决策树·深度优先·剪枝
Hello.Reader10 分钟前
全面解析 Golang Gin 框架
开发语言·golang·gin
禁默21 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
yuyanjingtao23 分钟前
CCF-GESP 等级考试 2023年9月认证C++四级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
Code哈哈笑30 分钟前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
程序猿进阶33 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
qq_4336184436 分钟前
shell 编程(二)
开发语言·bash·shell
闻缺陷则喜何志丹39 分钟前
【C++动态规划 图论】3243. 新增道路查询后的最短距离 I|1567
c++·算法·动态规划·力扣·图论·最短路·路径
charlie1145141911 小时前
C++ STL CookBook
开发语言·c++·stl·c++20