一、vector

1、vector简介:

  vector的数据安排及其操作方式与数组非常相似,微小的差别在于空间的使用,数组是静态空间,一旦配置了就不能改变。vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。

2、vector的构造和内存管理

其数据结构为:

 class vector
{
...
private:
iterator start; //表示目前使用空间的头
iterator finish; //表示目前使用空间的尾
iterator end_of_storage; //表示目前可用空间的尾
...
};

vector提供许多的constructs,其中一个允许我们指定空间大小及初值。

 vector(size_type n, const T& value)   //构造函数,允许指定vector大小n和初值value
{
fill_initialize(n, value);
}
void fill_initialize(size_type n, const T& value)
{
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}
iterator allocate_and_fill(size_type n, const T& x)
{
iterator reslut = data_allocator::allocator(n);//配置n个元素空间
uninitialized_fill_n(result, n, x); //全局函数
return result;
}//uninitialized_fill_n()根据第一参数的型别特性决定使用fill_n()或反复调用construct()来完成任务,
//如果[first,n)范围内的每一个迭代器都指向未初始化的内存,那么uninitialized_fill_n()会调用copy construct,在该范围内的产生x的复制品,
//也就是在该范围内的每个迭代器都会调用construct(&*i,x),在对应位置上产生x的复制品.

当我们以push_back()将新元素插入vector尾端时,该函数首先检查是否还有备用空间,如果有就直接在备用空间上构造元素,并调整迭代器finish,使vector变大,如果没有备用空间了,就扩充空间,扩充空间的过程包括重新配置、移动数据和释放原空间。

