目录
一、list的使用
1.1list的构造
1.2list的iterator
编辑
1.3 list的capacity
1.4 list的element access
编辑
1.5list的mdifiers
编辑
二、list的迭代器失效问题
三、list的模拟实现
3.1定义一个节点类
3.2用节点去封装迭代器
编译器对->的优化问题
编辑
Ref和Ptr
3.3list基本功能的实现
四、vector和list的比较
4.1vector
4.2list
一、list的使用
1.1list的构造
1.2list的iterator
1.3 list的capacity
1.4 list的element access
1.5list的mdifiers
二、list的迭代器失效问题
list的底层是双向带头循环链表,在实现插入功能的时候是一边扩容一边插入,且都是在原空间上进行操作的,因此list的插入不存在迭代器失效问题;但list的删除就会使该节点位置的迭代器失效,其他位置的迭代器不受影响,如果要解决这个问题,仍然是用迭代器去接收返回值。
三、list的模拟实现
3.1定义一个节点类
//节点
template<class T>
struct list_node
{
	list_node<T>* _prev;
	list_node<T>* _next;
	T _val;
	list_node(const T& x = T())
		:_prev(nullptr)
		,_next(nullptr)
		,_val(x)
	{}
};
节点类就相当于c语言中的BuyNewNode()
3.2用节点去封装迭代器
因为list的底层结构是不连续的,指向节点的指针++不一定是list下一个位置的节点,因此不能使用原生指针来作为list的迭代器。这里的解决办法是用节点指针(原生指针)去封装迭代器,在这个迭代器类的内部去模拟实现原生指针的功能,即用运算符重载实现适配于list的++ -- != == * ->等操作
//用节点(自定义类型)封装的迭代器
//typedef _list_iterator<T,T&,T*> iterator;
//typedef _list_iterator<T, const T&, const T*> const_iterator;
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* node)
		:_node(node)
	{}
	Ref operator*()
	{
		return _node->_val;
	}
	Ptr operator->()
	{
		return &_node->_val;
	}
	self& operator++()
	{
		_node = _node->_next;
		return *this;
	}
	self operator++(int)
	{
		_list_iterator temp(*this);
		_node = _node->_next;
		return temp;
	}
	self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}
	self operator--(int)
	{
		_list_iterator temp(*this);
		_node = _node->_prev;
		return temp;
	}
	bool operator!=(const self& lt) const
	{
		return _node != lt._node;
	}
	bool operator==(const self& lt) const
	{
		return _node == lt._node;
	}
};编译器对->的优化问题
创建一个存储结构体的list对象,结构体对成员变量的访问可以通过 变量名.成员变量 或者 结构体指针->成员变量 来实现。我们在重载*和->的时候可以发现,对it进行*解引用操作找到的是一个结构体,该结构体使用.操作符去访问成员变量,这是合理的;但是对it进行->操作时找到的是一个结构体指针,结构体指针要去访问成员变量,应该再次使用->,it->_a1代码应该是写成(it->)->_a1的,但是编译器对其进行了优化,直接用一个->就可以实现迭代器对结构体成员变量的访问
Ref和Ptr
在实现const_iterator时,不能直接typedef const _list_iterator<T, Ref ,Ptr> const_self,因为const的作用是不能改变迭代器所指向的内容,迭代器本身是可以改变的。所以要实现const_list_iterator 只需要在_list_iterator这个类内部对*和->的返回值进行限制。那么*和->的返回值就不只有T& 和T*,还有const T& 和const T*,将返回值重新定义为新的模板参数Ref和Ptr
3.3list基本功能的实现
	//双向带头循环链表
	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;
		iterator begin()
		{
			//return _head->_next;
			return iterator(_head->_next);
		}
		iterator end()
		{
			//return _head;
			return iterator(_head);
		}
		const_iterator begin() const
		{
			//return _head->_next;
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			//return _head;
			return const_iterator(_head);
		}
		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}
		list()
		{
			empty_init();
		}
		//拷贝构造
		list(const list<T>& lt)
		{
			empty_init();
			for (auto& e : lt)
			{
				push_back(e);
			}
		}
		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}
		//赋值运算符重载
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
				it++;
			}
			_size = 0;
		}
		void push_back(const T& x = T())
		{
			/*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 push_front(const T& x = T())
		{
			insert(begin(), x);
		}
		void pop_back()
		{
			erase(--end());
		}
		void pop_front()
		{
			erase(begin());
		}
		//在pos位置之前插入数据
		iterator insert(iterator pos, const T& x=T())
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);
			newnode->_next = cur;
			cur->_prev = newnode;
			prev->_next = newnode;
			newnode->_prev = prev;
			_size++;
			return newnode;
		}
		//删除pos位置的数据
		iterator erase(iterator pos)
		{
			assert(pos != end());
			Node* cur = pos._node;
			Node* next = cur->_next;
			Node* prev = cur->_prev;
			prev->_next = next;
			next->_prev = prev;
			delete cur;
			_size--;
			return next;
		}
		size_t size()
		{
			return _size;
		}
	private:
		Node* _head;
		size_t _size;
		
	};
}四、vector和list的比较
4.1vector
vector的底层是一块连续的空间,支持用[下标]随机访问元素,时间复杂度为O(1);插入和删除的时候需要搬移元素(插入有时候还需要扩容),时间复杂度为O(N);对空间的利用率高,不容易造成内存碎片,缓存利用率高;迭代器使用原生指针,插入和删除都会导致迭代器的失效问题;适用于需要高效存储,支持随机访问,不关心插入和删除的场景
4.2list
list的底层是一段不连续的空间,不支持[下标]随机访问,访问元素需要遍历,时间复杂度为O(N);插入和删除的时候直接对该位置进行操作,不需要搬移元素,时间复杂度为O(1);对空间的利用率低,容易造成内存碎片,缓存利用率低;迭代器是对原生指针(节点指针)的封装,插入时不存在迭代器失效问题,但删除时会导致迭代器的失效;适用于需要大量的插入和删除,但不关心随机访问的场景
























