C++容器--list

list介绍

list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且可以前后双向迭代
list的底层式双向链表结构,双向链表中的每个元素存储在互不关联的独立节点中,节点中的指针指向前一个位置和后一个位置
list和forward_list非常相似:不同点在于,forward_list是单链表,只支持向前迭代,让其更加简单高效
与其他序列式容器相比(array,vector,deque),list通常在任意位置插入,删除元素的执行效率更好
list的最大缺陷在于不支持随机访问,要访问第六个元素,必须从头部或尾部遍历到该位置,在这段位置上需要线性时间的开销;list需要一些额外的空间,用于保存每个节点的相关联信息

常见接口

构造

list();	// 构造空的list
list(size_type n, const value_type& val = value_type());	// 构造的list中包含n个值为val的值
list(const list& x);	// 拷贝构造函数
list(InputIterator first, InputIterator last);	// 用迭代器区间中的元素构造list

迭代器

list的迭代器不是原生的指针,而是通过封装之后的指针
在这里可以直接将迭代器理解为一个指针,该指针指向list中的某个节点
在实现前会将迭代器的封装讲一下实现思路

begin();	// 返回第一个元素的迭代器
end();		// 返回最后一个元素的下一个位置的迭代器
rbegin();	// 返回第一个元素的reverse_iterator,即end位置
rend();		// 返回最后一个元素的reverse_iterator,即begin位置

// (C++11)	const迭代器
 cbegin();
 cend();
 crbegin();
 crend();

begin和end为正向迭代器,对迭代器进行++操作,迭代器向后移动
rbegin和rend为反向迭代器,对迭代器进行++操作,迭代器向前移动
const系列迭代器,不允许更改值

容量

bool empty() const;	// 检测list是否为空
size_t size() const;	// 返回list中有效节点的数量

元素引用

reference front();	// 返回list第一个节点值的引用
const_reference front() const;	// const引用
reference back();	// 返回list最后一个节点值的引用
const_reference back() const;	// const引用

reference为引用的重命名,使用typedef进行重命名
const_reference为const引用的重命名

修改

void push_front(const value_type& val);	// 头插
void pop_front();	// 头删
void push_back(const value_type& val);	// 尾插
void pop_back();	// 尾删
iterator insert(iterator position, const value_type& val);	// 在pos位置进行插入
void insert(iterator position, size_type n, const value_type& val);	//在pos位置插入n个val
void insert(iterator position,InputIterator first,InputIterator last);
	// 插入[first, last)区间的元素
iterator erase(iterator position);	// 删除pos位置的元素
iterator erase(iterator first, iterator last);	// 删除[first,last)区间的元素
void swap(list& x);	// 交换两个list中的元素
void resize(size_type n, value_type val = value_type());
	// 将list有效元素改位n个,多出的元素用val填充
void clear();	// 清空list中的有效元素

list迭代器失效问题

迭代器失效即迭代器指向的节点被删除
list的底层结构为带头节点的双向循环链表,在list中进行插入是不会导致迭代器失效的
在删除的时候,只有删除的迭代器会失效,其他迭代器不受影响

#include <list>

// list迭代器失效问题,在删除元素后,迭代器指向的节点已经释放,所以不能进行操作
void TestListIterator1() {
	int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; 
	std::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 }; 
	std::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

迭代器封装

list的迭代器
迭代器有两种实现方式:1. 原生指针–vector; 2. 将原生指针进行封装
封装后的迭代器必须具备以下方法:

  1. 解引用,重载operator*();
  2. ->访问其指向空间的成员,迭代器必须重载operator->();
  3. 指针可以++向后移动,迭代器需要重载operator++(),operator++(int),如果是双向链表还需要重载–
  4. 迭代器需要进行必要,所以还需要重载operator==(), operator!=();

封装后的迭代器可通过类模板参数进行传入

