STL学习——Slist篇

  • 简介

    STL中List是双向链表,而Slist是单向链表。它们的区别:Slist的迭代器是单向的Forward Iterator,而list的迭代器是双向的Bidirectional Iterator。Slist所耗用的空间更小,操作更快。它们共同的特点是,插入、移除、接合等操作并不会造成原有的迭代器失效。slist插入时,需要从前遍历,找到插入点的位置。为了更快插入,提供了insert_after,erase_after。slist提供push_front()操作,故其元素次序与元素插入顺序相反。

  • 节点与操作

    slist节点和迭代器设计上,使用了继承关系,故较复杂。下面是其节点信息。

    // 单向链表的节点基本结构
    struct _Slist_node_base
    {_Slist_node_base* _M_next;
    };
    // 单向链表的节点结构
    template <class _Tp>
    struct _Slist_node : public _Slist_node_base
    {_Tp _M_data;
    };
    // 全局函数:已知某一节点,插入新节点于其后
    inline _Slist_node_base*
    __slist_make_link(_Slist_node_base* __prev_node,_Slist_node_base* __new_node)
    {__new_node->_M_next = __prev_node->_M_next;    // 令new节点的下一节点为prev节点的下一节点__prev_node->_M_next = __new_node;return __new_node;
    }
    // 查找node节点的前一个节点
    inline _Slist_node_base*
    __slist_previous(_Slist_node_base* __head,const _Slist_node_base* __node)
    {while (__head && __head->_M_next != __node)    // 从头遍历,查找node的前一个节点__head = __head->_M_next;return __head;
    }
    // 查找node节点的前一个节点
    inline const _Slist_node_base*
    __slist_previous(const _Slist_node_base* __head,const _Slist_node_base* __node)
    {while (__head && __head->_M_next != __node)    // 从头遍历,查找node的前一个节点__head = __head->_M_next;return __head;
    }
    // 将before_first与before_after之间的节点插入到pos后面
    inline void __slist_splice_after(_Slist_node_base* __pos,_Slist_node_base* __before_first,_Slist_node_base* __before_last)
    {if (__pos != __before_first && __pos != __before_last) {// 记录before_first的next节点_Slist_node_base* __first = __before_first->_M_next;// 记录pos的next节点_Slist_node_base* __after = __pos->_M_next;// 先将befor_first与before_last前后挂接在一起__before_first->_M_next = __before_last->_M_next;// 将before_first的下一个节点挂接在pos的后面__pos->_M_next = __first;// 将before_last的next与pos_next进行挂接 __before_last->_M_next = __after;}
    }
    // 链表的翻转操作
    inline _Slist_node_base* __slist_reverse(_Slist_node_base* __node)
    {_Slist_node_base* __result = __node;__node = __node->_M_next;__result->_M_next = 0;while(__node) {_Slist_node_base* __next = __node->_M_next;    // 记住下一个节点__node->_M_next = __result;     // 将当前节点插入到result节点的最前__result = __node;              // 更新result节点__node = __next;                // 更新node节点}return __result;                  // 返回逆转的链表
    }
    // 全局函数:单向链表的大小(元素个数)
    inline size_t __slist_size(_Slist_node_base* __node)
    {size_t __result = 0;for ( ; __node != 0; __node = __node->_M_next)++__result;return __result;
    }// 单向链表的迭代器基本结构
    struct _Slist_iterator_base
    {typedef size_t               size_type;typedef ptrdiff_t            difference_type;typedef forward_iterator_tag iterator_category;     // 注意,单向_Slist_node_base* _M_node;                          // 指向节点基本结构_Slist_iterator_base(_Slist_node_base* __x) : _M_node(__x) {}void _M_incr() { _M_node = _M_node->_M_next; }      // 前进一个节点bool operator==(const _Slist_iterator_base& __x) const {   // 判断链表是否相等return _M_node == __x._M_node;}bool operator!=(const _Slist_iterator_base& __x) const {   // 判断链表是否不相等return _M_node != __x._M_node;}
    };
    // 单向链表的迭代器结构
    template <class _Tp, class _Ref, class _Ptr>
    struct _Slist_iterator : public _Slist_iterator_base
    {typedef _Slist_iterator<_Tp, _Tp&, _Tp*>             iterator;typedef _Slist_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;typedef _Slist_iterator<_Tp, _Ref, _Ptr>             _Self;typedef _Tp              value_type;typedef _Ptr             pointer;typedef _Ref             reference;typedef _Slist_node<_Tp> _Node;_Slist_iterator(_Node* __x) : _Slist_iterator_base(__x) {}// 调用slist<T>::end()时会造成__slist_iterator(0),于是调用上述函数_Slist_iterator() : _Slist_iterator_base(0) {}     // 产生一个暂时对象,引发ctor_Slist_iterator(const iterator& __x) : _Slist_iterator_base(__x._M_node) {}reference operator*() const { return ((_Node*) _M_node)->_M_data; }
    #ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
    #endif /* __SGI_STL_NO_ARROW_OPERATOR */_Self& operator++(){_M_incr();     // 前进一个节点return *this;}_Self operator++(int){_Self __tmp = *this;_M_incr();     // 前进一个节点return __tmp;}// 注意没有实现operator--,因为这是一个forward iterator
    };template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
    class slist : private _Slist_base<_Tp,_Alloc>
    {__STL_CLASS_REQUIRES(_Tp, _Assignable);private:typedef _Slist_base<_Tp,_Alloc> _Base;
    public:typedef _Tp                value_type;typedef value_type*       pointer;typedef const value_type* const_pointer;typedef value_type&       reference;typedef const value_type& const_reference;typedef size_t            size_type;typedef ptrdiff_t         difference_type;typedef _Slist_iterator<_Tp, _Tp&, _Tp*>             iterator;typedef _Slist_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;typedef typename _Base::allocator_type allocator_type;allocator_type get_allocator() const { return _Base::get_allocator(); }private:typedef _Slist_node<_Tp>      _Node;typedef _Slist_node_base      _Node_base;typedef _Slist_iterator_base  _Iterator_base;_Node* _M_create_node(const value_type& __x) {_Node* __node = this->_M_get_node();    // 配置空间__STL_TRY {construct(&__node->_M_data, __x);     // 构造元素__node->_M_next = 0;}__STL_UNWIND(this->_M_put_node(__node));return __node;}public:explicit slist(const allocator_type& __a = allocator_type()) : _Base(__a) {}slist(size_type __n, const value_type& __x,const allocator_type& __a =  allocator_type()) : _Base(__a){ _M_insert_after_fill(&this->_M_head, __n, __x); }explicit slist(size_type __n) : _Base(allocator_type()){ _M_insert_after_fill(&this->_M_head, __n, value_type()); }#ifdef __STL_MEMBER_TEMPLATES// We don't need any dispatching tricks here, because _M_insert_after_range// already does them.template <class _InputIterator>slist(_InputIterator __first, _InputIterator __last,const allocator_type& __a =  allocator_type()) : _Base(__a){ _M_insert_after_range(&this->_M_head, __first, __last); }#else /* __STL_MEMBER_TEMPLATES */slist(const_iterator __first, const_iterator __last,const allocator_type& __a =  allocator_type()) : _Base(__a){ _M_insert_after_range(&this->_M_head, __first, __last); }slist(const value_type* __first, const value_type* __last,const allocator_type& __a =  allocator_type()) : _Base(__a){ _M_insert_after_range(&this->_M_head, __first, __last); }
    #endif /* __STL_MEMBER_TEMPLATES */slist(const slist& __x) : _Base(__x.get_allocator()){ _M_insert_after_range(&this->_M_head, __x.begin(), __x.end()); }slist& operator= (const slist& __x);~slist() {}...// 两个slist互换:只要将head交换互指即可。void swap(slist& __x){ __STD::swap(this->_M_head._M_next, __x._M_head._M_next); }public:reference front() { return ((_Node*) this->_M_head._M_next)->_M_data; }const_reference front() const { return ((_Node*) this->_M_head._M_next)->_M_data; }// 从头部插入元素(新元素成为slist的第一个元素)void push_front(const value_type& __x)   {__slist_make_link(&this->_M_head, _M_create_node(__x));}void push_front() { __slist_make_link(&this->_M_head, _M_create_node()); }// 注意:没有push_back()// 从头部取走元素(删除之)。修改headvoid pop_front() {_Node* __node = (_Node*) this->_M_head._M_next;this->_M_head._M_next = __node->_M_next;destroy(&__node->_M_data);this->_M_put_node(__node);}
    
  • 参考文献

    STL源码剖析——侯捷

    STL源码

STL学习——Slist篇相关推荐

  1. STL学习——RB-tree篇

    STL学习--RB-tree篇 简介 RB-tree(红黑树)是一棵平衡二叉搜索树,它需要满足以下规则: 1)每个节点不是红色就是黑色: 2)根节点为黑色: 3)如果节点为红,其子节点必须为黑: 4) ...

  2. STL学习_配接器篇

    STL学习_配接器篇 定义 配接器(Adapter)在STL组件的灵活组合运用功能上,扮演着轴承.转换器的角色.它事实上是一种设计模式.即将一个class的接口转换为另一个class的接口,使原本因接 ...

  3. C++ STL学习笔记

    C++ STL学习笔记一 为何要学习STL: 数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C ...

  4. MongoDB学习第一篇 --- Mac下使用HomeBrew安装MongoDB

    2019独角兽企业重金招聘Python工程师标准>>> MongoDB学习第一篇 --- Mac下使用HomeBrew安装MongoDB 0.确保mac已经安装了HomeBrew ( ...

  5. 深度学习实战篇-基于RNN的中文分词探索

    深度学习实战篇-基于RNN的中文分词探索 近年来,深度学习在人工智能的多个领域取得了显著成绩.微软使用的152层深度神经网络在ImageNet的比赛上斩获多项第一,同时在图像识别中超过了人类的识别水平 ...

  6. JNI学习开始篇 基础知识 数据映射及学习资料收集

    JNI学习开始篇 基础知识 数据映射及学习资料收集 JNI介绍 JNI(Java Native Interface) ,Java本地接口. 用Java去调用其他语言编写的程序,比如C或C++. JNI ...

  7. java helloworld代码_java学习应用篇|逃不掉的HelloWorld

    本文知识点 1.表白不是发起进攻的冲锋号,而是吹响胜利的号角 2.除了爱情不讲道理,公理也不讲道理 3.这世界,离了javac,也是可以运行的! 4.Hello,寺水 写程序并不是写代码 看前面啰啰嗦 ...

  8. Mongodb学习(安装篇): 在centos下的安装

    安装篇 ###下载解压文件 [root@192 lamp]# wget http://fastdl.mongodb.org/linux/mongodb-linux-i686- 2.2.2.tgz ## ...

  9. [Django]模型学习记录篇--基础

    模型学习记录篇,仅仅自己学习时做的记录!!! 实现模型变更的三个步骤: 修改你的模型(在models.py文件中). 运行python manage.py makemigrations ,为这些修改创 ...

最新文章

  1. Matlab-贪心/贪婪算法
  2. 你需要知道的Android View的布局
  3. Linux Shell编程实战---以逆序形式打印行
  4. Deep Learning Face Representation by Joint Identification-Verification
  5. [USACO08DEC]在农场万圣节Trick or Treat on the Farm
  6. 关于yii2学习笔记:gii的使用
  7. python html表格模版,python-如何使用模板(例如Jinja2)将列值列表呈现到表中
  8. 如何对接线上支付接口
  9. linux下制作dos启动u盘启动,linux dos启动盘怎样做
  10. HEVC学习(十二) —— CU的最终划分
  11. 服务器地址显示169.254,IP地址是169.254开头的
  12. linux的的符号,Linux 常见特殊符号
  13. linux触摸板设置密码程序6,Touchegg:Linux上触摸板/屏的多指手势
  14. CentOS7下安装google chrome浏览器
  15. IBM 能靠 2nm 芯片翻身吗?
  16. 深度学习和TensorFlow学习资源(书籍、文档和视频)
  17. [ 数据结构 - C++] AVL树原理及实现
  18. python正则表达式查找(findall)
  19. 小学计算机打字基础知识教案绿色圃,小学信息技术公开课教案智能ABC输入法教学设计与反思...
  20. 新书上市|历经十年,这本9.2分的数学经典终于再版了!

热门文章

  1. 区块链基础理论模拟试卷四
  2. mysql批量清空表数据脚本
  3. 易画办公助手 v7.0 免费
  4. java pjax_PJAX,站点加速之翼
  5. Android如何愉快的使用Spinner列表选择框
  6. 26.学习Camera之——PDAF(相位对焦)的基本原理
  7. SpringBoot学习笔记总结—动力节点王鹤
  8. 恶人传时长_恶人传中国什么时候上映,恶人传怎么样才看到,恶人传剧情介绍...
  9. MACHENIKE 机械师F117 B1 8代i7独显全面屏游戏本轻薄笔记本电脑怎么样?
  10. 2023.6.8每日一题