【STL源码剖析读书笔记】【第4章】序列式容器之list和slist

2023-10-18 05:48

本文主要是介绍【STL源码剖析读书笔记】【第4章】序列式容器之list和slist,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、list

1、list概述

list是双向链表,对于任何位置的元素插入或元素移除,list永远是常数时间。

2、list的节点

list本身和list节点是不同的数据结构,需要分开设计。STL list的节点结构:

template <class T>
struct __list_node {typedef void* void_pointer;void_pointer next;void_pointer prev;T data;
};
3、 list 的迭代器

STL list是一个双向链表,迭代器必须具备前移、后移的能力,list提供的是Bidirectional Iteratorslist的插入操作和接合操作都不会导致原来的list迭代器失效。


4、list的数据结构

STL list是一个环状双向链表,只需一个指针就可以表现整个链表。

template<class T,class Alloc = alloc> //缺省使用alloc为配置器:w
class list{
protected :typedef	__list_node<T> list_node ;
public  :typedef	list_node* link_type ;
protected :link_type node ; //只要一个指针,便可以表示整个环状双向链表
};
如果让指针 node 指向刻意置于尾端的一个空白节点, node 便能符合 STL 对于“前闭后开”区间的要求,成为 last 迭代器。


5、insert()函数

insert()是一个重载函数,最简单的一种如下:

iterator insert(iterator position, const T& x){//在迭代器position所指位置插入一个节点,内容为xlink_type tmp = create_node(x);tmp->next = position.node;tmp->prev = position.node->node;(link_type(position.node->prev))->next = tmp;return tmp;
}

6、push_back()函数

将新元素插入于list尾端,内部调用insert()函数

void push_back(const T& x){
insert(end(),x);
}
7、 push_front() 函数

将新元素插入于list头端,内部调用insert()函数

void push_front(const T&x){
insert(begin(),x);
}
8、 erase() 函数

iterator erase(iterator position){
link_type next_node=link_type(position.node->next);
link_type prev_node=link_type(position.node->prev_nodext);
prev_node->next=next_node;
next_node->prev=prev_node;
destroy_node(position.node);
return iterator(next_node);
}

9、pop_front()函数

移除头结点,内部调用erase()函数

void pop_front(){
erase(begin());
}
10、 pop_back() 函数

移除尾结点,内部调用erase()函数

void pop_back(){
iterator i=end();
erase(--i);
}
11、 transfer() 函数

将某连续范围的元素迁移到某个特定位置之前。

void transfer(iterator position, iterator first, iterator last) {if (position != last) {(*(link_type((*last.node).prev))).next = position.node; //(1)(*(link_type((*first.node).prev))).next = last.node;    //(2)(*(link_type((*position.node).prev))).next = first.node;//(3)link_type tmp = link_type((*position.node).prev);       //(4)(*position.node).prev = (*last.node).prev;              //(5)(*last.node).prev = (*first.node).prev;                 //(6)(*first.node).prev = tmp;                               //(7)}}

二、slist

1slist概述

SGI STL另提供一个单向链表slistslistlist的主要差别在于,前者的迭代器属于单向的Forward Iterator,后者的迭代器属于双向的BidirectionalIterator

根据STL的习惯,插入操作会将新元素插入于指定位置之前。作为单向链表,slist没有任何方便的方法可以回头定出前一个位置,因此它必须从头找起。

2、slist的节点

3、slist的迭代器


4、slist的数据结构

template<class T, class Alloc = alloc>
class slist
{
public :typedef	T	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<T,T&,T*>	iterator ;typedef	__slist_iterator<T,const T&,const T*> const_iterator ;private :typedef	__slist_node<T>	list_node ;typedef	__slist_node_base	list_node_base ;typedef	__slist_iterator_base	iterator_base ;typedef simple_alloc<list_node,Alloc> list_node_allocator ;static	list_node* create_node(const value_type& x){list_node* node = list_node_allocator:;allocate() ; //配置空间__STL_TRY{construct(&node->data,x) ;node->next = 0 ;}__STL_UNWIND(list_node_allocator:;deallocate(node)) ;return node ;}static void destroy_node(list_node* node){destroy(&node->data) ; //将元素析构	list_node_allocator::deallocate(node) ; //释放空间}private :list_node_base head  ; //头部。注意,它不是指针,是实物public:slist() {head.next = 0 ;} ~slist(){clear() ;}public :iterator begin() {return iterator((list_node*)head.next) ;}iterator end() {return iteator(0) ;}iterator size() {const __slist_size(head.next) ;}bool empty() const {return head.next == 0 ;} //两个slist互换:只要将head交换互指即可void swap(slist &L){list_node_base* tmp = head.next;head.next = L.head.next ;L.head.next = tmp ;}public ://取头部元素reference front() {return ((list_node*)head.next)->data ;}//从头部插入元素(新元素成为slist的第一个元素)void push_front(const value_type& x){__slist_make_link(&head,create_node(x)) ;}//注意,没有push_back()//从头部取走元素(删除之)。修改headvoid pop_front(){list_node* node = (list_node*)head.next ;head.next = node->next ;destroy_node(node);}.....
}  ;
5、 slist 的元素操作





这篇关于【STL源码剖析读书笔记】【第4章】序列式容器之list和slist的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/230578

相关文章

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

如何将Tomcat容器替换为Jetty容器

《如何将Tomcat容器替换为Jetty容器》:本文主要介绍如何将Tomcat容器替换为Jetty容器问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat容器替换为Jetty容器修改Maven依赖配置文件调整(可选)重新构建和运行总结Tomcat容器替

java streamfilter list 过滤的实现

《javastreamfilterlist过滤的实现》JavaStreamAPI中的filter方法是过滤List集合中元素的一个强大工具,可以轻松地根据自定义条件筛选出符合要求的元素,本文就来... 目录1. 创建一个示例List2. 使用Stream的filter方法进行过滤3. 自定义过滤条件1. 定

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

Python容器类型之列表/字典/元组/集合方式

《Python容器类型之列表/字典/元组/集合方式》:本文主要介绍Python容器类型之列表/字典/元组/集合方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 列表(List) - 有序可变序列1.1 基本特性1.2 核心操作1.3 应用场景2. 字典(D

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory