码迷,mamicode.com
首页 > 其他好文 > 详细

STL----<list>

时间:2015-08-11 18:42:06      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:

双向循环链表list

        list是双向循环链表,,每一个元素都知道前面一个元素和后面一个元素。在STL中,list和vector一样,是两个常被使用的容器。和 vector不一样的是,list不支持对元素的任意存取。list中提供的成员函数与vector类似,不过list提供对表首元素的操作 push_front、pop_front,这是vector不具备的。和vector另一点不同的是,list的迭代器不会存在失效的情况,他不像 vector会保留备份空间,在超过容量额度时重新全部分配内存,导致迭代器失效;list没有备份空间的概念,出入一个元素就申请一个元素的空间,所以 它的迭代器不会失效。


  与vector相比  list每次增加一个元素,不存在重新申请内存的情况,它的成本是恒定的。而vector每当增加关键元素的时候,都需要重新申请新的更大的内存空间,会 调用元素的自身的复制构造函数,存在构造成本。在销毁旧内存的时候,会调用析构函数,存在析构成本。所以在存储复杂类型和大量元素的情况下,list比 vector更有优势! 

    List是一个双向链表,双链表既可以向前又向后链接他的元素。

    List将元素按顺序储存在链表中. 与 向量(vector)相比, 它允许快速的插入和删除,但是随机访问却比较慢。

具体的list结构可以看下图

技术分享

下面是list的主要函数:

assign() 给list赋值 

back() 返回最后一个元素 

begin() 返回指向第一个元素的迭代器 

clear() 删除所有元素 

empty() 如果list是空的则返回true 

end() 返回末尾的迭代器 

erase() 删除一个元素 

front() 返回第一个元素 

get_allocator() 返回list的配置器 

insert() 插入一个元素到list中 

max_size() 返回list能容纳的最大元素数量 

merge() 合并两个list 

pop_back() 删除最后一个元素 

pop_front() 删除第一个元素 

push_back() 在list的末尾添加一个元素 

push_front() 在list的头部添加一个元素 

//rbegin() 返回指向第一个元素的逆向迭代器 

remove() 从list删除元素 

//remove_if() 按指定条件删除元素 

//rend() 指向list末尾的逆向迭代器 

resize() 改变list的大小 

reverse() 把list的元素倒转 

size() 返回list中的元素个数 

//sort() 给list排序 

splice() 合并两个list 

swap() 交换两个list 

            //unique() 删除list中重复的元素

下面是提取出的list源码:

//list.h
#include "allocator.h"

//从list源码中提取出的没有const的iterator和反向iterator
namespace kai
{
template<class _Ty, class _A = allocator<_Ty> >
class list {
protected:
 struct _Node;
 friend struct _Node;
    typedef  _Node*   _Nodeptr;// typedef _POINTER_X(_Node, _A) _Nodeptr;
 struct _Node {
  _Nodeptr _Next, _Prev;
  _Ty _Value;
 };
 struct _Acc;
 friend struct _Acc;
 struct _Acc {
  typedef  _Node*&  _Nodepref;//typedef _REFERENCE_X(_Nodeptr, _A) _Nodepref;
  typedef _A::reference _Vref;
  static _Nodepref _Next(_Nodeptr _P)//定义为static是为了在类外可以用_A::方式访问函数
  {return ((_Nodepref)(*_P)._Next); }//代替了p->next
  static _Nodepref _Prev(_Nodeptr _P)
  {return ((_Nodepref)(*_P)._Prev); }//代替了p->prev
  static _Vref _Value(_Nodeptr _P)
  {return ((_Vref)(*_P)._Value); }//代替了p->value
  };
 public:
  typedef list<_Ty, _A> _Myt;
  typedef _A  allocator_type;
  typedef _A::size_type size_type;
  typedef _A::difference_type difference_type;
  typedef _A::pointer _Tptr;
  //typedef _A::const_pointer _Ctptr;
  typedef _A::reference reference;
  //typedef _A::const_reference const_reference;
  typedef _A::value_type value_type;
 
 
  // CLASS iterator 内嵌迭代器
  class iterator;//其实就是对指针的封装 重载*  和->
  friend class iterator;
  class iterator
 {
 public:
         iterator()
   {
   }
   iterator(_Nodeptr _P):_Ptr(_P)
   {
   }
   _Nodeptr _Mnode()//得到当前迭代器对象的数据
   {
           return (_Ptr);//this->_Ptr
   }
         