// 正向迭代器的封装
template<class T, class Ref, class Ptr>
class ListIterator {
public:
	typedef ListNode<T>* PNode;
	typedef ListIterator<T, Ref, Ptr> Self;
public:
	ListIterator(PNode pNode = nullptr)
		: _pNode(pNode)
	{}
	ListIterator(const Self& l)
		: _pNode(l._pNode)
	{}

	Ref operator*() {
		return _pNode->_val;
	}
	Ptr operator->() {
		return &(operator*());
	}
	Self& operator++() {
		_pNode = _pNode->_next;
		return *this;
	}
	Self operator++(int) {
		Self tmp(*this);
		_pNode = _pNode->_next;
		return tmp;
	}
	Self& operator--() {
		_pNode = _pNode->_prev;
		return *this;
	}
	Self operator--(int) {
		Self tmp(*this);
		_pNode = _pNode->_prev;
		return tmp;
	}


	bool operator!=(const Self& l) {
		return _pNode != l._pNode;
	}
	bool operator==(const Self& l) {
		return _pNode == l._pNode;
	}

	PNode _pNode;
};

// 反向迭代器的封装
template<class T, class Ref, class Ptr, class Iterator>
class ListReverseIterator {
	typedef ListReverseIterator<T, Ref, Ptr, Iterator> Self;
public:
	ListReverseIterator(const Iterator& it)
		: _it(it)
	{}
	ListReverseIterator(const Self& s)
		: _it(s._it)
	{}
	Ref operator*()  {
		Iterator tmp = _it;
		return *(--tmp);
	}
	Ptr operator->() {
		return &(operator*());
	}

	// 反向迭代器的++就是正向迭代器的--
	Self& operator++() {
		--_it;
		return *this;
	}
	Self operator++(int) {
		Iterator tmp(_it);
		--_it;
		return tmp;
	}

	Self& operator--() {
		++_it;
		return *this;
	}
	Self operator--(int) {
		Iterator tmp(_it);
		++_it;
		return tmp;
	}
	bool operator!=(const Self& s) {
		return _it != s._it;
	}
	bool operator==(const Self& s) {
		return _it == s._it;
	}

private:
	Iterator _it;
};

模拟实现

#include <iostream>

// 节点定义
template<class T>
struct ListNode
{
	ListNode(const T& val = T()) 
		: _prev(nullptr)
		, _next(nullptr)
		, _val(val) 
	{}
	ListNode<T> *_prev;
	ListNode<T> *_next;
	T _val;
};

template<class T, class Ref, class Ptr>
class ListIterator {
public:
	typedef ListNode<T>* PNode;
	typedef ListIterator<T, Ref, Ptr> Self;
public:
	ListIterator(PNode pNode = nullptr)
		: _pNode(pNode)
	{}
	ListIterator(const Self& l)
		: _pNode(l._pNode)
	{}

	Ref operator*() {
		return _pNode->_val;
	}
	Ptr operator->() {
		return &(operator*());
	}
	Self& operator++() {
		_pNode = _pNode->_next;
		return *this;
	}
	Self operator++(int) {
		Self tmp(*this);
		_pNode = _pNode->_next;
		return tmp;
	}
	Self& operator--() {
		_pNode = _pNode->_prev;
		return *this;
	}
	Self operator--(int) {
		Self tmp(*this);
		_pNode = _pNode->_prev;
		return tmp;
	}


	bool operator!=(const Self& l) {
		return _pNode != l._pNode;
	}
	bool operator==(const Self& l) {
		return _pNode == l._pNode;
	}

	PNode _pNode;
};

template<class T, class Ref, class Ptr, class Iterator>
class ListReverseIterator {
	typedef ListReverseIterator<T, Ref, Ptr, Iterator> Self;
public:
	ListReverseIterator(const Iterator& it)
		: _it(it)
	{}
	ListReverseIterator(const Self& s)
		: _it(s._it)
	{}
	Ref operator*()  {
		Iterator tmp = _it;
		return *(--tmp);
	}
	Ptr operator->() {
		return &(operator*());
	}

