C++学习之STL:list的模拟实现与解析

STL之list

  • 一级目录:list的介绍
    • 二级目录:list接口
      • 三级目录:list的模拟实现

一级目录:list的介绍

1.在数据结构中,我们都学过list是一个链表,有很多分类,比如单向链表,双向链表,循环链表等等…,但在STL中,list是一个容器,毋庸置疑,是用来保存链表与数据结构中的list有相似之处,但是在实现的时候会更加的绝妙,让人佩服。
首先,我们先看看文档中对STL中list的介绍:

  1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
  2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
  3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

2.list的优缺点:
在底层,list的实现方式是双向循环的链表,所以其优缺点与数据结构中的链表是相似的。
优点:
①:由于是链表的存储,所以在任意位置的删除和插入效率非常高,不需要移动数据。
②:可以进行大量的插入和删除,要多少申请多少,不用担心申请过多的不需要空间。
缺点:
①:不支持随机访问,每次访问都必须从头节点(或者指定节点)开始往后(或者往前)逐个访问,效率比较低。
②:底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低。
3.迭代器
迭代器:目前看来就跟指针的操作是相同的,但是它不是传统指针,而是相当于一个被封装了的指针,并且其操作都是通过操作运算符进行完成的,并且操作和使用与指针相类似。
但是在使用的时候,会存在迭代器失效的问题:
迭代器失效是在进行删除节点的操作中出现的,因为会存在将该节点删除后,再对该节点的迭代器进行操作,这样会使迭代器失效,例如如下操作:

list<int> L;
iterator it = L.begin();
while(it != L.end())
{
   L.erase(it);
   it++;
}
//这个函数是错误的,因为此时it已经被删除了,此时对it进行操作会出现错误;
//改正如下
while(it != L.end())
{
  L.erase(it++);
}
//在删除前让其指向下一个节点即可。

二级目录:list接口

由于在C++中,对于list的使用已经拥有了完整的代码,所以在实现一些有关链表的操作时,我们不需要再重新编写代码,可以使用关于list的接口去调用底层已经实现好的操作。
有关list的接口如下:
1.list的构造接口:

list()//构造一个空的链表
list (size_type n, const value_type& val = value_type()) //构造一个链表,其中还有n个值是val;
list (const list& x)//拷贝构造;
list (InputIterator first, InputIterator last)//用[first, last)区间中的元素构造list;

2.迭代器的接口:
(为了保证迭代器能像指针一样被使用,所以迭代器的各种使用方法都是经过运算符重载)

iterator begin();
iterator end();

3.list的容量:

bool empty();
int size();

4.list元素的访问:

_Ty& front();
_Ty& back();

5.list函数方法接口:

void push_front(value_type a);
void Pop_front();
void push_back(value_type a);
void Pop_back();
iterator insert(iterator _P, const _Ty& _X = _Ty());
iterator erase(iterator _P);
void clear();
void swap(list<int>& L);

三级目录:list的模拟实现

namespace m_list
{
	template<typename _Ty>
	class list
	{
		public:
		struct _Node
		{
			struct _Node* _Prev;
			struct _Node* _Next;
			_Ty _Value;
		};
	public:
		    typedef _Node* _Nodeptr;
			typedef size_t size_type;
			typedef _Ty*   pointer_type;
			typedef _Ty&   reference_type;
			typedef _Ty    value_type;
			typedef const _Ty* const_pointer_type;
			typedef const _Ty& const_reference_type;
	public:
		list():_Head(_BuyNode()),_Size(0)
		{}
	public:
		void push_back(value_type a)
		{
			/*_Nodeptr s = _BuyNode(_Head, _Head->_Prev);
			s->_Value = a;
			s->_Next->_Prev = s;
			s->_Prev->_Next = s;
			_Size++;*/
			insert(end(),a);
		}
		void push_front(value_type a)
		{
			insert(begin(), a);
		}
		void Pop_back()
		{
			/*_Nodeptr p = (--end())._Ptr;
			p->_Next->_Prev = p->_Prev;
			p-> _Prev->_Next = p->_Next;
			free(p);
			--_Size;
			p = nullptr;*/
			erase(--end());
		}
		void Pop_front()
		{
			/*_Nodeptr p = begin()._Ptr;
			p->_Next->_Prev = p->_Prev;
			p->_Prev->_Next = p->_Next;
			free(p);
			--_Size;
			p = nullptr;*/
			erase(begin());
		}
	public:
		class iterator//迭代器,目前我们可以用其代之指针(其实就是一个被封装了的指针)
		{
			friend class list;
		public:
			iterator()
			{}
			iterator(_Nodeptr P) :_Ptr(P)
			{}
			_Ty operator*()
			{
				return _Ptr->_Value;
			}
			_Ty* operator->()
			{
				return &(_Ptr->_Value);
			}
			iterator& operator++()
			{
				_Ptr = _Ptr->_Next;
				return (*this);
			}
			iterator operator++(int)
			{
				iterator r_Ptr = *this;
				++*this;
				return r_Ptr;
			}
			iterator& operator--()
			{
				_Ptr = _Ptr->_Prev;
				return (*this);
			}
			iterator operator--(int)
			{
				iterator r_Ptr = *this;
				--*this;
				return r_Ptr;
			}
			bool operator==(iterator& X)
			{
				return _Ptr == X._Ptr;
			}
			bool operator!=(iterator& X)
			{
				return !(_Ptr == X._Ptr);
			}
			_Nodeptr _Mynode()const
			{
				return _Ptr;
			}
		private:
			_Nodeptr _Ptr;
		};

	public:
		iterator insert(iterator _P, const _Ty& _X = _Ty())
		{
			_Nodeptr s = _P._Mynode();
			s->_Prev = _BuyNode(s, s->_Prev);
			s = s->_Prev;
			s->_Prev->_Next = s;
			s->_Value = _X;
			++_Size;
			return (iterator(s));
		}
		iterator erase(iterator _P)
		{
			_Nodeptr _S = (_P++)._Mynode();
			_S->_Next->_Prev = _S->_Prev;
			_S->_Prev->_Next = _S->_Next;
			_Size--;
			free(_S);
			_S = nullptr;
			return (iterator(_P));
		}
		iterator erase(iterator _F, iterator _L)
		{
			while (_F != _L)
				erase(_F++);
			return (_F);
		}
	public:
		iterator begin()
		{
			return iterator(_Head->_Next);//如同初始化类函数
		}
		iterator end()
		{
			return iterator(_Head);
		}
	public:
		bool empty()
		{
			return _Size == 0;
		}
		int size()
		{
			return _Size;
		}
	public:
		_Ty& front()
		{
			return _Head->_Next->_Value;
		}
		_Ty& back()
		{
			return _Head->_Prev->_Value;
		}
	public:
		void clear()
		{
			erase(begin(), end());
		}
		void swap(list<int>& L)
		{
			std::swap(_Head, L._Head);
		}
	private:
		_Nodeptr _BuyNode(_Nodeptr _Narg = 0, _Nodeptr _Parg = 0)
		{
			_Nodeptr s = (_Nodeptr)malloc(sizeof(_Node));
			s->_Next = _Narg != 0 ? _Narg : s;
			s->_Prev = _Parg != 0 ? _Parg : s;
			return s;
		}
	private:
		_Nodeptr _Head;
		size_type _Size;
	};
};

你可能感兴趣的:(list,c++,容器)