   reference operator*()const//重载*返回_Node中数据的引用 _Ty
   {
    return (_Acc::_Value(_Ptr));
   }
         
          _Tptr operator->()//重载->
    {
     return (&**this); //相当于这两步iterator tmp=*this;
                               // &tmp.operator*();
                     
    }
          iterator& operator++()//重载前置++可以返回对象引用
    {
     _Ptr=_Acc::_Next(_Ptr);//p=p->next;
     return *this;
    }
          iterator operator++(int)//重载后置++,不可以返回对象引用,因为要建立临时对象
    {
     iterator tmp=*this;
     ++ *this;//调用了重载的前置++
              return tmp;
    }
    iterator& operator--()//重载前置++可以返回对象引用
    {
     _Ptr=_Acc::_Prev(_Ptr);//p=p->Pre;
     return *this;
    }
          iterator operator--(int)
    {
     iterator tmp = *this;
     -- *this;//调用了重载的前置--
              return tmp;
    }
    bool operator==(const iterator& _X) const//重载==
    {
     return (_Ptr == _X._Ptr);
    }
    bool operator!=(const iterator& _X) const//重载!=
    {
     return (!(*this == _X));
    }

 protected:
  _Nodeptr _Ptr;
 };

////////reverse///////////

  //默认构造函数
  explicit list(const _A& _Al = _A())//list的构造函数并且不允许隐式类型转换
   : allocator(_Al),_Head(_Buynode()), _Size(0)
   //allocator是一个 _A这个类的对象
 {}
explicit list(size_type _N,const _Ty &_V=_Ty(), const _A &_A1=_A())
            :allocator(_A1),_Head(_Buynode()),_Size(0)
{
   insert(begin(),_N,_V);//创建N个相同的节点
}

list (_Myt& X)//list的拷贝构造函数
   :allocator(X.allocator),_Head(_Buynode()),_Size(0)
{
    insert(this->begin(),X.begin(),X.end());
}

list(const _Ty *_F,const _Ty *_L,const _A &_A1=_A())
  :allocator(_A1),_Head(_Buynode()),_Size(0)
{
   insert(begin(),_F,_L);
}

  typedef iterator _It;
list(_It _F,_It _L,const _A &_A1 = _A())//创建一定范围的链表
   :allocator(_A1),_Head(_Buynode()),_Size(0)
  {
      insert(begin(),_F,_L);
   
  }
  ~list()
  {
   erase(begin(),end());
   free(_Head);
  }
_Myt& operator=(_Myt &_X)//重载list的赋值函数
{
   if(this != &_X)
   {
       iterator _F1 = begin();
    iterator _L1 = end();
    iterator _F2 = _X.begin();
    iterator _L2 = _X.end();
 for (; _F1 != _L1 && _F2 != _L2; ++_F1, ++_F2)
 {
 *_F1 = *_F2;//先用_X中数据赋值到*this的数据上
 }
 erase(_F1, _L1);//将*this中剩余的空间(可能会没有剩余空间)
 insert(_L1, _F2, _L2);//当_X的数据比*this的数据多的时候把_X剩余的数据插到_L1的前面,此时_L1指向的是链表最后一个元素的下一个元素的位置
   }
   return *this;
}
  iterator begin()//有头结点的双向循环链表的第一个节点就是头节点后边的第一个节点
  {return (iterator(_Acc::_Next(_Head)));}//返回迭代器无名对象
  iterator end()
  {return (iterator(_Head)); }//返回iterator的无名对象  
                   //双向循环链表的结束标志就是p->next!=head所以表示结束的就是到头节点
  iterator rbegin()
  {
   return iterator(--end());
  }
  iterator rend()
  {
   return iterator(--begin());
  }

