STL list容器

一、operator++()和operator++(int)

这次认真看了一下list中的重载运算,发现了对operator++()和operator++(int)进行了重载,一时没有搞清楚这两者的区别,其实就是分别重载++前缀和++后缀,正好就以list中迭代器的的源码作为例子,分析一下++前缀和后缀有什么区别

 _Self& operator++() { 
    this->_M_incr();
    return *this;
  }
  _Self operator++(int) { 
    _Self __tmp = *this;//创建临时变量存储当前值,并最后返回	
    this->_M_incr();//_M_incr函数就是找到list的下一个节点
    return __tmp;
  }

可以看到++前缀是先将当前变量的值保存在一个临时变量中,然后+1,但返回的是那个临时变量,所以出现了先赋值再加1的效果
而++后缀则是将当前变量直接+1,并返回,所以出现先加1再赋值的效果。

二、list数据结构

stl中的list数据结构就是平时自己写的那种list,源码如下;

struct _List_node_base {    //前驱后驱指针
  _List_node_base* _M_next;
  _List_node_base* _M_prev;
};

template <class _Tp>
struct _List_node : public _List_node_base {
  _Tp _M_data;   //数据,并且继承了前驱后驱指针
/*每一个list类成员中都只有一个成员变量,就是链表头*/
class _List_base //list的父类
{
...//其他内容省略
protected:
  _List_node<_Tp>* _M_node;//头结点,不存放真实数据
}
};

在创建一个list的时候,在构造函数中会创建这个头结点,并且让前驱和后继指针指向自己。源码如下:

  _List_base(const allocator_type& __a) : _Base(__a) {
    _M_node = _M_get_node();
    _M_node->_M_next = _M_node;
    _M_node->_M_prev = _M_node;
  }//这是list的父类的够赞函数

如下图所示,注意stl中list是环形双向链表,所以在空链表中前驱和后继指针指向自己。
在这里插入图片描述
在这里插入图片描述

三、list的迭代器

list的迭代器是属于bidirectional_iterator迭代器,拥有++,–,*,->操作符,但是没有+n,-n这样的操作符,所以就是比Random access iterator弱的地方。
并且这个迭代器中有存储的是_List_node_base类型的指针,也就是list中的前驱和后继结构体。
看了两个容器中的迭代器以后,我觉得迭代器最重要的就是几个点

  • 迭代器的类型,不同类型的迭代器代表拥有不同的操作运算符,其中Random access iterator所拥有的操作运算符最多,具体可以看前面的博客。
  • 迭代器中存储的数据,比如list迭代器中就存储的不是list指针,而是_List_node_base指针,不过其实还是传入的是_List_node指针,只是转换成了父指针,我认为是避免在迭代器类中对数据进行误操作。

四、list中关键算法

①在list的操作函数中,最主要的函数是三个,insert,erase和transfer。其他函数都是对这个函数的封装。

  iterator insert(iterator __position, const _Tp& __x) {//在指定位置插入结点,结点数据为__x
    _Node* __tmp = _M_create_node(__x);//新建一个结点,然后插入
    __tmp->_M_next = __position._M_node;
    __tmp->_M_prev = __position._M_node->_M_prev;
    __position._M_node->_M_prev->_M_next = __tmp;
    __position._M_node->_M_prev = __tmp;
    return __tmp;//这里__tmp是_Node类型指针,也就是_List_node类型,但是返回值是一个迭代器,
//个人认为由于迭代器中也就是一个_List_node_base类型的指针,所以_List_node指针可以安全地强转为迭代器类型。
  }
  iterator erase(iterator __position) {//删除__position位置的元素
    _List_node_base* __next_node = __position._M_node->_M_next;//保存待删除结点的前一个结点
    _List_node_base* __prev_node = __position._M_node->_M_prev;//保存待删除结点的后一个结点
    _Node* __n = (_Node*) __position._M_node;//获取迭代器所指向的结点
    __prev_node->_M_next = __next_node;//连接待删除结点的前一个结点和后一个结点
    __next_node->_M_prev = __prev_node;
    _Destroy(&__n->_M_data);//调用析构函数
    _M_put_node(__n);//删除结点
    return iterator((_Node*) __next_node);//返回指向该迭代器
  }
  void transfer(iterator __position, iterator __first, iterator __last) {
    if (__position != __last) {
	//把first到last的部分移动到position前面
	
      // Remove [first, last) from its old position.
      //改变后驱指针
      __last._M_node->_M_prev->_M_next     = __position._M_node;
      __first._M_node->_M_prev->_M_next    = __last._M_node;
      __position._M_node->_M_prev->_M_next = __first._M_node; 

      // Splice [first, last) into its new position.
      //改变前驱指针
      _List_node_base* __tmp      = __position._M_node->_M_prev;
      __position._M_node->_M_prev = __last._M_node->_M_prev;
      __last._M_node->_M_prev     = __first._M_node->_M_prev; 
      __first._M_node->_M_prev    = __tmp;
    }
  }

过程如图所示
在这里插入图片描述
②list中一些成员函数的介绍
这些函数都是依靠上面三种函数的封装,就不一一介绍了,但是对这些函数不熟悉,所以介绍一下使用方法

/*将值为value的所有元素删除*/
template <class _Tp, class _Alloc> void list<_Tp, _Alloc>::remove(const _Tp& __value)
/*将list __x和使用merge函数的list进行融合,并且要求两个list都是按递增顺序排列,因为融合的时候也会按照递增顺序融合元素*/
template <class _Tp, class _Alloc> void list<_Tp, _Alloc>::merge(list<_Tp, _Alloc>& __x)
/*整个链表__x插入到__position前面*/
void splice(iterator __position, list& __x) 
/*把参数list中__i位置的元素移动到__position的位置*/
void splice(iterator __position, list&, iterator __i)

③list的sort成员函数
STL算法有提供一个sort通用函数,但是只接受Random access iterator迭代器,所以list不能使用,只能使用自己定义的sort函数,像vector就可以使用。
list中的sort函数使用了非递归快排思想,具体过程可以参考这篇博客,讲解非常清晰https://blog.csdn.net/chenhanzhun/article/details/39337331

注意:vector迭代器可能因为扩容换存储空间,而失效,但是list的迭代器不存在这种情况,除非是删除节点,才有可能失效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值