deque源码1(deque概述、deque中的控制器)

deque源码2(deque迭代器、deque的数据结构)

deque源码3(deque的构造与内存、ctor、push_back、push_front)

deque源码4(deque元素操作:pop_back、pop_front、clear、erase、insert)

deque的迭代器

deque是分段连续空间,维持其"整体连续"的假象任务,落在了迭代器的operator++和operator--两个运算子身上。

对于operator:1、必须能够指出分段连续空间(即缓冲区)在哪里

         2、必须能够判断自己是否已经处于其所在缓冲区的边缘,在跳跃时,必须掌握控制中心。

如下图:

template <class T,class Ref,class Ptr,size_t Bufsize>
struct __deque_iterator{ //为继承 std::iterator
typedef __deque_iterator<T,T&,T*,Bufsize> iterator;
typedef __deque_iterator<T,const T&,const T*,Bufsize> const_iterator;
static size_t buffer_size(){return __deque_buf_size(Bufsize,sizeof(T));} //未继承std::iterator,所以必须自行撰写五个必要的迭代器相应型别
typedef random_access_iterator_tag iterator_category; //
typedef T value_type; //
typedef Ptr pointer; //
typedef Ref renference; //
typedef size_t size_type;
typedef ptrdiff_t difference_type; //
typedef T** map_pointer; typedef __deque_iterator self; //保持与容器的联结
T* cur; //此迭代器所指之缓冲区中的现行(current)元素
T* first; //此迭代器所指之缓冲区中的头
T* last; //此迭代器所指之缓冲区中的尾(含备用空间)
map_pointer node; //指向管控中心
... inline size_t __deque_buf_size(size_t n,size_t sz){
return n!=? n:(sz<? size_t(/sz):size_t());
}
/*
n!=0,返回n,表示buffer_size由用户自定义
n=0,表示buffer_size使用默认值,那么:
sz<512,传回512/sz;
sz>=512,传回1
*/
};

例如:产生一个deque<int>,令缓冲区大小为32,于是每个缓冲区可以容纳32/sizeof(int)=8个元素,经过增删操作,deque中包含20个元素,deque情况如下图:

start和finish分别指向deque的第一个缓冲区和最后一个缓冲区,20/8=3,所以map拥有3个节点,且最后一个缓冲区还有插入元素的空间。

用于迭代器内对各种指针运算都进行重载操作,所以各种运算算法都比较麻烦,特别是对于在缓冲区边缘的元素操作都需要调用set_node操作,来跳一个缓冲区。代码如下:

    void set_node(map_pointer new_node){
node=new_node;
first=*new_node;
last=first+difference_type(buffer_size());
}

重载运算符如下:

    renference operator*() const {return *cur;}

    pointer operator->() const {return &(operator*());}

    difference_type operator-(const self& x)const{
return difference_type(buffer_size())*(node-x.node-)+(cur-first)+(x.last-x.cur);
} self& operator++(){
++cur; //切换下一个元素
if(cur==last){ //如果已达到所在缓冲区的尾端
set_node(node+); //利用set_node方法切换到下一个缓冲区
cur=first;
}
return *this;
}
self operator++(int){
self temp=*this;
++*this; //调用operator++
return temp;
} self& operator--(){
if(cur==first){ //如果达到缓冲区的头部
set_node(node-); //利用set_node方法切换到上一个缓冲区
cur=first;
}
--cur;
return *this;
}
self operator--(int){
self temp=*this;
--*this; //调用operator--
return temp;
} self& operator+=(difference_type n){ //实现随机存取、迭代器可以直接跳跃n个距离
difference_type offset=n+(cur-first);
if(offset>=&&offset<difference_type(buffer_size())) //目标位置在统一缓冲区
cur+=n;
else{ //目标位置在统一缓冲区
difference_type node_offset=offset>?
offset/difference_type(buffer_size()):-difference_type((-offset-)/buffer_size())-;
set_node(node+node_offset); //切换至正确的节点
cur=first+(offset-node_offset*difference_type(buffer_size()); //切换至正确的元素
}
return *this;
}
self operator+(difference_type n) const{
self temp=*this;
return temp+=n; //调用operator+=
} self& operator-=(difference_type n){
return *this+=-n;
}
self operator-(difference_type n) const{
self temp=*this;
return temp-=n; //调用operator-=
} //随机存取第n个元素
reference operator[](difference_type n)const {return *(*this+n);} bool operator==(const self& x)const{return cur==x.cur;}
bool operator!=(const self& x)const{return !(*this==x);}
bool operator<(const self& x)const{
return (node==x.node)?(cur<x.cur):(node<x.node);
}

deque的数据结构

deque除了维护上文map的指针外,还要维护start,finish两个迭代器(上图2可见),分别指向第一个缓冲区的第一个元素和最后一个缓冲区的最后一个元素的下一个位置(可能还有备用空间),此外,它当然也必须记住目前的map大小,因为一旦map所提供的节点不足,就必须重新配置更大的一块map。

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;
public:
typedef __deque_iterator<T,T&,T*,BufSiz> iterator;
protected:
typedef pointer* map_pointer;//元素的指针的指针
protected:
iterator start; //表示第一个节点
iterator finish; //表示最后一个节点
map_pointer map; //指向map,map是块连续空间,其每个元素都是指针,指向一个节点
size_type map_size; //map内有多个指针
... public:
iterator begin(){return start;}
iterator end(){return finish;} reference operator[](size_type n){
return start[difference_type(n)]; //调用operator[]
}
reference front(){return *start;} //调用operator*
reference back(){
iterator temp=finish;
--temp; //调用operator--
return *temp; //调用operator*
} size_type size() const{return finish-start;} //调用operator-
size_type max_size() const{return size_type(-);} bool empty() const{return finish==start;}
};