  //这是我自己加的一个函数
  iterator Prend()//真正的最后一个元素
  {
   return (iterator(_Acc::_Prev(_Head)));
  }
  void resize(size_type _N,_Ty _X=_Ty())//当你一开始建立了_N个内容一样的节点,现在感觉节点的个数不符合自己的需求,就可以将相同节点的个数维持在你认为的个数上
  {
   if( size()<_N)//确保元素的个数是_N如果不够就使用_X进行补齐
   {
          insert(end(),_N-size(),_X);
   }
   else
   {
        while(size() > _N)
  {
   pop_back();
  }

   }
  }
  size_type size()const//返回节点个数
  {
   return _Size;
  }

  size_type max_size()const//计算这种类型的数据最多可以有多个节点
  {
   return allocator.max_size;
  }

  bool empty()const
  {
    return (0==size());
  }
 _A get_allocator()const//得到list内嵌的空间配置器对象
 {
    return (allocator);
 }

 reference front()//返回迭代器对象的地址,这个迭代器指向链表的第一个节点
 {
    return (*begin());
 }

 reference back()
 {
  return (*--end());//返回迭代器对象的地址,指向链表的最后一个节点的
 }

 void push_front(const _Ty &_X)//头插插入节点
 {
  insert(begin(),_X);
 }

void pop_front()//头删
{
 erase(begin());
}

void push_back(const _Ty &_X)//尾插插入节点
{
  insert(end(),_X);
}

void pop_back()//尾删
{
 erase(--end());
}
void assign(_It _F, _It _L)//赋值链表的一个范围的节点
{
    erase(begin(),end());//将链表删除只剩下头节点
 insert(begin(),_F,_L);//再依次创建节点进行插入
}
void assign(size_type _N,const _Ty &_X = _Ty())//赋上_N 个一样的数据默认数据是该类型的0值
{
   erase(begin(),end());
   insert(begin(),_N,_X);//其实_N个元素在头部的前边插入或者尾部插入效果都是一样的
                         //insert(end(),_N,_X);
}

iterator insert(iterator _P,const _Ty &X=_Ty())//默认在该节点的前边进行插入
{
 _Nodeptr _S = _P._Mnode();//_S指针指向当前节点
 _Acc::_Prev(_S)=_Buynode(_S,_Acc::_Prev(_S));
        //节点购买回来前已经next指向了当前节点,pre已经指向了当前节点的前驱
           //之后把当前节点的pre指向新节点
 _S=_Acc::_Prev(_S); //_S指针指向新节点
 _Acc::_Next(_Acc::_Prev(_S)) = _S;//新节点的前驱的后继指向自己
 allocator.construct(&_Acc::_Value(_S),X);//当前新节点值的地址,定位处创建当前类型的大小空间,并将值_X 放进去
    ++_Size;
 return (iterator(_S));//返回指向新节点的迭代器
   
}
void insert(iterator _P,size_type _M,const _Ty &_X)//在_P所指节点的前边插入_M个值为_X 的节点
{
 for(; 0<_M; --_M)
 {
       insert(_P,_X);
 }
}
void insert(iterator _P,const _Ty *F, const _Ty *L)//插入一个范围的节点
{
 for(;F!=L;++F)//每次移动的是类型的大小,指针的移动,不会调用重载后的前置++,和!=
 {
        insert(_P,*F);//这里没有调用重载*,就是普通的指针的解引用
 }
}

void insert(iterator _P,_It F,_It L)
{
 for(;F!=L;++F)//调用重载后的前置++ 和!=,链表即是 for(;p->next!=head;p=p->next)
 {
  insert(_P,*F);//这里调用的是重载后的*,返回的是值得引用
 }
}

iterator erase(iterator _F)//删除当前节点并且返回它的后继节点
{
    _Nodeptr _S=(_F++)._Mnode();
 _Acc::_Next(_Acc::_Prev(_S))=_Acc::_Next(_S);
 _Acc::_Prev(_Acc::_Next(_S))=_Acc::_Prev(_S);
 allocator.destroy(&_Acc::_Value(_S));//析构对象
    _Freenode(_S);//释放对象空间
 --_Size;
 return(_F);    
}

iterator erase(iterator _F,iterator _L)//删除_F 到_L 范围的节点,并且返回_L的后继节点
{
   while(_F!=_L)//调用重载!=
   {
    erase(_F++);//调用重载++
   }
   return _F;//返回_F后边的节点迭代器
}

void clear()//清空
{
 erase(begin(),end());
}
//自己加的函数娱乐一下
void Print()
{
  iterator p=begin();
  iterator q=end();
   for(; p!=q;++p)
   {
    cout<<_Acc::_Value(p._Mnode())<<" ";//p._Mnode()->_value;
   }

   cout<<endl;
}

//自己加的函数娱乐一下,其实list自带有反向迭代器这个是多此一举
void RevesPrint()
{
 iterator p=rbegin();
 iterator q=rend();
 for(;p!=q;--p)
 {
       cout<<_Acc::_Value(p._Mnode())<<" ";
 }
 cout<<endl;
}

void swap(_Myt& _X)
{
 if (allocator == _X.allocator)//判断是不是同一个空间配置器
 {  
  std::swap(_Head, _X._Head);
        std::swap(_Size, _X._Size); }
    else
 {
  iterator _P = begin();
        splice(_P, _X);
       _X.splice(_X.begin(), *this, _P, end());
 }
}

//自己加的交换函数(友员的)
friend void swap(_Myt& _X, _Myt& _Y)
{
 _X.swap(_Y);
}

void splice(iterator _P, _Myt& _X)
{
 if (!_X.empty())
 {
  _Splice(_P, _X, _X.begin(), _X.end());
        _Size += _X._Size;
        _X._Size = 0;
 }
}
void splice(iterator _P, _Myt& _X, iterator _F)
{
 iterator _L = _F;
    if (_P != _F && _P != ++_L)
 {
  _Splice(_P, _X, _F, _L);
         ++_Size;
         --_X._Size;
 }
}
//Distance这里我自己实现了一下,其实系统自己有实现
void Distance(iterator _F,iterator _L,difference_type _N)
{
  for(;_F!=_L;++_F)
  {
   ++_N;
  }
}

void splice(iterator _P, _Myt& _X, iterator _F, iterator _L)//拼接一个_X的一个元素范围到*this,这是剪切下来进行拼接
{
 if (_F != _L)//判断是不是没有节点
{
 if (&_X != this)//判断是不是自己拼接自己
 {
   difference_type _N = 0;
         Distance(_F, _L, _N);//计算要拼接的节点个数
         _Size += _N;//给源链表+长度
         _X._Size -= _N; //给dest链表-长度
 }
 _Splice(_P, _X, _F, _L);
}
}

void splice(iterator _P, _Myt& _X, ptrdiff_t _F, ptrdiff_t  _L)
{
 iterator p=_X.begin();
 iterator q=_X.end();
 ptrdiff_t  i=1;
 ptrdiff_t  j=(ptrdiff_t )size();
 while(i<_F)
 {
    ++p;
    ++i;
 }
 while(j>_L)
 {
     --q;
  --j;
 }
splice(_P,_X,p,q);
}
void remove(const _Ty& _V)    //从list删除元素
{
iterator _L = end();
for (iterator _F = begin(); _F != _L; )
{
if (*_F == _V)
erase(_F++);
else
 ++_F;
}//没有找到也不会有提示,因为没有何来删除一说
}

//自己添加的重载>> 默认向尾插入  L>>5>>8>>9
friend _Myt& operator>> ( _Myt& L, const _Ty& value)
{
 L.push_back(value);
   
 return L;
}
//重载<< 默认向头插入  L<<5<<8<<9
friend _Myt& operator<< ( _Myt& L, const _Ty& value)
{
 L.push_front(value);
 
 return L;
}
friend std::ostream& operator<< ( std::ostream& Out,_Myt &_X)
{
   _X.Print();
    return Out;
}


protected:
  _A allocator;//通过_A空间配置器的内嵌对象构造节点
  _Nodeptr _Head;
  size_type _Size;

