deque类可能的字段:
template <class T>
class deque
{
T *map[NUMS];
// 映射数组(指针数组): 指向保存项的连续存储块
// 块: 大小相同,其中能保存的项的数量是————1KB/项的大小
protected:
class iterator
{
T *first; // 指向包含项 X 的块的第一个项
T *current; // 指向项 X 的指针
T *last; // 指向包含项 X 的块的尾部的下一个单元的指针
T **node; // 指向 map 中单元的指针,其中 map 指向包含项 X 的块首
};
static iterator start; // 指向双端队列的第一个存储块
static iterator finish; // 指向双端队列的最后一个存储块
};
deque类的实现:
假设每个块能保存五个项,并且deque对象pets包含了11个这样的项,依次是:"dog", "cat", "pig", "gerbil", "canary", "duck", "cow", "horse", "parrot", "fox", "rabbit"。图1显示了如何表示deque对象pets,使用问号指示未使用的单元。
然后执行
pets.pop_front();
pets.push_back("mouse");
pets.push_back("iguana"); // 超出块尾,必须分配一个新的块
假设双端队列迭代器 itr 位于图2的双端队列中的项 ”duck"。图3显示了迭代器 itr、start、finish 的字段的值。(带反斜线的框表示紧随块尾之后 的单元)
然后执行 pets[9] = "goose";,过程如下
1)项 0 在第一块中的偏移量是4 —— start.current - start.first = 4
2)所求块号是 2 —— (项 0 的偏移量4 + 下标9)/ 块的大小5 = 2
3)所求块的偏移量是 3 —— (项 0 的偏移量4 + 下标9)% 块的大小5 = 3
因此块2中偏移量为3的位置上的项 “rabbit" 被替换成 ”goose"。
当所有映射指针指向的块都被使用而又需要另一个块时,map大小将加倍,并且旧的指针将位于新的map数组的中间。
deque好于vector的地方:
1)调整大小时没有项的移动。
当在deque的头尾插入时需要一个额外的块(或者map太小了),不需要移动deque的任何一项; vector中调整大小需要移动所有的项;
2)deque可在头和尾快速插入。
vector只适合尾部快速插入,vector甚至没有 push_front() 和 pop_front()方法
3)deque可回收未使用的块。
vector只会增长,不会收缩。
4)对内部的插入和删除,deque比vector少几次数据移动。
deque差于vector的地方:
deque需要模运算将下标转换成块地址。实际上,除非大多数操作都位于或接近容器的开头,否则 vector 是比 deque 快的。
由于deque和vector的大部分方法相同,只需将 vector 的 “一个非常长的整数类” 少许改动,可以正常运行。
头文件中:
vector<char> digits; 改成 deque<char> digits;
实现文件中修改 operator+如下:
very_long_int very_long_int::operator+(const very_long_int& other_very_long) const
{
very_long_int sum; // 和(返回值)
int carry = 0, // 进位值
small_size, // *this和other_very_long对象位数较小者
big_size, // *this和other_very_long对象位数较大者
value; // *this和other_very_long对象位数相加的和
if (digits.size() > other_very_long.digits.size()){
big_size = digits.size();
small_size = other_very_long.digits.size();
}
else{
big_size = other_very_long.digits.size();
small_size = digits.size();
}
deque<char>::const_iterator iter1 = digits.end(),
iter2 = other_very_long.digits.end(); //const_iterator用于遍历const容器
for (int i = 0; i < big_size; i++){
if (i < small_size){
iter1--; iter2--;
value = *iter1 + *iter2 + carry;
carry = value / 10; // 是否产生进位
sum.digits.push_front(value % 10); // 双端队列头部插入
} // 个位数为 sum.digits[0],应为 sum.digits[sum.digits.size()-1];
else if (big_size == digits.size()){
iter1--;
value = *iter1 + carry;
carry = value / 10; // 是否产生进位
sum.digits.push_front(value % 10);
}
else if (big_size == other_very_long.digits.size()){
iter2--;
value = *iter2 + carry;
carry = value / 10; // 是否产生进位
sum.digits.push_front(value % 10);
}
}
if (carry == 1) // 是否产生新位
sum.digits.push_front(carry);
// reverse(sum.digits.begin(), sum.digits.end()); // 反转sum.digits中各元素的顺序
return sum;
}
实现文件中修改 factorial()方法如下:(使用递归)
very_long_int very_long_int::factorial(int n) const
{
very_long_int temp = *this,
sum = *this;
if (n == 0){
sum.digits.erase(sum.digits.begin(), sum.digits.end()); // 释放sum占用的所有内存
sum.digits.push_back('0'-'0'); // 分配一个字节存储 0
}
if (n == 1)
return *this;
else{
return *this * factorial(n-1); // 递归求阶乘
}
}
运行结果: