STL_list

  • 了解list容器
  • 熟悉常见接口
  • 迭代器
  • list模拟实现

list容器


1.list容器

list容器底层是带头双向循环链表。任意位置插入删除效率都很高。

2.list与vector的优缺点

vectorlist
优点1.cpu缓存命中率高
2.支持随机访问
1.任意位置插入删除效率高
2.扩容消耗小
缺点1.扩容消耗大
2.头插,头删,中间插入删除效率低
1.不支持随机访问

接口


1.构造函数
//默认构造函数
list();
//用n个val构造
list(size_t n, T& val = T());
//迭代器区间构造
template<class InputIterator>
list(InputIterator first, InputIterator last);

2.重载函数

list<T> operator=(const list<T>& lt);

3.数据修改
//返回首元素
T& front();
//返回尾元素
T& back();
//在position位置前插入val
iterator insert(iterator position, const T& val);
//删除position位置
iterator erase(iterator position);
//尾插
void push_back(const T& val);
//尾删
void pop_back();
//头插
void push_front(const T& val);
//头删
void pop_front();

4.容量
//返回元素个数
size_t size();
//判空
bool empty();

迭代器


1.迭代器的本质

从外部接口来看,用户都是使用iterator来创建迭代器,但是它们的底层却并不简单,像string,vector之类底层是连续的空间,那么迭代器可以用原生指针,因为指针加1指向下一个有效元素,解引用指针也可得到正确的值,但是像list这样由一个一个节点构成,并不能将节点的地址作为迭代器,因为它们节点之间并不是连续的空间,将当前节点的地址+1也并不能指向下一个节点,将节点的地址解引用得到一个节点,但是我们需要的是节点内部的数据,所以list的原生指针并不能作为迭代器使用。如果我们想要达到我们的目的,即:迭代器+1指向下一个元素,解引用迭代器得到数据,那么就要结合前面的知识(函数重载),我们只要将原生指针封装为一个类,然后对该类的进行函数重载,此时,在外部创建迭代器,就是创建了一个该类的对象,对迭代器++或者解引用,就可以调用我们自己编写的重载函数,执行我们想要的操作。
总之:迭代器要么是原生指针,要么是类对原生指针的封装,如果原生指针不能达到目的,那么我们就需要封装原生指针。

2.list中迭代器失效问题
  • list中insert不会造成迭代器失效,因为迭代器指向的元素不会改变。
  • list中erase会造成迭代器失效,因为已经释放了迭代器指向的元素。常见的解决办法是erase函数返回下一个元素。
3.封装后迭代器如何控制const迭代器问题

我们直接可以想到的办法就是重新封装一个const_iterator类,但是因为模板可以传参,我们可以将引用作为参数传入,这样就可以实现。详见下列代码中的实现。

list模拟实现


namespace zs
{
	//当成员访问权限不应受限制时,我们可以把节点封装为struct类型
	template<class T>
	struct list_node
	{
		list_node<T>* _prev;
		list_node<T>* _next;

		T _val;

		list_node(const T& val = T())
			:_prev(nullptr)
			,_next(nullptr)
			,_val(val)
		{}
	};

	//为什么要重载->运算符
	//当T为类对象时,我们可以使用->来轻易访问类内的数据成员,此时就要用函数重载重载->
	//为什么要在模板中加入第三个参数,和Ref一样,是为了控制const属性
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> node;
		typedef __list_iterator<T, Ref, Ptr> self;

		node* _node;

		__list_iterator(node* n)
			:_node(n)
		{}

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

    	//->调用方法:
    	//假设T为class AA{int a; int b;}
    	// auto it = lt.begin();
    	// cout << it->a << it->b << endl; 这里应该是it->->a, 但是为了可读性,省略了一个箭头
		Ref operator*()
		{
			return _node->_val;
		}

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

		bool operator!=(const self& it)
		{
			return it._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;
		}


		template<class T>
		class list
		{
			typedef list_node<T> node;
		public:
			typedef __list_iterator<T, T&, T*> iterator;
			typedef __list_iterator<T, const T&, const T*> const_iterator;

			empty_init()
			{
				_head = new node;
				_head->_prev = _head;
				_head->_next = _head;
			}
			list()
			{
				empty_init();
			}

			//迭代器区间构造
			template<class InputIterator>
			list(InputIterator first, InputIterator last)
			{
				empty_init();
				while (first != last)
				{
					push_back(*first++);
				}
			}

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

			//拷贝构造
			//现代写法
			list(const list<T>& lt)
			{
				empty_init();
				
				list<T> tmp(lt.begin(), lt.end());

				swap(tmp);
			}

        	//现代写法
			list<T>& operator=(list<T> lt)
			{
				swap(lt);
				return *this;
			}

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

			void push_front(const T& val)
			{
				insert(begin(), val);
			}
			void pop_back()
			{
				erase(--end());

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

			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);
			}
			void insert(iterator pos, const T& val)
			{
				node* cur = pos;
				node* prev = pos._node->_prev;

				node* newNode = new node(val);

				newNode->_prev = prev;
				prev->_next = newNode;
				newNode->_next = cur;
				cur->_prev = newNode;
			}
			iterator erase(iterator pos)
			{
				assert(pos != end());

				node* prev = pos._node->_prev;
				node* next = pos._node->_next;

				delete pos._node;
				prev->_next = next;
				next->_prev = prev;

				return iterator(next);
			}
			void clear()
			{
				iterator it = begin();
				while (it != end())
				{
					erase(it++);
				}
			}
			~list()
			{
				clear();
				delete _head;
				_head = nullptr;
			}

		private:
			node* _head;

		};

	};
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值