  _Nodeptr _Buynode(_Nodeptr _Narg = 0, _Nodeptr _Parg = 0)
  {
   _Nodeptr _S = (_Nodeptr)allocator.allocate(1 * sizeof (_Node),0);
   //_Nodeptr _S = (_Nodeptr)allocator._Charalloc(1 * sizeof (_Node));
   _Acc::_Next(_S) = _Narg != 0 ? _Narg : _S; //
   _Acc::_Prev(_S) = _Parg != 0 ? _Parg : _S;
   return (_S);
  }
  void _Freenode(_Nodeptr _S)
  {
     allocator.deallocate(_S,1);//释放空间
  }
  void _Splice(iterator _P, _Myt& _X, iterator _F, iterator _L)//拼接是在_P这个位置的前边进行拼接
  {                                 //拼接的范围是_F 到_L的前一个节点,包括_F
   if (allocator == _X.allocator)//同一个空间配置器
  {
  _Acc::_Next(_Acc::_Prev(_L._Mnode())) = _P._Mnode();//把_L的前一个节点的后继指向要插入点位置的后一个元素
  _Acc::_Next(_Acc::_Prev(_F._Mnode())) = _L._Mnode();//原来的链表中_P到_L前面的一段链表要被切割出去,所以现在要将原来的链表重新连接好,_F前驱的后继指向_L
  _Acc::_Next(_Acc::_Prev(_P._Mnode())) = _F._Mnode();//_P的前驱的后继指向_F
  _Nodeptr _S = _Acc::_Prev(_P._Mnode());//_P的前驱节点地址保存一下
  _Acc::_Prev(_P._Mnode()) = _Acc::_Prev(_L._Mnode());//各自前驱地址的赋值
  _Acc::_Prev(_L._Mnode()) = _Acc::_Prev(_F._Mnode());//各自前驱地址的赋值
  _Acc::_Prev(_F._Mnode()) = _S;//把_P的前驱节点地址赋给_F的前驱
}
 else
 {
   insert(_P, _F, _L);//直接插入*this中
   _X.erase(_F, _L); //直接将原来的删除
  }
 
  }
  void _Xran() const//异常处理
  {_THROW(out_of_range, "invalid list<T> subscript"); }

};
     
// list TEMPLATE OPERATORS
template<class _Ty, class _A> inline
bool operator==(const list<_Ty, _A>& _X,
    const list<_Ty, _A>& _Y)
{return (_X.size() == _Y.size()
   && equal(_X.begin(), _X.end(), _Y.begin())); }
template<class _Ty, class _A> inline
bool operator!=(const list<_Ty, _A>& _X,
    const list<_Ty, _A>& _Y)
{return (!(_X == _Y)); }
template<class _Ty, class _A> inline
bool operator<(const list<_Ty, _A>& _X,
      const list<_Ty, _A>& _Y)
{return (lexicographical_compare(_X.begin(), _X.end(),
   _Y.begin(), _Y.end())); }
template<class _Ty, class _A> inline
bool operator>(const list<_Ty, _A>& _X,
      const list<_Ty, _A>& _Y)
{return (_Y < _X); }
template<class _Ty, class _A> inline
bool operator<=(const list<_Ty, _A>& _X,
    const list<_Ty, _A>& _Y)
{return (!(_Y < _X)); }
template<class _Ty, class _A> inline
bool operator>=(const list<_Ty, _A>& _X,
    const list<_Ty, _A>& _Y)
{return (!(_X < _Y)); }

}
//allocator.h

