zoukankan      html  css  js  c++  java
  • 《STL源码剖析》--- deque1

    参考文献:

      《STL源码剖析》

    ...........................................................................................................................................................

    一. deque 概述

           vector是单向开口的连续性线性空间,deque则是一种双开的连续性空间,即两边都可以进行插入和删除操作(vector也可进行头部的删除、插入操作,但效率很差,不被接受)。

      下图为deque示意图:

     

            deque和vector最大差异,一是deque允许在常数时间内对头部元素进行插入和移除操作,二在于deque没有所谓的容量的概念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。
            虽然deque也提供Random Access Iterator,但它的迭代器并不是普通指针,其复杂度远高于vector,所以除非必要尽可 能使用vector。为了deque排序效率最高,deuqe会先将所有的元素复制到vector中,进行排序后,再复制回deque

    二. deque 的中控器

            deque是一段一段连续的空间构成,一旦在deque前端或尾端增加新空间,便配置一段定量连续空间,串联在头端和尾端。deque的最大任务就是将这些定量的空间,维护成连续的假象,并提供随机存储的接口,避开了“重新配置、复制、释放”的轮回,代价即是复杂的迭代器架构。
            既然是分段连续的线性空间,就必须要有中央控制,而为了维持连续的假象,数据结构的设计及迭代器前进后退等操作都比较麻烦,所以deque的实现代码分量远比vector或list都多得多。
            deque采用一块map(不是STL的map容器)作为主控,这里的map是一块连续空间,其中每个元素都是指针,指向另一段连续线性空间,称为缓冲区。缓冲区才是deque的存储空间主体。

     1 template <class T,class Alloc=alloc,size_t BufSiz=0>
     2 class deque{
     3 public:
     4     typedef T value_type;
     5     typedef value_type* pointer;
     6     ...
     7 protected:
     8     typedef pointer* map_pointer;
     9 protected:
    10     map_pointer map; //指向map,map是连续空间,其内的每个元素都是一个指针,指向一块缓冲区
    11     size_type map_size; //map可容纳多少指针
    12     ...
    13 };

    从上面可以看出,map其实是一个T**,也就是说它是一个指针,所指向另一个指针,指向型别为T的一块空间。具体如下图:

    三. deque 使用实例(理解)

     1 #include <deque>  
     2 #include <iostream>  
     3 #include <algorithm>  
     4 #include <stdexcept>  
     5 using namespace std;  
     6   
     7 void print(int num)  
     8 {  
     9 
    10     cout << num << " ";  
    11 }  
    12   
    13 int main()  
    14 {  
    15     //1. 初始化  
    16     deque<int> v;  
    17     deque<int>::iterator iv;  
    18   
    19     v.assign(10, 2);//将10个值为2的元素赋到deque中  
    20     cout << v.size() << endl; //返回deque实际含有的元素数量  
    21     cout << endl;  
    22   
    23     //2. 添加  
    24     v.push_front(666);  
    25     for (int i = 0; i < 10; i++)  
    26         v.push_back(i);  
    27     for_each(v.begin(), v.end(), print);//需要#include <algorithm>  
    28     cout << endl;  
    29     cout << v.size() << endl;  
    30     cout << endl;  
    31   
    32 
    33 
    34     //3. 插入及遍历、逆遍历  
    35     v.insert(v.begin() + 3, 99);  
    36     v.insert(v.end() - 3, 99);  
    37     for_each(v.begin(), v.end(), print);  
    38     cout << endl;  
    39     for_each(v.rbegin(), v.rend(), print);//在逆序迭代器上做++运算将指向容器中的前一个元素  
    40     cout << endl;  
    41   
    42     //一般遍历写法  
    43     for(iv = v.begin(); iv != v.end(); ++iv)  
    44         cout << *iv << " ";  
    45     cout << endl;  
    46     cout << endl;  
    47   
    48     //4. 删除  
    49     v.erase(v.begin() + 3);  
    50 
    51    for_each(v.begin(), v.end(), print);  
    52     cout << endl;  
    53     v.insert(v.begin() + 3, 99);//还原  
    54   
    55     v.erase(v.begin(), v.begin() + 3); //注意删除了3个元素而不是4个  
    56     for_each(v.begin(), v.end(), print);  
    57     cout << endl;  
    58   
    59     v.pop_front();  
    60     v.pop_back();  
    61     for_each(v.begin(), v.end(), print);  
    62     cout << endl;  
    63     cout << endl;  
    64   
    65 
    66 
    67     //5. 查询  
    68     cout << v.front() << endl;  
    69     cout << v.back() << endl;  
    70   
    71     //危险的做法,但一般我们就像访问数组那样操作就行  
    72     //for (int i = 15; i < 25; i++)  
    73         //cout << "Element " << i << " is " << v[i] << endl;  
    74     //安全的做法  
    75     int i;  
    76     try  
    77     {  
    78         for (i = 15; i < 25; i++)  
    79             cout << "Element " << i << " is " << v.at(i) << endl;  
    80     }  
    81     catch (out_of_range err)//#include <stdexcept>  
    82     {  
    83         cout << "out_of_range at " << i << endl;  
    84     }  
    85     cout << endl;  
    86   
    87     //6. 清空  
    88     v.clear();  
    89     cout << v.size() << endl;//0  
    90     for_each(v.begin(), v.end(), print); //已经clear,v.begin()==v.end(),不会有任何结果。  
    91   
    92     return 0;  
    93 }  
  • 相关阅读:
    Access的相关SQL语句
    决心创业
    [转]在.NET环境中使用单元测试工具NUnit
    [转]IE"单击以激活控件"网站代码解决法
    [转]C#中ToString格式大全
    [转]div中放flash运行30秒钟后自动隐藏效果
    Property和attribute的区别
    C++中的虚函数(virtual function)
    进程间通信方式
    关于页面传值的方法
  • 原文地址:https://www.cnblogs.com/mysky007/p/11280025.html
Copyright © 2011-2022 走看看