本節(jié)我們將介紹 STL 中的 deque 容器使用。
deque<T>,是一個(gè)定義在 deque 頭文件中的容器模板,可以生成包含 T 類型元素的容器,它以雙端隊(duì)列的形式組織元素,因此可以在容器的頭部和尾部高效地添加或刪除對(duì)象,它可以處理先進(jìn)先出類型的事務(wù),類似于棧這種數(shù)據(jù)結(jié)構(gòu),它的使用和 vector 相似,但 vector 只能在容器末尾處增加和刪除元素。
deque 容器的初始化
初始化方式:
1.使用默認(rèn)的構(gòu)造函數(shù)生成 deque 容器,容器中沒(méi)有任何元素,大小為0,當(dāng)添加第一個(gè)元素,就就會(huì)有內(nèi)存的分配。
deque<string> data;
2.和 vector 容器在本質(zhì)上相同類似,可以生成給定元素個(gè)數(shù)的 deque 容器。
deque<string> data(7);
或者
deque<string> data(7,"seven");
3.可以用初始化列表來(lái)生成 deque 容器。
deque<string> data {"one","null","three","four","null","six","seven"};
4.也可以用由兩個(gè)迭代器標(biāo)識(shí)的一段元素來(lái)初始化它。
deque<string> data {"one","null","three","four","null","six","seven"};
deque<string> data_ {data};
或者
deque<string> data {"one","null","three","four","null","six","seven"};
deque<string> data_ {begin(data)+2,end(data)-2};
接下來(lái),我們匯總下 deque 容器的初始化。
示例如下:
#include <bits/stdc++.h>
using namespace std;
int main(){
deque<string> data_1;
deque<string> data_2(7);
deque<string> data_3(7,"null");
deque<string> data_4 {"one","null","three","four","null","six","seven"};
//全部復(fù)制
deque<string> data_5{data_4};
auto begin_iter = begin(data_4);
deque<string>::iterator end_iter = end(data_4);
begin_iter += 2;
end_iter -= 2;
//部分復(fù)制
deque<string> data_6{begin_iter,end_iter};
cout<<"data_1: "<<data_1.size()<<endl;
for(auto d : data_1){
cout<<d<<" ";
}
cout<<endl;
cout<<"data_2: "<<data_2.size()<<endl;
for(auto d : data_2){
cout<<d<<" ";
}
cout<<endl;
cout<<"data_3: "<<data_3.size()<<endl;
for(auto d : data_3){
cout<<d<<" ";
}
cout<<endl;
cout<<"data_4: "<<data_4.size()<<endl;
for(auto d : data_4){
cout<<d<<" ";
}
cout<<endl;
cout<<"data_5: "<<data_5.size()<<endl;
for(auto d : data_5){
cout<<d<<" ";
}
cout<<endl;
cout<<"data_6: "<<data_6.size()<<endl;
for(auto d : data_6){
cout<<d<<" ";
}
cout<<endl;
return 0;
}
結(jié)果如下:

deque 容器的訪問(wèn)
和 vector 類似,我們可以使用下標(biāo)索引和 at() 方法進(jìn)行訪問(wèn)容器內(nèi)的元素,使用 size() 方法得到容器的大小。
同時(shí) at() 方法比索引方法安全,因?yàn)樗黾恿诉吔鐧z查,越界時(shí)會(huì)拋出 out_of_range 異常。
示例如下:
#include <bits/stdc++.h>
using namespace std;
int main(){
deque<string> data {"one","null","three","four","null","six","seven"};
cout<<"data: "<<data.size()<<endl;
for(int i=0;i<data.size();i++){
cout<<data[i]<<" ";
}
cout<<endl;
cout<<"data: "<<data.size()<<endl;
//推薦使用 at() 方法
for(int i=0;i<data.size();i++){
cout<<data.at(i)<<" ";
}
cout<<endl;
return 0;
}
結(jié)果如下:

deque 成員函數(shù) front() 和 back() 的用法也和 vector 相同。參考之前 vector 章節(jié)內(nèi)容即可。
deque 容器添加和刪除元素
我們知道,在 vector 中,有 push_back() 和 pop_back() 方法,可以在 vector 容器的尾部增加和刪除元素。
deque 容器不僅能在容器尾部增加和刪除元素,在頭部也可以增加和刪除元素。
deque<string> data {"one","two","three","four"};
//在頭部增加一個(gè)元素
data.push_front("zeros");
//刪除頭部的元素
data.pop_front();
//在尾部增加一個(gè)元素
data.push_back("five");
//刪除尾部的元素
data.pop_back();
除了和 vector —樣都有 emplace_back() 函數(shù)外,deque 還有成員函數(shù) emplace_front(),可以在序列的開始位置生成新的元素。
deque<string> data {"one","two","three","four"};
string word = "zeros five";
//從word中截取,從6開始的4個(gè)字符,在尾部加入
data.emplace_back(word,6,4);
//從word中截取,從0開始的5個(gè)字符,在頭部加入
data.emplace_front(word,0,5);
和 vector 一樣,我們也可以使用 emplace() 或 insert() 在 deque 內(nèi)部添加或移除元素。
但這個(gè)過(guò)程相對(duì)要慢一些,因?yàn)檫@些操作需要移動(dòng)容器內(nèi)現(xiàn)有元素。
emplace():
deque<string> data {"one","two","three","four"};
auto iter = end(data);
//使用 emplace() 容器尾部添加一個(gè) "AAA"
data.emplace(iter,3,'A');
iter = end(data);
iter--;
//在 data 的倒數(shù)第一個(gè)元素前加上一個(gè) "AAAA"
data.emplace(iter,4,'A');
insert():
deque<string> data {"one","two","three","four"};
deque<string> data_add {"six","seven"};
auto iter = end(data);
string goal = "five";
// 在容器后面增加一個(gè) "five"
data.insert(iter,goal);
iter = begin(data);
iter++;
goal = "one_two";
//在容器第 0 個(gè)元素后增加一個(gè) "one_two"
data.insert(iter,goal);
auto begin_iter = begin(data_add);
auto end_iter = end(data_add);
//插入 data_add 的一部分,在 data 尾部插入
iter = end(data);
data.insert(iter,begin_iter,end_iter);
之前系列文章中關(guān)于 vector 容器的 insert() 函數(shù)的使用也適用于 deque 容器。在 deque 的任意位置插入一個(gè)元素會(huì)讓現(xiàn)有的迭代器全部失效,因此需要重新生成迭代器。
deque 的成員函數(shù)clear() , erase() 也和 vector 的相同。
clear():
deque<string> data {"one","two","three","four"};
//清除 deque 容器內(nèi)的所有元素
data.clear();
erase():
deque<string> data {"null","one","two","three","four","five"};
auto iter = begin(data);
//刪除一個(gè)元素,由一個(gè)迭代器指定位置
data.erase(iter);
//此時(shí)容器內(nèi)的元素為: {"one","two","three","four","five"}
auto begin_iter = begin(data);
auto end_iter = end(data);
//使用兩個(gè)迭代器,用來(lái)指定刪除元素的范圍
begin_iter += 2;
end_iter -= 1;
data.erase(begin_iter,end_iter);
該部分的內(nèi)容和 vector 容器大同小異,更詳細(xì)的可以參考之前關(guān)于 vector 方面的博客。
deque 容器修改元素
deque 的成員函數(shù) assign() 可以替換現(xiàn)有的所有元素,它有三個(gè)重版版本:
1.替換的新內(nèi)容是由初始化列表指定的元素
2.替換的新內(nèi)容是由迭代器指定的一段元素
3.替換的新內(nèi)容是一個(gè)特定對(duì)象的多個(gè)副本
使用初始化列表
deque<string> data {"one","two","three","four","five"};
auto data_ = {string{"null"},string{"nine"},string{"null"}};
data.assign(data_);
注意,此句
auto data_ = {string{"null"},string{"nine"},string{"null"}};
不能寫成
auto data_ = {"null","nine","null"};
因?yàn)檫@么做,data_ 的類型會(huì)被推導(dǎo)為 initializer_list<const char*>,然而 assign() 需要的是一個(gè) initializer_list<string> 類型的實(shí)參,這樣就無(wú)法通過(guò)編譯。
當(dāng)然,我們可以在 assign() 的實(shí)參中直接定義初始化列表
deque<string> data {"one","two","three","four","five"};
data.assign({"null","nine","null"});
這樣,data 的內(nèi)容
{"one","two","three","four","five"}
將會(huì)被初始化成 data_ 的內(nèi)容
{"null","nine","null"}
由迭代器指定的一段元素
deque<string> data {"one","two","three","four","five"};
deque<string> data_ {"never","hardly ever","sometimes","often","usually","always"};
deque<string>::iterator begin_iter = begin(data_);
auto end_iter = end(data_);
begin_iter++;
end_iter--;
data.assign(begin_iter,end_iter);
此時(shí),data 的內(nèi)容為:
{"hardly ever","sometimes","often","usually"}
一個(gè)特定對(duì)象的多個(gè)副本
assign() 中第一個(gè)參數(shù)指定了替換當(dāng)前容器內(nèi)容的第二個(gè)參數(shù)的個(gè)數(shù)
deque<string> data {"one","two","three","four","five"};
data.assign(5,"null");
此時(shí),data 的內(nèi)容為:
{"null","null","null","null","null"}
最后,我們來(lái)看看容器的賦值操作,只要賦值運(yùn)算的右操作數(shù)必須和左操作數(shù)是相同類型,就可以完成賦值操作。
示例如下:
#include <bits/stdc++.h>
using namespace std;
int main(){
deque<string> data {"one","two","three","four","five"};
deque<string> data_;
data_ = data;
cout<<"data: "<<data.size()<<endl;
for(auto d : data){
cout<<d<<" ";
}
cout<<endl;
cout<<"data_: "<<data_.size()<<endl;
for(auto d : data_){
cout<<d<<" ";
}
cout<<endl;
//data 的元素發(fā)生更改
data = {"hardly ever","sometimes","often","usually"};
cout<<"data: "<<data.size()<<endl;
for(auto d : data){
cout<<d<<" ";
}
cout<<endl;
cout<<"data_: "<<data_.size()<<endl;
for(auto d : data_){
cout<<d<<" ";
}
cout<<endl;
return 0;
}
結(jié)果如下:

至此,deque 的內(nèi)容暫告一段落了,可以看出,deque 的使用和 vector 其實(shí)大同小異,它的特點(diǎn)之一是可以在容器的頭部和尾部增加元素,當(dāng)然由于移動(dòng)元素,時(shí)空代價(jià)會(huì)略有增加。
deque 容器的部分細(xì)節(jié)和 vector 很相似,例如刪除元素后,迭代器的變化,在之前的博客中也有所介紹,這里就不詳細(xì)展開了。