deque源码2(deque迭代器、deque的数据结构)的更多相关文章

  1. deque源码4(deque元素操作:pop_back、pop_front、clear、erase、insert)

    deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...

  2. deque源码3(deque的构造与内存、ctor、push_back、push_front)

    deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...

  3. deque源码1(deque概述、deque中的控制器)

    deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...

  4. STL源码分析之迭代器

    前言 迭代器是将算法和容器两个独立的泛型进行调和的一个接口. 使我们不需要关系中间的转化是怎么样的就都能直接使用迭代器进行数据访问. 而迭代器最重要的就是对operator *和operator-&g ...

  5. STL源码剖析:迭代器

    准备知识 什么是迭代器? 迭代器是链接容器和算法的桥梁,所有的算法都通过迭代器操作容器中的数据 迭代器是一种智能指针,最重要的操作符重载就是operator*,operator-> 迭代器的实现 ...

  6. 给jdk写注释系列之jdk1.6容器(6)-HashSet源码解析&Map迭代器

    今天的主角是HashSet,Set是什么东东,当然也是一种java容器了.      现在再看到Hash心底里有没有会心一笑呢,这里不再赘述hash的概念原理等一大堆东西了(不懂得需要先回去看下Has ...

  7. 结合JDK源码看设计模式——迭代器模式

    前言: Iterator翻译过来就是迭代器的意思.在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器 ...

  8. HDFS源码分析:NameNode相关的数据结构

    本文主要基于Hadoop1.1.2分析HDFS中的关键数据结构. 1 NameNode 首先从NameNode开始.NameNode的主要数据结构如下: NameNode管理着两张很重要的表: 1)  ...

  9. 动图+源码,演示Java中常用数据结构执行过程及原理

    最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList Linke ...

随机推荐

  1. Linux中硬链接和软链接的区别

    看了这篇文章之后,豁然开朗.直接放链接,感谢作者的分享. https://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/#ico ...

  2. Scikit-learn 安装

    Scikit-Learn 3 pip 安装 如果安装了Python,没有安装pip,使用Windows + R,输入cmd,回车打开命令行,输入 python -m pip install -U pi ...

  3. 记录一下maven使用过程中的问题

    Failed to execute goal on project bos_fore: Could not resolve dependencies for project 上面问题,我把<de ...

  4. springcloud+zuul+swagger 分布式接口文档

    https://gitee.com/didispace/swagger-butler 1.引用上面项目中的swagger 工具包 2.zuul 网关配置 zuul.routes.api-apiserv ...

  5. go 函数类型

    在go中,函数也可以被当成数据类型 e.g:下面有两个函数,+.-,然后定义了一个函数类型FuncType1,然后对funcType1附于不同的函数,则funcType1就可以执行相应的函数 pack ...

  6. org.apache.maven.archiver.mavenarchiver.getmanifest怎么解决

    原因就是你的maven的配置文件不是最新的 1.help ->Install New Software -> add ->https://otto.takari.io/content ...

  7. 20155205 郝博雅 Exp4 恶意代码分析

    20155205 郝博雅 Exp4 恶意代码分析 一.实验目标 1.监控你自己系统的运行状态,看有没有可疑的程序在运行. 2.分析一个恶意软件,就分析Exp2或Exp3中生成后门软件:分析工具尽量使用 ...

  8. mysql实现多实例

    > mariadb安装    yum install mariadb-server > 创建相关目录,及设置权限    mkdir /mysqldb; mkdir /mysqldb/{33 ...

  9. VS Code 之 smarty 扩展

    VS Code 中的 Smarty 扩展: https://github.com/imperez/vscode-smarty 目前(v0.2.0)不支持定制定界符.可以通过 trick 的方式篡改. ...

  10. 基于面向方面和UML的实时系统建模研究

    一.基本信息 标题:基于面向方面和UML的实时系统建模研究 时间:2010 出版源:计算机技术与发展 领域分类:面向方向:实时系统:横切关注点:统一建模语言: 二.研究背景 问题定义:实时系统建模研究 ...