//#include <cstdlib>//包含ptrdiff_t,size_t
//#include <new>   //包含 placement new
typedef int ptrdiff_t;
namespace wei
{ 
	// TEMPLATE FUNCTION _Allocate
	template<class _Ty> inline 
		_Ty *_Allocate(ptrdiff_t _N, _Ty *)
	{
		if (_N < 0)
			_N = 0;
		return ((_Ty *)operator new((ptrdiff_t)_N * sizeof (_Ty))); 
	}
	
	// TEMPLATE FUNCTION _Construct
	template<class _T1, class _T2> inline
		void _Construct(_T1  *_P, const _T2& _V)
	{   
		new ((void*)_P) _T1(_V); 	
	}//placement new,调用T1的构造函数构造对象
	//new(_P) _T1(value);
	
	// TEMPLATE FUNCTION _Destroy
	template<class _Ty> inline
		void _Destroy(_Ty  *_P)
	{   _P->~_Ty(); }
	
	// TEMPLATE CLASS allocator
	template<class _Ty>
		class allocator{
public:
	typedef size_t        size_type;
	typedef  int          difference_type;//ptrdiff_t
	typedef _Ty*          pointer;
	//	typedef const _Ty*    const_pointer;
	typedef _Ty&          reference;
	//	typedef const _Ty&    const_reference;
	typedef _Ty           value_type;
	
	
	pointer address(reference _X) const
	{return (&_X); }//返回对象地址
	
	//	const_pointer address(const_reference _X) const
	//{return (&_X); } //返回常对象地址
	
	pointer allocate(size_type _N, const void *)
	{return (_Allocate((difference_type)_N,(pointer)0)); }
	
	char *_Charalloc(size_type _N)
	{return (_Allocate((difference_type)_N,(char*)0)); }
	
	void deallocate(void* _P, size_type)//释放指针所指空间
	{operator delete(_P); }
	
	void construct(pointer _P, const _Ty& _V)
	{_Construct(_P, _V); }
	
	void destroy(pointer _P)
	{_Destroy(_P); }//释放该类型指针所指的空间
	size_type max_size() const
	{                   //4294967295 /sizeof(_Ty)
		//以整型为例约等于 1073741823
		size_type _N = (size_type)(-1) / sizeof (_Ty);//类型除以-1是该类型中所能表示的最大无符号值
		return (0 < _N ? _N : 1); 
	}
	
	};
	
	//判断是不是用的同一种空间配置器方式进行配置
	template<class _Ty, class _U> inline
		bool operator==(const allocator<_Ty>&, const allocator<_U>&)
	{return (true); }
	template<class _Ty, class _U> inline
		bool operator!=(const allocator<_Ty>&, const allocator<_U>&)
	{return (false); }
}

下面是对list的一些使用测试:

#include <iostream>
#include "List.h"
using namespace std;

int main()
{
	int a[5]={1,2,3,4,5};
	int arr[5]={11,22,33,44,55};
	
	kai::list<int,wei::allocator<int> > d(a,a+5);
	kai::list<int,wei::allocator<int> > e(arr,arr+3);
	
	kai::list<int,wei::allocator<int> >::iterator it,iter;


	d.remove(9);
	it = e.begin();
	it++;
	iter =d.end();
	--iter;
	d.splice(iter,e,it,e.end());


	//d.swap(e);
	d.Print();//这些函数本库中没有我只是为了测试方便自己加上的
	e.Print();
	
	/*  d.splice(e.begin(),d,d.begin(),d.end());//把d的全部拼接到e的前边
	d.Print();
	e.Print();
	d<<99<<88;
	cout<<d;
	
      d.splice(e.begin(),d,1,5);
	  d.Print();
	  e.Print();
	  d.Print();
	  d.RevesPrint();
	   d>>99>>88;
	  cout<<d;
	  d.Print();
			
	d.splice(e.begin(),d,d.begin());//把链表d的第一个元素拼接到e的开头
	d.splice(e.begin(),d,d.Prend());//把链表d的最后一个元素拼接到e的开头
	e.Print();
	d.Print();
	kai::list<int,wei::allocator<int> > g;
	(g>>99).Print();
	g.Print();
			  
	cout<<g;
				
	d.splice(e.begin(),d);//把d拼接到e的前边
	e.Print();
	d.Print();
				  
					
	d.splice(e.begin(),d,d.begin(),d.end());//把d的全部拼接到e的前边
	d.Print();
	e.Print();
					  
						
	d.swap(e);
	d.Print();
	e.Print();
						  
	//list::swap(d,e);
	d.Print();
	e.Print();
							
		/*
	kai::list<int,wei::allocator<int> > b;
	kai::list<int,wei::allocator<int> > c(a,a+5);
	kai::list<int,wei::allocator<int> > d(2,3);
	kai::list<int,wei::allocator<int> > e(c.begin(),c.end());
							  
	kai::list<int,wei::allocator<int> > ab;
	ab=c;//list的赋值函数
	kai::list<int,wei::allocator<int> > ac=b;//list的拷贝构造
	ab.Print();
	ab.clear();
	ab.Print();
								
	d.Print();
	d.resize(9,3);//将d的相同元素扩展到9个
	d.Print();
								  
	c.erase(c.begin());
									
									  
	for(int i=0;i<sizeof(a)/sizeof(*a);++i)
	b.push_back(a[i]);
	b.clear();
										
		*/
	return 0;
											
	 }


版权声明:本文为博主原创文章,未经博主允许不得转载。

STL----<list>

标签:

原文地址:http://blog.csdn.net/kai8wei/article/details/47424573

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!