STL学习——Slist篇
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篇相关推荐
- STL学习——RB-tree篇
STL学习--RB-tree篇 简介 RB-tree(红黑树)是一棵平衡二叉搜索树,它需要满足以下规则: 1)每个节点不是红色就是黑色: 2)根节点为黑色: 3)如果节点为红,其子节点必须为黑: 4) ...
- STL学习_配接器篇
STL学习_配接器篇 定义 配接器(Adapter)在STL组件的灵活组合运用功能上,扮演着轴承.转换器的角色.它事实上是一种设计模式.即将一个class的接口转换为另一个class的接口,使原本因接 ...
- C++ STL学习笔记
C++ STL学习笔记一 为何要学习STL: 数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C ...
- MongoDB学习第一篇 --- Mac下使用HomeBrew安装MongoDB
2019独角兽企业重金招聘Python工程师标准>>> MongoDB学习第一篇 --- Mac下使用HomeBrew安装MongoDB 0.确保mac已经安装了HomeBrew ( ...
- 深度学习实战篇-基于RNN的中文分词探索
深度学习实战篇-基于RNN的中文分词探索 近年来,深度学习在人工智能的多个领域取得了显著成绩.微软使用的152层深度神经网络在ImageNet的比赛上斩获多项第一,同时在图像识别中超过了人类的识别水平 ...
- JNI学习开始篇 基础知识 数据映射及学习资料收集
JNI学习开始篇 基础知识 数据映射及学习资料收集 JNI介绍 JNI(Java Native Interface) ,Java本地接口. 用Java去调用其他语言编写的程序,比如C或C++. JNI ...
- java helloworld代码_java学习应用篇|逃不掉的HelloWorld
本文知识点 1.表白不是发起进攻的冲锋号,而是吹响胜利的号角 2.除了爱情不讲道理,公理也不讲道理 3.这世界,离了javac,也是可以运行的! 4.Hello,寺水 写程序并不是写代码 看前面啰啰嗦 ...
- Mongodb学习(安装篇): 在centos下的安装
安装篇 ###下载解压文件 [root@192 lamp]# wget http://fastdl.mongodb.org/linux/mongodb-linux-i686- 2.2.2.tgz ## ...
- [Django]模型学习记录篇--基础
模型学习记录篇,仅仅自己学习时做的记录!!! 实现模型变更的三个步骤: 修改你的模型(在models.py文件中). 运行python manage.py makemigrations ,为这些修改创 ...
最新文章
- Matlab-贪心/贪婪算法
- 你需要知道的Android View的布局
- Linux Shell编程实战---以逆序形式打印行
- Deep Learning Face Representation by Joint Identification-Verification
- [USACO08DEC]在农场万圣节Trick or Treat on the Farm
- 关于yii2学习笔记:gii的使用
- python html表格模版,python-如何使用模板(例如Jinja2)将列值列表呈现到表中
- 如何对接线上支付接口
- linux下制作dos启动u盘启动,linux dos启动盘怎样做
- HEVC学习(十二) —— CU的最终划分
- 服务器地址显示169.254,IP地址是169.254开头的
- linux的的符号,Linux 常见特殊符号
- linux触摸板设置密码程序6,Touchegg:Linux上触摸板/屏的多指手势
- CentOS7下安装google chrome浏览器
- IBM 能靠 2nm 芯片翻身吗?
- 深度学习和TensorFlow学习资源(书籍、文档和视频)
- [ 数据结构 - C++] AVL树原理及实现
- python正则表达式查找(findall)
- 小学计算机打字基础知识教案绿色圃,小学信息技术公开课教案智能ABC输入法教学设计与反思...
- 新书上市|历经十年,这本9.2分的数学经典终于再版了!
热门文章
- 区块链基础理论模拟试卷四
- mysql批量清空表数据脚本
- 易画办公助手 v7.0 免费
- java pjax_PJAX,站点加速之翼
- Android如何愉快的使用Spinner列表选择框
- 26.学习Camera之——PDAF(相位对焦)的基本原理
- SpringBoot学习笔记总结—动力节点王鹤
- 恶人传时长_恶人传中国什么时候上映,恶人传怎么样才看到,恶人传剧情介绍...
- MACHENIKE 机械师F117 B1 8代i7独显全面屏游戏本轻薄笔记本电脑怎么样?
- 2023.6.8每日一题