简介

forwrad_list字面意思为前向列表,但实际上它是一种单向列表,只能从单一方向遍历。

单向链表实现

forward_list内部是用单向列表实现的,并且设计该库的时候就是以近乎手写的单向链表的运行效率(时间上和空间上)为目的的。 这导致了它是唯一一个C++标准库容器中没有size成员函数的容器, 因为维护这样一个信息会造成效率上的轻微损失。

作为单向链表,它有以下几个属性:

  • 潜在可能的非连续内存分配
  • 线性时间的元素位置获取
  • 常数时间的元素插入、删除、移动

与list的共性

因为它们的内部实现都是通过链表(不管是单链表还是双链表),所以forwrd_list类模版具有一些与list相同的特殊函数:

  • splice_after
  • remove、remove_if
  • unique
  • merge
  • sort
  • reverse

与list的差异

明显的,forward_list是单向链表,内部只维护了单向遍历的信息。 因此,forward_list的迭代器是前向迭代器(forward intertor)。

除此之外,它们的插入操作也有明显的不同,具体体现在传入的迭代器上:

  • list::insert:在传入的迭代器之前插入。
  • forward_list::insert:在传入的迭代器之后插入。

我们来看,为什么标准库要放弃接口语义的一致性,采用不一样的接口设计。

节点修改策略

单向 VS 双向

典型的链表分单向和双向,基本上每一个方向上都需要额外的空间来保存顺序信息(即前一个和后一个元素)。 双向链表保存有两个方向的链接, 而单向链表只有一个方向。

节点修改

当涉及到链表节点的修改时,例如插入、移动等,问题就变得明显了:对于链表来说,修改单个节点实际上涉及到3个节点的信息----当前节点、前驱节点lis、后继节点(修改前后节点的前后节点的链接信息是必要的)。

但是,可以更简单点:双向链表的前驱和后继信息可以间接地通过当前节点得到,因为当前节点有足够的信息 。也就是说,在修改节点时,我只要传入该节点就可以了;而单向链表单个节点可以通过链接信息获得后继节点

传入前驱节点迭代器

实际上,forward_list库做得更好,它的相关接口只需要我们传入一个节点迭代器。 这些接口包括(分别对应常见的非after版本):

  • insert_after
  • emplace_after
  • erase_after

那么这怎么做到的呢? forward_list的策略是----传入前驱节点的迭代器。 这样一来,所有需要的节点信息都能够直接间接地得到。 Great!

但是这也有一个问题:怎么在头部插入一个元素呢?毕竟头节点没有前驱节点。 哈哈,这就是为什么这个类模版提供了两个非常奇怪的函数, 它们是专门为上述三个函数提供服务的(-_-):

  • before_begin
  • before_cbegin

所以现在你也知道了,为什么随笔开头的示意图有一个灰色的节点了吧。ヽ(^o^)ノ

C++ 头文件系列(forward_list)的更多相关文章

  1. C++ 头文件系列(array)

    注意,该头文件仅在C++11中标准才开始出现. 简介 与语言内置的数组一样, array类模版支持几乎所有内置数组包含的特性: 顺序的(sequence) 内存连续的(contiguous stora ...

  2. C++ 头文件系列(queue)

    简介 这个头文件定义了两个跟队列有关的类----quque.priority_queue,分别实现的是队列 和 优先队列这两个概念. 但是与这两个类模版与其它类模版(vector.array等)最大的 ...

  3. C++ 头文件系列(stack)

    简介 该头文件只含有一个类模版stack, 它实现栈的概念,是一个容器适配器(说实话,在写这篇随笔之前我都不知道有这么个类模版). 栈 栈只有一个重要的特性: LIFO(last-in first-o ...

  4. C++ 头文件系列(vector)

    简介 vector头文件包含vector的类模版以及该模版的显示特化版本vector< bool >. vector是C++容器库中非常通用的一种容器,如果你不知道该决定使用哪一种容器,或 ...

  5. C++ 头文件系列(map)

    简介 该头文件包含两个概念相似的容器----map.multimap. 而这两个容器反映的概念就是 映射. 这两个容器 相同 的属性有: 关联性 映射 动态增长 键(Key)唯一性 这两个不相同的属性 ...

  6. C++ 头文件系列(unordered_map、unordered_set)

    简介 很明显,这两个头文件分别是map.set头文件对应的unordered版本. 所以它们有一个重要的性质就是: 乱序 如何乱序 这个unorder暗示着,这两个头文件中类的底层实现----Hash ...

  7. C++ 头文件系列(iterator)

    简介 该头文件围绕迭代器展开,定义了一系列与迭代器有关的概念,但最最最重要的一点就是----它和其它容器一起实现了C++容器的Iterator设计模式. Iterators are a general ...

  8. C++ 头文件系列 (algorithm)

    简介 algorithm头文件是C++的标准算法库,它主要应用在容器上. 因为所有的算法都是通过迭代器进行操作的,所以算法的运算实际上是和具体的数据结构相分离的 ,也就是说,具有低耦合性. 因此,任何 ...

  9. C++ 头文件系列 (bitset)

    简介 该头文件有关位集,实际上是vector 位 位本质上对应bool的概念,只有0或1,true或false两种对立的值. 但很可惜,字节才是机器上最小的存储单元,所以bool基本上是由一个字节大小 ...

随机推荐

  1. mahout第一篇-----Mahout学习路线图

    Mahout学习路线图 前言 Mahout是Hadoop家族中与众不同的一个成员,是基于一个Hadoop的机器学习和数据挖掘的分布式计算框架.Mahout是一个跨学科产品,同时也是我认为Hadoop家 ...

  2. Delphi中建立指定大小字体和读取该字体点阵信息的函数(转)

    源:Delphi中建立指定大小字体和读取该字体点阵信息的函数 Delphi中建立指定大小字体和读取该字体点阵信息的函数 作者:Thermometer Email:  webmaster@daheng- ...

  3. jquery选择器 之 获取父级元素、同级元素、子元素 - yes的日志 - 网易博客

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  4. Ural Vol1(dif>=900)

    目前已AC:  2 1040.Airline Company(构造) 题目要求与每个顶点相连的所有边编号最大公约数为1,其实只要其中的两条边编号互质,所有边编号的最大公约数一定为1.我们知道相邻的数字 ...

  5. Android L(5.0)源码之手势识别GestureDetector

    本人新手,最近下了Android L的源码,正在研究手势识别,能力有限,现总结如下: Android识别触摸屏手势使得用户体验大大提高.在View类中有个View.OnTouchListener内部接 ...

  6. iOS 之UICollectionView 之原理介绍

    0. 简介 参考:支持重排的iOS9 UICollectionView 参考:http://www.cnblogs.com/langtianya/p/3902801.html 参考:http://ww ...

  7. 【Xilinx-Petalinux学习】-05-OpenCV程序测试

    占位, 通过上一次编译的opencv库,运行程序,实现图像处理

  8. java的HashCode和equals

    什么时候用到hashcode,什么时候用到equals? 首先java为每个对象都生成有默认的hashcode,这个java core里说是java对象的内存地址,但是equals方法里比较的也是对象 ...

  9. 安卓弹出对话框——AlertDialog(二)

    在Android中,启动一个对话框有三种方式: 1.定义一个新的activity,并将其主题设置为对话框风格 2.使用AlertDialog类,并且显示它 3.使用 Android的Dialog类的子 ...

  10. 学习生命周期activity

    2014年4月2日 08:31:27 开始学习activity周期, 简单了解了几个方法,写了几个打印语句,知道了先后顺序