注:当没有备用空间时,为了时间成本,容量会扩充至两倍,如果两倍容量仍不足,就扩充至足够大的容量。另外,对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就失效了。

 void push_back(const T& x)
{
if (finish != end_of_storage) //还有备用空间
{
construct(finish, x); //构造元素
++finish;
}
else
{
insert_aux(end(), x); //如果没有备用空间,调用该全局函数
}
}
insert_aux(iterator position, const T& x)
{
if (finish != end_of_storage) //还有备用空间,
{
construct(finish, *(finish - )); //在备用空间起始处构造一个元素,并以vector最后一个元素值为其初始值
++finish;
T x_copy = x;
copy_backward(position, finish - , finish - );
*position = x_copy;
}
else //没有备用空间
{
const size_type old_size = size();
const size_type len = old_size != ? * old_size : ;
//配置原则:如果原大小为0,则配置一个元素大小空间
//如果原大小不为0,则配置为原大小的两倍,
//前半段用来放置原数据,后半段准备用来放新数据
iterator new_start = data_allocator::allocator(len); //配置大小为len的元素空间
iterator new_finish = new_start;
try
{
new_finish = uninitialized_copy(start, position, new_start); //将原vector的内容拷贝到新vector中
construct(new_finish, x); //为新元素设定初值x;
++finish;
new_finish = uninitialized_copy(position, finish, new_finish);//将安插点的原内容拷贝过来
}
catch (...)
{
destory(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
//析构并释放原vector
destroy(begin(), end());
deallocate();
//调整迭代器,指向新的vector
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}

3、vector的元素操作

vector所提供的元素很多,见下图

这里只选择几种典型的操作进行介绍。详细参考http://www.cplusplus.com/reference/vector/vector/?kw=vector。

 iterator erase(iterator first, iterator last)            //清除[first,last)中所有的元素
{
iterator i = copy(last, finish, first);
destroy(i, finish);
finish = finish - (last - first);
return first;
} iterator erase(iterator position) //清除某个位置上的元素
{
if (position + != end())
{
copy(position + , finish, position); //该函数将[position + 1,finish)的元素拷贝到从position开始的位置上
}
--finish;
destroy(finish);
return position;
}

二、list

1、list简介

相对vector的连续性空间,list则为离散的空间布局,每次插入或删除一个元素,就会配置或释放一个元素空间。

2、list的构造和内存管理

SGI list是一个环状双向链表,其节点结构为:

 template <class T>
struct _list_node
{
typedef void* void_pointer;
void_pointer prve;
void_pointer next;
T data;
};

以下四个函数,分别用来配置、释放、构造、销毁一个节点:

 link_type get_node()  //配置一个节点
{
return list_node_allocator::allocator();
}
void put_node(link_type p) //释放一个节点
{
list_node_allocator::deallocate(p);
}
link_type create_node(const T& x) //产生一个节点,带有元素值
{
link_type p = get_node();
construct(&p->data, x);
return p;
}
void destroy_node(link_type p) //销毁(析构释放)一个节点
{
destroy(&p->data);
put_node(p);
}
 void empty_initialize()  //产生一个空链表
{
node = get_node();
node->next = node; //令头尾都指向自己
node->prve = node;
}

3、list的元素操作

主要的操作包括:

 iterator insert(iterator position, const T& x)  //在迭代器position所指位置出插入一个节点,内容为x
{
link_type tmp = create_node(x);
tmp->next = position.node;
tmp->prve = position.node->prve;
(link_type(position.node->prve))->next = tmp;
position.node->prve = tmp;
return tmp;
} iterator erase(iterator position) //移除迭代器position所指节点
{
link_type next_node = link_type(position.node->next);
link_type prve_node = link_type(position.node->prve);
prve_node->next = next_node;
next_node->prve = prve_node;
destroy_node(position.node);
return iterator(next_node);
} void remove(const T& value)//将数值为value的元素移除
{
iterator first = begin();
iterator last = end();
while (first != last)
{
iterator next = last;
++next;
if (*first == value)
erase(first);
first = next;
}
}

list还提供一个迁移操作,将某连续范围的元素迁移到某个特定位置之前,这个操作为其他人如splice、sort、merge奠定了基础。

 void transfer(iterator position, iterator first, iterator last)  //将[first,last)中的元素移到position之前
{
if (position != last)
{
(*(link_type((*last.node).prve))).next = position.node;
(*(link_type((*first.node).prve))).next = position.node;
(*(link_type((*position.node).prve))).next = first.node;
link_type tmp = link_type((*position.node).prve);
(*position.ndoe).prve = (*last.node).prve;
(*last.node).prve = (*first.node).prve;
(*last.node).prve = tmp;
}
}

 三、deque

1、deque的简介

  deque是一种双向开口的连续性空间,可以在头尾两端分别做元素的插入和删除操作。

2、deque的构造和内存管理

  deuqe除了维护一个指向map的指针,也维护start、finish两个迭代器,分别指向第一缓冲区的第一个元素和最后一个缓冲区的最后一个元素(的下一个位置)。

 template<class T,class Alloc=alloc,size_t BufSiz=>
class deque
{
public :
typedef T value_type;
typedef value_type* pointer;
typedef size_t size_type;
typedef _deque_iterator<T, T&, T*, BufSiz> iterator;
protected:
typedef pointer* map_pointer;
iterator start;
iterator finish;
map_pointer mao;
size_type map_size;
}

根据上述结构,容易得到下列函数:

 iterator begin()
{
return start;
}
iterator end()
{
return finish;
}
size_type size() const
{
return finish - start;
}
bool empty() const
{
return finish == start;
}
reference back()
{
iterator tmp = finish;
--tmp;
return *tmp;
}
reference operator[](size_type n) //对[]符号的重载
{
return start[difference_type(n)];
}

STL源码剖析—顺序容器的更多相关文章

  1. STL源码剖析之序列式容器

    最近由于找工作需要,准备深入学习一下STL源码,我看的是侯捷所著的<STL源码剖析>.之所以看这本书主要是由于我过去曾经接触过一些台湾人,我一直觉得台湾人非常不错(这里不涉及任何政治,仅限 ...

  2. 《STL源码剖析》读书笔记

    转载:https://www.cnblogs.com/xiaoyi115/p/3721922.html 直接逼入正题. Standard Template Library简称STL.STL可分为容器( ...

  3. 通读《STL源码剖析》之后的一点读书笔记

    直接逼入正题. Standard Template Library简称STL.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adap ...

  4. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

  5. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  6. 【转载】STL"源码"剖析-重点知识总结

    原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...

  7. (原创滴~)STL源码剖析读书总结1——GP和内存管理

    读完侯捷先生的<STL源码剖析>,感觉真如他本人所说的"庖丁解牛,恢恢乎游刃有余",STL底层的实现一览无余,给人一种自己的C++水平又提升了一个level的幻觉,呵呵 ...

  8. STL源码剖析读书笔记之vector

    STL源码剖析读书笔记之vector 1.vector概述 vector是一种序列式容器,我的理解是vector就像数组.但是数组有一个很大的问题就是当我们分配 一个一定大小的数组的时候,起初也许我们 ...

  9. STL源码剖析 迭代器(iterator)概念与编程技法(三)

    1 STL迭代器原理 1.1  迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型,STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,而迭代器(i ...

随机推荐

  1. 性能优化系列二:JVM概念及配置

    一.虚拟机组成 虚拟机主要由三部分组成:编译器(执行引擎),堆与栈. 1. 编译器 编译器分为即时编译器与解释器. 即时编译器将代码编译成本地代码存于code区.因此它快,但它有内存限制! 解释器逐行 ...

  2. e782. 排列JList中的项

    By default, the items in a list are arranged vertically, in a single column, as in: item1 item2 ... ...

  3. 某软件大赛C#版考题整理——【单选题】

    多选题:http://www.cnblogs.com/zxlovenet/p/3525849.html 编程题:http://www.cnblogs.com/zxlovenet/p/3525854.h ...

  4. 利用neon技术对矩阵旋转进行加速(2)

    上次介绍的是顺时针旋转90度,最近用到了180度和270度,在这里记录一下. 1.利用neon技术将矩阵顺时针旋转180度: 顺时针旋转180度比顺时针旋转90度容易很多,如下图 A1 A2 A3 A ...

  5. GCT之数学公式(几何部分)

    一.平面图形   二.空间几何体

  6. Android四大组件之——ContentProvider(二)

    Content Resolver介绍: 开发者文档中这么定义的: This class provides applications access to the content model. 这个类为应 ...

  7. level 1 -- unit 4 -- where 引导的疑问句

    where be sb/sth 询问地点,用where where is the restaurant? where are my socks ? where was tome just now? w ...

  8. VC6.0在win 8.1中的安装使用

    http://blog.csdn.net/liups/article/details/14646663 一.首先是win8.1的安装 本人选择的是win 8.1简体中文专业N版,文件名: cn_win ...

  9. phpstorm 初体验

    最近在学php,今天想要读一下公司刚外包网站的源代码,要安装一个php的集成环境,因最开始用过JetBrains的pycharm觉得很好用,这会儿还选用该家产品PHPStorm(为啥storm这个词, ...

  10. python通过标准输入读取内容,读取键盘输入的内容?接收用户输入?

    需求说明: 在交互式脚本中,需要用户手动输入内容,并对内容进行处理.在这里记录下通过 python的内置函数input()读取标注输入的内容.默认的标准输入是键盘. 操作过程: 1.通过input() ...