STL—list
前面我们分析了vector,这篇介绍STL中另一个重要的容器list
list的设计
list由三部分构成:list节点、list迭代器、list本身
list节点
list是一个双向链表,所以其list节点中有前后两个指针。如下:
// list节点
template <typename T>
struct __list_node
{
typedef void* void_pointer;
void_pointer prev; // 指向前一个节点
void_pointer next; // 指向下一个节点
T data; // 节点的值
};
list迭代器
前面我们说过vector是利用其内存分配类型成员给vector分配一大块内存,而其迭代器是原始指针,所以其迭代器的移动就是指针的移动,vector那样通过指针的移动就能得到下一个元素,不需要特别设计。而list是链表结构,链表中每个节点的内存不连续,list的迭代器就是对外隐藏了从一个节点是如何移动到下一个节点的具体细节,使得外部只要将迭代器自增或自减就能得到相邻的节点。
list迭代器只有一个指向链表节点的指针数据成员。如下:
typedef __list_node<T>* link_type;
link_type node; // point to __list_node
下面是迭代器的前置自增和前置自减运算符的源码,可以看到是通过节点的前向和后向指针来完成从一个节点移动到另一个节点:
self& operator++() { node = (link_type)(*node).next; return *this;}
self& operator--() { node = (link_type)(*node).prev; return *this;}
list
和vector一样,list也有个空间配置器的类型成员,通过该类型来为list的每个节点分配内存,并且通过该类型成员将外部指定的节点数目转换为相应节点所需的内存。所以list的内存模型是每个链表节点分配一块单独的内存,然后将每个节点连接起来。而vector的内存模型是分配一大块连续的内存。如下:
// 空间配置器
typedef simple_alloc<list_node, alloc> list_node_allocator;
实际上,list不仅是一个双向链表,而且还是一个环状的双向链表。为了设计的方便,在list中放置一个node指针,该指针指向一个空白节点,该空白节点的下一个节点是链表中起始节点,而链表的尾节点的下一个节点为该空白节点。虽然list底层是一个环状双向链表,但通过这样设计后对外就表现出一个普通的双向链表,符合一般习惯。这样设计还有很多好处,比如快速得到链表的首尾节点。如下。
private:
//指向空白节点
link_type node;
public:
// 通过空白节点node完成
iterator begin() const { return (link_type)(*node).next; }
iterator end() const { return node;}
bool empty() const { return node->next == node; }
下面我们看list内部是如何构造一个链表的。以我们对list的常用使用方法 list<int> lis(10)为例:
首先调用构造函数
explicit list(size_type n)
{
empty_initialize();
insert(begin(), n, T());
}
该构造函数会先调用empty_initialize()为list分配一个空白节点,并设置前向后向指针
void empty_initialize()
{
node = get_node();
node->next = node;
node->prev = node;
}
link_type get_node() { return list_node_allocator::allocate();}
然后构造函数会循环以插入相应个数的链表节点,每次插入时会分配一个节点大小的内存,然后对这块内存初始化,注意插入位置是在指定位置之前插入。由于list的内存模型和vector内存模型的区别,vector每次插入时由于可能会造成内存的重新配置,会造成原先所有的迭代器失效。而list的插入只是为新节点分配内存,并将其添加到链表中,对链表中其他节点的内存不会造成影响,所以list的插入则不会引起迭代器失效。如下。
template <typename T>
void
list<T>::insert(iterator position, size_type n, const T& x)
{
for (; n > ; --n)
insert(position, x);
}
template <typename T>
void
list<T>::insert(iterator position, const T& x)//posiiton之前插入
{
link_type tmp = create_node(x);
tmp->next = position.node;
tmp->prev = position.node->prev;
(link_type(position.node->prev))->next = tmp;
position.node->prev = tmp;
}
link_type create_node(const T& x)
{
link_type p = get_node();
construct(&p->data, x);
return p;
}
link_type get_node() { return list_node_allocator::allocate();}
(全文完)
STL—list的更多相关文章
- 详细解说 STL 排序(Sort)
0 前言: STL,为什么你必须掌握 对于程序员来说,数据结构是必修的一门课.从查找到排序,从链表到二叉树,几乎所有的算法和原理都需要理解,理解不了也要死记硬背下来.幸运的是这些理论都已经比较成熟,算 ...
- STL标准模板库(简介)
标准模板库(STL,Standard Template Library)是C++标准库的重要组成部分,包含了诸多在计算机科学领域里所常见的基本数据结构和基本算法,为广大C++程序员提供了一个可扩展的应 ...
- STL的std::find和std::find_if
std::find是用来查找容器元素算法,但是它只能查找容器元素为基本数据类型,如果想要查找类类型,应该使用find_if. 小例子: #include "stdafx.h" #i ...
- STL: unordered_map 自定义键值使用
使用Windows下 RECT 类型做unordered_map 键值 1. Hash 函数 计算自定义类型的hash值. struct hash_RECT { size_t operator()(c ...
- C++ STL简述
前言 最近要找工作,免不得要有一番笔试,今年好像突然就都流行在线笔试了,真是搞的我一塌糊涂.有的公司呢,不支持Python,Java我也不会,C有些数据结构又有些复杂,所以是时候把STL再看一遍了-不 ...
- codevs 1285 二叉查找树STL基本用法
C++STL库的set就是一个二叉查找树,并且支持结构体. 在写结构体式的二叉查找树时,需要在结构体里面定义操作符 < ,因为需要比较. set经常会用到迭代器,这里说明一下迭代器:可以类似的把 ...
- STL bind1st bind2nd详解
STL bind1st bind2nd详解 先不要被吓到,其实这两个配接器很简单.首先,他们都在头文件<functional>中定义.其次,bind就是绑定的意思,而1st就代表fir ...
- STL sort 函数实现详解
作者:fengcc 原创作品 转载请注明出处 前几天阿里电话一面,被问到STL中sort函数的实现.以前没有仔细探究过,听人说是快速排序,于是回答说用快速排序实现的,但听电话另一端面试官的声音,感觉不 ...
- STL的使用
Vector:不定长数组 Vector是C++里的不定长数组,相比传统数组vector主要更灵活,便于节省空间,邻接表的实现等.而且它在STL中时间效率也很高效:几乎与数组不相上下. #include ...
- [C/C++] C/C++延伸学习系列之STL及Boost库概述
想要彻底搞懂C++是很难的,或许是不太现实的.但是不积硅步,无以至千里,所以抽时间来坚持学习一点,总结一点,多多锻炼几次,相信总有一天我们会变得"了解"C++. 1. C++标准库 ...
随机推荐
- pc网页到移动端怎么自动加载适应移动端的css。
1.通过link标签判断加入 以前听说过在link标签中加media = "handheld",但这个用到安卓或苹果都不管用,后来尝试以下方法,是管用的. <link hre ...
- kali高速更新源以及主题修改方法
文章不小心删了~这是我以前写的文章了了.实用性较强,所以现在补回来! 安装完kali之后,需要对软件进行一次整体更新:apt-get update & apt-get upgrade 但是,先 ...
- asp.net core 教程(四)-项目结构
Asp.Net Core-项目结构 Asp.Net Core-项目结构 案例 在这一章,我们将讨论 ASP.NET Core项目在文件系统上的组成方式以及不同的文件和目录都是如何协同工作的. 让我们打 ...
- (转)让浏览器支持Webp
转载:https://segmentfault.com/a/1190000005898538?utm_source=tuicool&utm_medium=referral Webp介绍 web ...
- CPU-Z五大主要功能及使用方法初步了解
CPU-Z这款软件除了具有查看CPU温度这个功能之外,还有很多其他的功能.今天就和小编一起去看看CPU-Z的5大功能以及他们的使用方法吧! CPU信息标签页 CPU-Z介绍: CPU-Z是一款著名的免 ...
- EntityFramework Core映射关系详解
前言 Hello,开始回归开始每周更新一到两篇博客,本节我们回归下EF Core基础,来讲述EF Core中到底是如何映射的,废话少说,我们开始. One-Many Relationship(一对多关 ...
- Scrapy中使用cookie免于验证登录和模拟登录
Scrapy中使用cookie免于验证登录和模拟登录 引言 python爬虫我认为最困难的问题一个是ip代理,另外一个就是模拟登录了,更操蛋的就是模拟登录了之后还有验证码,真的是不让人省心,不过既然有 ...
- angularJS directive详解(自定义指令)
Angularjs指令定义的API AngularJs的指令定义大致如下 其中return返回的对象包含很多参数,下面一一说明 1.restrict (字符串)可选参数,指明指令在DOM里面以什么形式 ...
- Tomcat网页加载速度过慢的解决方法
可以vim conf/server.xml,在# OS specific support. $var _must_ be set to either true or false.下添加: JAVA_ ...
- Structured-Streaming之窗口操作
Structured Streaming 之窗口事件时间聚合操作 Spark Streaming 中 Exactly Once 指的是: 每条数据从输入源传递到 Spark 应用程序 Exactly ...