现在学习下deque的正确使用 ,与vector不同的是deque可以在头部,进行添加和删除操作,并且是常数时间的复杂度
#include<string>
#include<deque>
#include<iostream>
using namespace std;
int main()
{
deque<string>d;
cout<<"the deque max_size is:"<<d.max_size()<<endl;
d.push_back("1:");
d.push_back("2");
d.push_back("3");
d.push_back("4");
for(int i=0;i<d.size();i++)
cout<<d[i]<<endl;
d.pop_back();
d.pop_front();
deque<string>::iterator itr;
for(itr=d.begin();itr!=d.end();itr++)
cout<<*itr<<endl;
d.push_back("first");
for(itr=d.begin();itr!=d.end();itr++)
cout<<*itr<<endl;
d.clear();
}
deque的元素采用线性结构进行存储,每一个存储块称之为deque块,每一个块的大小一般是512字节,元素类型所占的大小决定了每一个deque块可容纳元素个数的多少,所
有deque块由map块进行管理,每个map块记录各个deque块的首地址,也就是说map块先于deque块的创建,每创建一个deque块,就将其加入到map块中去,deque的迭代
器共有4个变量,一个是m_first m_last m_cur m_node,m_first和m_last指定了第一个deque块第一个元素地址和最后一个deque块最后一个元素地址,而m_cur指定了当前访问的deque双对列的元素的地址 m_node存放当前deque块的map数据项的地址。m_start和m_finish都可以按照“++”和“--” 进行跨块操作,如果--超出了m_start则开辟新的块,将m_start指向新的deque的首地址,同样的,如果“++”超过了m_last,则开辟新的块,进行将m_last移动到新的deque的最后一个元素的地址
这样的话,因为deque元素可动态增长,也就不存在capacity容量操作,这样的话可以认为是容量组的链表
每次当内存不够用时,自动开辟一个deque块,并将该deque块放在map块当中,也就是说理论上不存在不够用的情况。每次添加或者删除一个元素,都会检查该deque块是否已经失效,或者需要新建新的deque块,这样一来,deque的内存管理还是很高效的。,新建一个deque的时候,我们会根据传递的参数(元素个数)和元素类型,决定需要的deque的个数
这里面需要注意的是deque元素的插入没有任何限制,就和vector是一样的,也就是说没有比较函数一说,无论重复与否,都可以放在里面,我们可以认为是内存模型不一致的数组即可
1、我们首先看看插入操作,因为我们在指定的位置上进行插入操作,然而我们需要进行辨别,该位置的特殊性,如果该位置靠近前面的位置上,进行的是一种操作,另一种则是靠近末尾的位置的上,
start pos
X A B C D E F
第一步,进行push_front(begin()),变成了
start pos
A A B C D E F
第二步,进行整个内存的复制
start pos
A B C C D E F
第三部就是在pos位置上进行赋值了
start pos
A B C M D E F
而如果pos靠近末尾位置呢,则是
pos end
A B C D E F
第一步,进行push_back(back()),变成了
pos end
A B C D E F F
第二步,进行整个内存的复制
pos end
A B C C D E F
第三部就是在pos位置上进行赋值了
pos end
A B M C D E F
接下来要说的就是删除操作了,同样的需要判断pos位置所在是靠近deque的起始位置还是结束位置
1、如果是起始位置的话,原始图谱是这样的
start pos
A B C D E F
2.进行内存的复制
start pos
A A B C E F
3.去掉第一个pop(front())
start pos
A B C E F
而如果是靠近末尾的元素呢,起始图谱:
1、
pos end
2\就是,向前复制,调用copy_forward
pos end
3、最后进行pop(back())操作,去掉最后一个元素
pos end
这样我们就完成了deque的操作,