	// 反向迭代器的++就是正向迭代器的--
	Self& operator++() {
		--_it;
		return *this;
	}
	Self operator++(int) {
		Iterator tmp(_it);
		--_it;
		return tmp;
	}

	Self& operator--() {
		++_it;
		return *this;
	}
	Self operator--(int) {
		Iterator tmp(_it);
		++_it;
		return tmp;
	}
	bool operator!=(const Self& s) {
		return _it != s._it;
	}
	bool operator==(const Self& s) {
		return _it == s._it;
	}

private:
	Iterator _it;
};

template<class T>
class List {
	typedef ListNode<T> Node;
	typedef Node* PNode;
public:
	typedef ListIterator<T, T&, T*> Iterator;
	typedef ListIterator<T, const T&, const T*> ConstIterator;
	typedef ListReverseIterator<T, T&, T*, Iterator> ReverseIterator;
	typedef ListReverseIterator<T, const T&, const T*, ConstIterator> ConstReverseIterator;
public:
	List() {
		CreateHeap();
	}
	List(int n, const T& value = T()) {
		CreateHeap();
		for (int i = 0; i < n; ++i)
		{
			push_back(value);
		}
	}

	template<class Iterator>
	List(Iterator first, Iterator last) {
		CreateHeap();
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}
	List(const List<T>& l) {
		CreateHeap();

		List<T> tmp(l.CBegin(), l.CEnd());
		this->Swap(tmp);
	}

	List<T>& operator=(const List<T>& l) {
		if (this != &l)
		{
			List<T> tmp(l);
			this->Swap(tmp);
		}
		return *this;
	}

	~List() {
		Clear();
		delete _pHead;
		_pHead = nullptr;
	}

	// Iterator
	Iterator Begin() {
		return Iterator(_pHead->_next);
	}
	Iterator End() {
		return Iterator(_pHead);
	}
	ReverseIterator RBegin() {
		return ReverseIterator(End());
	}
	ReverseIterator REnd() {
		return ReverseIterator(Begin());
	}
	ConstIterator CBegin() const {
		return ConstIterator(_pHead->_next);
	}
	ConstIterator CEnd() const {
		return ConstIterator(_pHead);
	}
	ConstReverseIterator CRBegin() const {
		return ConstReverseIterator(CEnd());
	}
	ConstReverseIterator CREnd() const {
		return ConstReverseIterator(CBegin());
	}

	// list capacity
	size_t Size() const {
		size_t count = 0;
		PNode pCur = _pHead->_next;
		while (pCur != _pHead)
		{
			++count;
			pCur = pCur->_next;
		}
		return count;
	}
	bool Empty() const {
		return _pHead->_next == pHead;
	}
	void ReSize(size_t newSize, const T& val = T());

	// list access
	T& Front() {
		return _pHead->_next->_val;
	}
	const T& Front() const {
		return _pHead->_next->_val;
	}
	T& Back() {
		return _pHead->_prev->_val;
	}
	const T& Back() const {
		return _pHead->_prev->_val;
	}

	// list modify
	void push_back(const T& val) {
		PNode pNewNode = new Node(val);

		pNewNode->_next = _pHead;
		pNewNode->_prev = _pHead->_prev;

		_pHead->_prev = _pHead;
		pNewNode->_prev = _pHead->_prev;

		_pHead->_prev = pNewNode;
		pNewNode->_prev->_next = pNewNode;
	}

	void pop_back() {
		PNode pDel = _pHead->_prev;
		if (pDel != _pHead)
		{
			_pHead->_prev = pDel->_prev;
			pDel->_prev->_next = _pHead;
			delete pDel;
		}
	}

	void push_front(const T& val) {
		PNode pNewNode = new Node(val);

		pNewNode->_next = _pHead->_next;
		pNewNode->_prev = _pHead;

		_pHead->_next = pNewNode;
		pNewNode->_next->_prev = pNewNode;
	}

