《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的存储空间主体。

扫描二维码关注公众号,回复: 6916959 查看本文章
 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 }  

猜你喜欢

转载自www.cnblogs.com/mysky007/p/11280025.html