C++初阶:list

✨✨所属专栏:C++✨✨

✨✨作者主页:嶔某✨✨

 学习STL要多看文档list - C++ Reference (cplusplus.com)

list的介绍

list的 底层结构和我们之前学的双向带头循环链表的结构是差不多的,封装一个节点包含数据和前后节点的指针。迭代器就是指向这个节点的指针,只不过由于原生指针不支持随机访问,所以对这个指针进行了封装。

list的使用

constructor

构造函数(constructor)接口说明
list()默认构造
list(size_type n,const value_type& val = value_type())构造的list中包含n个值为val的与元素
list(const list& x)拷贝构造
list(InputIterator first , InputItertor last)用迭代器[first , last)区间中的元素构造list

 list iterator

(1)这里的list迭代器的实现不再是简单的原生指针,而是对原生指针进行了一层封装,使它更符合迭代器的行为

(2)这里多加两个模板参数,主要是 * -> 两个操作符重载访问Node里面的内容。如果调的是const_iterator,那么返回的就是const指针(const修饰指针指向的内容不可修改)或引用如果调用普通的iterator,返回普通指针或引用。

(3)这样通过模板编译器其实还是会生成两个类,减少了重复的代码

(4)list的迭代器不是随机迭代器,而是双向迭代器。

输入迭代器(Input Iterators):允许读取和遍历容器中的元素,只能单向移动,每个元素只能被访问一次。
输出迭代器(Output Iterators):允许向容器中写入元素,只能单向移动,每个位置只能被写入一次。
前向迭代器(Forward Iterators):允许读写容器中的元素,可以多次读写同一个元素,只能单向移动。
双向迭代器(Bidirectional Iterators):具有前向迭代器的所有功能,同时允许在容器中双向移动。
随机访问迭代器(Random Access Iterators):具有双向迭代器的所有功能,同时提供了快速随机访问容器中任意元素的能力,如指针算术运算。 

template<class T,class Ref,class Ptr>
struct list_iterator
{
	typedef list_iterator<T, Ref, Ptr> self;
	typedef list_iterator<T, T&, T*> iterator;
	typedef list_iterator<T, const T&, const T*> const_iterator;

	typedef struct Node<T> Node;

	list_iterator(Node* node = nullptr)
		:_node(node)
	{}
	list_iterator(const self& lf)
	{
		_node = lf._node;
	}
	Ref operator*()
	{
		return _node->data;
	}
	Ptr operator->()
	{
		return &_node->data;
	}
	self& operator++()
	{
		_node = _node->next;
		return *this;
	}
	self operator++(int)
	{
		self tmp(_node);
		//Node* tmp = new Node(_node->data);//自己想出来的写法哟~but有点复杂了
		_node = _node->next;
		return tmp;
	}
	self& operator--()
	{
		_node = _node->prev;
		return *this;
	}
	self operator--(int)
	{
		self tmp(_node);
		//Node* tmp = new Node(_node->data);//自己想出来的写法哟~but有点复杂了
		_node = _node->prev;
		return tmp;
	}
	bool operator==(const self& it)
	{
		return _node == it._node;
	}
	bool operator!=(const self& it)
	{
		return _node != it._node;
	}
	Node* _node;
};
begin()返回第一个元素的迭代器
end()返回最后一个元素的下一个位置的迭代器
rbegin()返回第一个元素的reverse_iterator,即end位置
rend()返回最后一个元素下一个位 置的reverse_iterator,即begin位置

【注意】

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

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

list capacity

函数声明接口说明
empty()检测list是否为空,是返回true,否则返回false
size()

返回list中有效节点的个数

list element access

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

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中的有效元素

 list的迭代器失效

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

 随机插入完成后会返回新插入节点的迭代器,随机删除完成后会返回删除节点的下一个节点的迭代器,若删除了最后一个元素,则返回头节点的迭代器。

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;

	++_size;

	return newnode;
}
iterator erase(iterator pos)
{
	assert(pos != end());
	Node* next = pos._node->next;
	Node* prev = next->prev;

	delete pos._node;

	prev->next = next;
	next->prev = prev;
	--_size;
	return next;
}

 模拟实现list

function/list类/list.h · 钦某/C++learning - 码云 - 开源中国 (gitee.com)

对比list和vector

vectorlist
底 层 结 构动态顺序表,一段连续空间带头结点的双向循环链表
随 机 访 问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(N)
插 入 和 删 除任意位置插入和删除效率低,需要搬移元素,时间 复杂度为O(N),插入时有可能需要增容,增容: 开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高, 不需要搬移元素,时间复杂度 为O(1)
空 间 利 用 率底层为连续空间,不容易造成内存碎片,空间利用 率高,缓存利用率高底层节点动态开辟,小节点容 易造成内存碎片,空间利用率 低,缓存利用率低
迭 代 器原生态指针对原生态指针(节点指针)进行封装
迭 代 器 失 效在插入元素时,要给所有的迭代器重新赋值,因为 插入元素有可能会导致重新扩容,致使原来迭代器 失效,删除时,当前迭代器需要重新赋值否则会失 效插入元素不会导致迭代器失 效,删除元素时,只会导致当 前迭代器失效,其他迭代器不 受影响
使 用 场 景需要高效存储,支持随机访问,不关心插入删除效 率大量插入和删除操作,不关心 随机访问

本期博客到这里就结束了,如果有什么错误,欢迎指出,如果对你有帮助,请点个赞,谢谢!

posted @ 2024-08-08 22:04  QinMou~  阅读(21)  评论(0)    收藏  举报  来源