	void pop_front() {
		PNode pDel = _pHead->_next;
		if (pDel != _pHead)
		{
			_pHead->_next = pDel->_next;
			pDel->_next->_prev = _pHead;
			delete pDel;
		}
	}

	Iterator insert(Iterator pos, const T& val) {
		PNode pNewNode = new Node(val);
		PNode pCur = pos._pNode;

		pNewNode->_prev = pCur->_prev;
		pNewNode->_next = pCur;
		pNewNode->_prev->_next = pNewNode;
		pCur->_prev = pNewNode;
		return Iterator(pNewNode);
	}

	Iterator erase(Iterator pos) {
		PNode pDel = pos._pNode;
		PNode pRet = pDel->_next;

		pDel->_prev->_next = pDel->_next;
		pDel->_next->_prev = pDel->_prev;
		delete pDel;

		return Iterator(pRet);
	}

	void Clear() {
		PNode pCur = _pHead->_next;
		while (pCur != _pHead)
		{
			_pHead->_next = pCur->_next;
			delete pCur;
			pCur = _pHead->_next;
		}
		_pHead->_next = _pHead;
		_pHead->_prev = _pHead;
	}

	void Swap(List<T>& l) {
		std::swap(_pHead, l._pHead);
	}




private:
	void CreateHeap() {
		_pHead = new Node;
		_pHead->_next = _pHead;
		_pHead->_prev = _pHead;
	}
private:
	PNode _pHead;
};

template<class T>
void PrintList(List<T>& l) {
	auto it = l.Begin();
	while (it != l.End())
	{
		std::cout << *it << " ";
		++it;
	}
	std::cout << std::endl;
}

template<class T>
void PrintListReverse(const List<T>& l) {
	auto it = l.CRBegin();
	while (it != l.CREnd())
	{
		std::cout << *it << " ";
		++it;
	}

	std::cout << std::endl;
}

void TestList1() {
	List<int> l1;   
	List<int> l2(10, 5);    
	PrintList(l2);

	int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };   
	List<int> l3(array, array + sizeof(array) / sizeof(array[0])); 
	PrintList(l3);

	List<int> l4(l3);    
	PrintList(l4);

	l1 = l4;    
	PrintList(l1);    
	PrintListReverse(l1);
}

int main()
{
	TestList1();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STL是指标准模板库(Standard Template Library),它是C++语言的一部分,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL的目标是提供高效、可重用和可扩展的组件,以便开发人员能够更轻松地编写高质量的代码。STL包含了许多常见的数据结构,如vector、list、set、map等,以及各种算法,比如排序、查找、遍历等。通过使用STL,开发人员可以更加高效地处理各种数据结构和算法的问题,提高代码的开发效率和质量。 在STL中,我们可以使用各种容器来存储和管理数据。例如,我们可以使用std::map来创建一个键值对的映射,其中每个键都有一个与之相关联的值。下面是一个示例代码,展示了如何创建和使用一个std::map对象: std::map<std::string, int> disMap() { std::map<std::string, int> tempMap{ {"C语言教程",10},{"STL教程",20} }; return tempMap; } std::map<std::string, int> newMap(disMap()); 在这个示例中,disMap()函数创建了一个临时的std::map对象,并初始化了其中的一些键值对。然后,使用移动构造函数将这个临时对象移动到了一个新的std::map对象newMap中。最终,我们可以通过newMap对象来访问和操作这些键值对。 综上所述,STL是C++中的标准模板库,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL的使用可以提高代码的开发效率和质量,并且通过各种容器和算法,可以方便地处理各种数据结构和算法的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++ STL详解超全总结(快速入门STL)](https://blog.csdn.net/qq_50285142/article/details/114026148)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【C++实验】阅读STL源码并分析](https://blog.csdn.net/qq_35760825/article/details/125311509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值